From 4eeeedb6b5383f0a851c273629a90cd61cecc84a Mon Sep 17 00:00:00 2001 From: Kirill Kalishev Date: Mon, 28 Jun 2010 15:49:50 +0400 Subject: [PATCH] thin tool window splitters --- .../openapi/ui/ThreeComponentsSplitter.java | 103 ++++++++++++++++-- .../util/ui/update/LazyUiDisposable.java | 50 ++++++--- .../impl/EditorTabbedContainer.java | 38 +++---- .../openapi/wm/impl/InternalDecorator.java | 79 ++++++++++++-- .../intellij/openapi/wm/impl/TitlePanel.java | 2 +- .../openapi/wm/impl/ToolWindowsPane.java | 4 + .../openapi/wm/impl/status/PositionPanel.java | 3 +- 7 files changed, 219 insertions(+), 60 deletions(-) diff --git a/platform/platform-api/src/com/intellij/openapi/ui/ThreeComponentsSplitter.java b/platform/platform-api/src/com/intellij/openapi/ui/ThreeComponentsSplitter.java index 05b094707db6..6e9628795f81 100644 --- a/platform/platform-api/src/com/intellij/openapi/ui/ThreeComponentsSplitter.java +++ b/platform/platform-api/src/com/intellij/openapi/ui/ThreeComponentsSplitter.java @@ -15,14 +15,20 @@ */ package com.intellij.openapi.ui; +import com.intellij.openapi.Disposable; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.project.Project; import com.intellij.openapi.util.IconLoader; +import com.intellij.openapi.wm.IdeGlassPane; +import com.intellij.openapi.wm.IdeGlassPaneUtil; import com.intellij.ui.UIBundle; +import com.intellij.util.ui.update.LazyUiDisposable; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.*; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; +import java.awt.event.*; /** * @author Vladimir Kondratyev @@ -58,6 +64,7 @@ public class ThreeComponentsSplitter extends JPanel { private int myLastSize = 10; private boolean myShowDividerControls; + private int myDividerZone; /** @@ -85,6 +92,10 @@ public class ThreeComponentsSplitter extends JPanel { setOrientation(myVerticalSplit); } + public void setDividerMouseZoneSize(int size) { + myDividerZone = size; + } + public boolean isHonorMinimumSize() { return myHonorMinimumSize; } @@ -262,7 +273,7 @@ public class ThreeComponentsSplitter extends JPanel { } public void setDividerWidth(int width) { - if (width <= 0) { + if (width < 0) { throw new IllegalArgumentException("Wrong divider width: " + width); } if (myDividerWidth != width) { @@ -382,17 +393,79 @@ public class ThreeComponentsSplitter extends JPanel { return lastVisible() ? myLastSize : 0; } - protected class Divider extends JPanel { + protected class Divider extends JPanel implements Disposable { protected boolean myDragging; protected Point myPoint; private final boolean myIsFirst; + private MouseAdapter myListener = new MouseAdapter() { + @Override + public void mousePressed(MouseEvent e) { + MouseEvent event = SwingUtilities.convertMouseEvent(e.getComponent(), e, Divider.this); + processMouseEvent(event); + if (event.isConsumed()) { + e.consume(); + } + } + + @Override + public void mouseReleased(MouseEvent e) { + MouseEvent event = SwingUtilities.convertMouseEvent(e.getComponent(), e, Divider.this); + processMouseEvent(event); + if (event.isConsumed()) { + e.consume(); + } + } + + @Override + public void mouseDragged(MouseEvent e) { + MouseEvent event = SwingUtilities.convertMouseEvent(e.getComponent(), e, Divider.this); + processMouseMotionEvent(event); + if (event.isConsumed()) { + e.consume(); + } + } + }; + private boolean myWasPressedOnMe; + public Divider(boolean isFirst) { super(new GridBagLayout()); setFocusable(false); enableEvents(MouseEvent.MOUSE_EVENT_MASK | MouseEvent.MOUSE_MOTION_EVENT_MASK); myIsFirst = isFirst; setOrientation(myVerticalSplit); + + new LazyUiDisposable(null, this, this) { + @Override + protected void initialize(@NotNull Disposable parent, @NotNull Divider child, @Nullable Project project) { + init(); + } + }; + } + + private boolean isInside(Point p) { + if (myVerticalSplit) { + if (getHeight() > 0) { + return p.y >= 0 && p.y < getHeight(); + } else { + return p.y >= -myDividerZone / 2 && p.y < myDividerZone / 2; + } + } else { + if (getWidth() > 0) { + return p.x >= 0 && p.x < getWidth(); + } else { + return p.x >= -myDividerZone / 2 && p.x < myDividerZone / 2; + } + } + } + + private void init() { + IdeGlassPane gp = IdeGlassPaneUtil.find(this); + gp.addMouseMotionPreprocessor(myListener, this); + gp.addMousePreprocessor(myListener, this); + } + + public void dispose() { } private void setOrientation(boolean isVerticalSplit) { @@ -485,13 +558,13 @@ public class ThreeComponentsSplitter extends JPanel { protected void processMouseMotionEvent(MouseEvent e) { super.processMouseMotionEvent(e); - if (MouseEvent.MOUSE_DRAGGED == e.getID()) { + if (MouseEvent.MOUSE_DRAGGED == e.getID() && myWasPressedOnMe) { myDragging = true; setCursor(getOrientation() ? Cursor.getPredefinedCursor(Cursor.S_RESIZE_CURSOR) : Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR)); myPoint = SwingUtilities.convertPoint(this, e.getPoint(), ThreeComponentsSplitter.this); float proportion; if (getOrientation()) { - if (getHeight() > 0) { + if (getHeight() > 0 || myDividerZone > 0) { if (myIsFirst) { setFirstSize(Math.max(getMinSize(myFirstComponent), myPoint.y)); } @@ -501,7 +574,7 @@ public class ThreeComponentsSplitter extends JPanel { } } else { - if (getWidth() > 0) { + if (getWidth() > 0 || myDividerZone > 0) { if (myIsFirst) { setFirstSize(Math.max(getMinSize(myFirstComponent), myPoint.x)); } @@ -512,6 +585,10 @@ public class ThreeComponentsSplitter extends JPanel { } ThreeComponentsSplitter.this.doLayout(); } + + if (myWasPressedOnMe) { + e.consume(); + } } private int getMinSize(JComponent component) { @@ -545,11 +622,21 @@ public class ThreeComponentsSplitter extends JPanel { } case MouseEvent.MOUSE_PRESSED: { - setCursor(getOrientation() ? Cursor.getPredefinedCursor(9) : Cursor.getPredefinedCursor(11)); + if (isInside(e.getPoint())) { + myWasPressedOnMe = true; + setCursor(getOrientation() ? Cursor.getPredefinedCursor(9) : Cursor.getPredefinedCursor(11)); + e.consume(); + } else { + myWasPressedOnMe = false; + } break; } case MouseEvent.MOUSE_RELEASED: { + if (myWasPressedOnMe) { + e.consume(); + } + myWasPressedOnMe = false; myDragging = false; myPoint = null; break; diff --git a/platform/platform-api/src/com/intellij/util/ui/update/LazyUiDisposable.java b/platform/platform-api/src/com/intellij/util/ui/update/LazyUiDisposable.java index 05579be3318d..cf9f4e3a35b8 100644 --- a/platform/platform-api/src/com/intellij/util/ui/update/LazyUiDisposable.java +++ b/platform/platform-api/src/com/intellij/util/ui/update/LazyUiDisposable.java @@ -16,7 +16,9 @@ package com.intellij.util.ui.update; import com.intellij.openapi.Disposable; +import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.AsyncResult; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.actionSystem.PlatformDataKeys; import com.intellij.openapi.actionSystem.DataKey; @@ -58,10 +60,18 @@ public abstract class LazyUiDisposable implements Activata if (myWasEverShown) return; try { - final Disposable parent = findParentDisposable(); - initialize(parent, myChild, findProject()); - Disposer.register(parent, myChild); - } finally { + findParentDisposable().doWhenDone(new AsyncResult.Handler() { + public void run(Disposable parent) { + Project project = null; + if (ApplicationManager.getApplication() != null) { + project = PlatformDataKeys.PROJECT.getData(DataManager.getInstance().getDataContext()); + } + initialize(parent, myChild, project); + Disposer.register(parent, myChild); + } + }); + } + finally { myWasEverShown = true; } } @@ -72,26 +82,32 @@ public abstract class LazyUiDisposable implements Activata protected abstract void initialize(@NotNull Disposable parent, @NotNull T child, @Nullable Project project); @NotNull - private Disposable findParentDisposable() { - final Disposable parent = findObject(myParent, PlatformDataKeys.UI_DISPOSABLE); - return parent != null ? parent : Disposer.get("ui"); + private AsyncResult findParentDisposable() { + return findDisposable(myParent, PlatformDataKeys.UI_DISPOSABLE); } - @Nullable - private Project findProject() { - return (Project) findObject(myProject, PlatformDataKeys.PROJECT); - } - - private Disposable findObject(Disposable defaultValue, DataKey key) { + private static AsyncResult findDisposable(Disposable defaultValue, final DataKey key) { if (defaultValue == null) { if (ApplicationManager.getApplication() != null) { - return key.getData(DataManager.getInstance().getDataContext()); - } else { + final AsyncResult result = new AsyncResult(); + DataManager.getInstance().getDataContextFromFocus().doWhenDone(new AsyncResult.Handler() { + public void run(DataContext context) { + Disposable disposable = key.getData(context); + if (disposable == null) { + disposable = Disposer.get("ui"); + } + result.setDone(disposable); + } + }); + return result; + } + else { return null; } - } else { - return defaultValue; + } + else { + return new AsyncResult.Done(defaultValue); } } diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorTabbedContainer.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorTabbedContainer.java index f97c049db6c5..98e916b4c89a 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorTabbedContainer.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorTabbedContainer.java @@ -147,6 +147,18 @@ final class EditorTabbedContainer implements Disposable, CloseAction.CloseTarget UISettings uiSettings = UISettings.getInstance(); + List topIds = mgr.getIdsOn(ToolWindowAnchor.TOP); + List bottom = mgr.getIdsOn(ToolWindowAnchor.BOTTOM); + List rightIds = mgr.getIdsOn(ToolWindowAnchor.RIGHT); + List leftIds = mgr.getIdsOn(ToolWindowAnchor.LEFT); + + if (!uiSettings.HIDE_TOOL_STRIPES) { + border.top = topIds.size() > 0 ? 1: 0; + border.bottom = bottom.size() > 0 ? 1: 0; + border.left = leftIds.size() > 0 ? 1: 0; + border.right = rightIds.size() > 0 ? 1: 0; + } + for (String each : ids) { ToolWindow eachWnd = mgr.getToolWindow(each); if (!eachWnd.isAvailable()) continue; @@ -160,35 +172,11 @@ final class EditorTabbedContainer implements Disposable, CloseAction.CloseTarget } else if (eachAnchor == ToolWindowAnchor.LEFT) { border.left = 1; } else if (eachAnchor == ToolWindowAnchor.RIGHT) { - border.right = 1; + border.right = 0; } } } - if (!uiSettings.HIDE_TOOL_STRIPES) { - if (mgr.getIdsOn(ToolWindowAnchor.TOP).size() > 0) { - border.top = 1; - } - - if (mgr.getIdsOn(ToolWindowAnchor.BOTTOM).size() > 0) { - border.bottom = 1; - } - - if (mgr.getIdsOn(ToolWindowAnchor.LEFT).size() > 0) { - border.left = 1; - } - - if (mgr.getIdsOn(ToolWindowAnchor.RIGHT).size() > 0) { - border.right = 1; - } - - if (!uiSettings.SHOW_STATUS_BAR && !uiSettings.HIDE_TOOL_STRIPES) { - border.bottom = 1; - } - } - - myTabs.getComponent().setBorder(new EmptyBorder(1, 0, 0, 0)); - myTabs.getPresentation().setPaintBorder(border.top, border.left, border.right, border.bottom).setTabSidePaintBorder(5); } diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/InternalDecorator.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/InternalDecorator.java index 4f34130ebde3..07b2c84fdefc 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/InternalDecorator.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/InternalDecorator.java @@ -46,12 +46,14 @@ import org.jetbrains.annotations.NonNls; import javax.swing.*; import javax.swing.border.Border; +import javax.swing.border.EmptyBorder; import javax.swing.event.EventListenerList; import java.awt.*; import java.awt.event.*; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; -import java.util.Map; +import java.util.*; +import java.util.List; /** * @author Eugene Belyaev @@ -429,6 +431,7 @@ public final class InternalDecorator extends JPanel implements Queryable, TypeSa contentPane.add(inner, BorderLayout.CENTER); add(contentPane, BorderLayout.CENTER); + setBorder(new EmptyBorder(0, 0, 0, 0)); // Add listeners registerKeyboardAction(new ActionListener() { @@ -448,21 +451,83 @@ public final class InternalDecorator extends JPanel implements Queryable, TypeSa public void paintBorder(final Component c, final Graphics g, final int x, final int y, final int width, final int height) { g.setColor(UIUtil.getBorderInactiveColor()); - UIUtil.drawLine(g, x, y, x, y + height - 2); - UIUtil.drawLine(g, x + width - 1, y, x + width - 1, y + height - 2); - if (hasBottomLine()) { - UIUtil.drawLine(g, x + 1, y + height - 1, x + width - 2, y + height - 1); + Insets insets = getBorderInsets(c); + + if (insets.left > 0) { + UIUtil.drawLine(g, x, y, x, y + height - 2); } + + if (insets.right > 0) { + UIUtil.drawLine(g, x + width - 1, y, x + width - 1, y + height - 2); + } + + if (insets.bottom > 0) { + UIUtil.drawLine(g, x + 1, y + height - 1, x + width - 2, y + height - 1); + } } private boolean hasBottomLine() { return (myWindow.getAnchor() == ToolWindowAnchor.BOTTOM || myWindow.getAnchor() == ToolWindowAnchor.LEFT || myWindow.getAnchor() == ToolWindowAnchor.RIGHT) - && !UISettings.getInstance().HIDE_TOOL_STRIPES && UISettings.getInstance().SHOW_STATUS_BAR; + && !UISettings.getInstance().HIDE_TOOL_STRIPES && UISettings.getInstance().SHOW_STATUS_BAR || (myWindow.getAnchor() == ToolWindowAnchor.TOP); } public Insets getBorderInsets(final Component c) { - return new Insets(0, 1, hasBottomLine() ? 1 : 0, 1); + UISettings settings = UISettings.getInstance(); + + ToolWindowManagerImpl mgr = ((ToolWindowImpl)myWindow).getToolWindowManager(); + + List topIds = mgr.getIdsOn(ToolWindowAnchor.TOP); + boolean topButtons = !settings.HIDE_TOOL_STRIPES && topIds.size() > 0; + boolean windowAtTop = hasDockedVisible(mgr, topIds); + + List bottomIds = mgr.getIdsOn(ToolWindowAnchor.BOTTOM); + boolean bottomButtons = !settings.HIDE_TOOL_STRIPES && bottomIds.size() > 0; + boolean windowAtBottom = hasDockedVisible(mgr, bottomIds); + + List leftIds = mgr.getIdsOn(ToolWindowAnchor.LEFT); + boolean leftButtons = !settings.HIDE_TOOL_STRIPES && leftIds.size() > 0; + boolean windowAtLeft = hasDockedVisible(mgr, leftIds); + + List rightIds = mgr.getIdsOn(ToolWindowAnchor.RIGHT); + boolean rightBottoms = !settings.HIDE_TOOL_STRIPES && rightIds.size() > 0; + boolean windowAtRight = hasDockedVisible(mgr, rightIds); + + Insets insets = new Insets(0, 0, 0, 0); + if (myWindow.getAnchor() == ToolWindowAnchor.TOP) { + insets.top = topButtons ? 1 : 0; + insets.left = leftButtons ? 1: 0; + insets.right = rightBottoms ? 1: 0; + insets.bottom = 1; + } else if (myWindow.getAnchor() == ToolWindowAnchor.BOTTOM) { + insets.top = 0; + insets.left = leftButtons ? 1 : 0; + insets.right = rightBottoms ? 1: 0; + insets.bottom = bottomButtons ? 1 : 0; + } else if (myWindow.getAnchor() == ToolWindowAnchor.LEFT) { + insets.top = topButtons && !windowAtTop ? 1 : 0; + insets.left = leftButtons ? 1: 0; + insets.right = 0; + insets.bottom = bottomButtons && !windowAtBottom ? 1 : 0; + } else if (myWindow.getAnchor() == ToolWindowAnchor.RIGHT) { + insets.top = topButtons && !windowAtTop ? 1: 0; + insets.left = 1; + insets.right = rightBottoms ? 1: 0; + insets.bottom = bottomButtons && !windowAtBottom ? 1: 0; + } + + return insets; + } + + private boolean hasDockedVisible(ToolWindowManager mgr, List ids) { + for (String each : ids) { + ToolWindow eachWnd = mgr.getToolWindow(each); + if (eachWnd.isVisible()) { + if (eachWnd.getType() == ToolWindowType.DOCKED) return true; + } + } + + return false; } public boolean isBorderOpaque() { diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/TitlePanel.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/TitlePanel.java index ddfce76f47ad..51c5201d6ba6 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/TitlePanel.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/TitlePanel.java @@ -60,7 +60,7 @@ public final class TitlePanel extends JPanel { public final static Color ACTIVE_SIDE_BUTTON_BG = new Color(179, 197, 231); public final static Color INACTIVE_SIDE_BUTTON_BG = new Color(200, 200, 200); - public static final int STRUT = 1; + public static final int STRUT = 0; TitlePanel() { super(new BorderLayout()); diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowsPane.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowsPane.java index b67c4d38e43f..b81f3522931e 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowsPane.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowsPane.java @@ -92,8 +92,12 @@ final class ToolWindowsPane extends JLayeredPane { // Splitters myVerticalSplitter = new ThreeComponentsSplitter(true); + myVerticalSplitter.setDividerWidth(0); + myVerticalSplitter.setDividerMouseZoneSize(5); myVerticalSplitter.setBackground(Color.gray); myHorizontalSplitter = new ThreeComponentsSplitter(false); + myHorizontalSplitter.setDividerWidth(0); + myHorizontalSplitter.setDividerMouseZoneSize(5); myHorizontalSplitter.setBackground(Color.gray); myVerticalSplitter.setInnerComponent(myHorizontalSplitter); diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/status/PositionPanel.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/status/PositionPanel.java index 797dbc916eef..6cf1b1ca0991 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/status/PositionPanel.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/status/PositionPanel.java @@ -75,7 +75,6 @@ public class PositionPanel implements StatusBarWidget, StatusBarWidget.TextPrese return "#############"; } - @Override public float getAlignment() { return JComponent.CENTER_ALIGNMENT; } @@ -141,7 +140,7 @@ public class PositionPanel implements StatusBarWidget, StatusBarWidget.TextPrese public void caretPositionChanged(final CaretEvent e) { final Editor editor = e.getEditor(); - if (FileEditorManager.getInstance(editor.getProject()).getSelectedTextEditor() == e.getEditor()) { + if (editor.getProject() != null && FileEditorManager.getInstance(editor.getProject()).getSelectedTextEditor() == e.getEditor()) { updatePosition(editor); } }