Merge remote branch 'origin/master'
[idea/community.git] / platform / lang-impl / src / com / intellij / execution / ui / layout / impl / JBRunnerTabs.java
1 /*
2  * Copyright 2000-2012 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.intellij.execution.ui.layout.impl;
17
18 import com.intellij.openapi.Disposable;
19 import com.intellij.openapi.actionSystem.ActionGroup;
20 import com.intellij.openapi.actionSystem.ActionManager;
21 import com.intellij.openapi.project.Project;
22 import com.intellij.openapi.wm.IdeFocusManager;
23 import com.intellij.ui.Gray;
24 import com.intellij.ui.awt.RelativePoint;
25 import com.intellij.ui.tabs.TabInfo;
26 import com.intellij.ui.tabs.TabsUtil;
27 import com.intellij.ui.tabs.UiDecorator;
28 import com.intellij.ui.tabs.impl.JBTabsImpl;
29 import com.intellij.ui.tabs.impl.TabLabel;
30 import com.intellij.util.ui.SameColor;
31 import com.intellij.util.ui.UIUtil;
32 import org.jetbrains.annotations.NotNull;
33 import org.jetbrains.annotations.Nullable;
34
35 import javax.swing.*;
36 import javax.swing.border.EmptyBorder;
37 import java.awt.*;
38 import java.util.List;
39 import java.util.Map;
40
41 /**
42  * @author Dennis.Ushakov
43  */
44 public class
45   JBRunnerTabs extends JBTabsImpl {
46   public JBRunnerTabs(@Nullable Project project, ActionManager actionManager, IdeFocusManager focusManager, @NotNull Disposable parent) {
47     super(project, actionManager, focusManager, parent);
48   }
49
50   @Override
51   protected void paintFirstGhost(Graphics2D g2d) {}
52
53   @Override
54   protected void paintLastGhost(Graphics2D g2d) {}
55
56   public boolean isGhostsAlwaysVisible() {
57     return false;
58   }
59
60   protected void doPaintInactive(Graphics2D g2d,
61                                  boolean leftGhostExists,
62                                  TabLabel label,
63                                  Rectangle effectiveBounds,
64                                  boolean rightGhostExists) {
65     Insets insets = getTabsBorder().getEffectiveBorder();
66
67     int _x = effectiveBounds.x + insets.left;
68     int _y = effectiveBounds.y + insets.top + 3;
69     int _width = effectiveBounds.width - insets.left - insets.right;
70     int _height = effectiveBounds.height - insets.top - insets.bottom - 3;
71     _height -= TabsUtil.ACTIVE_TAB_UNDERLINE_HEIGHT;
72
73     g2d
74       .setPaint(new GradientPaint(_x, _y, new Color(255, 255, 255, 180), _x, _y + effectiveBounds.height, new Color(255, 255, 255, 100)));
75     g2d.fillRect(_x, _y, _width, _height);
76
77     g2d.setColor(new Color(255, 255, 255, 100));
78     g2d.drawRect(_x, _y, _width - 1, _height - 1);
79   }
80
81   @Override
82   protected void doPaintBackground(Graphics2D g2d, Rectangle clip) {
83     g2d.setColor(UIUtil.getPanelBackground());
84     g2d.fill(clip);
85
86     g2d.setColor(new Color(0, 0, 0, 50));
87     g2d.fill(clip);
88
89     List<TabInfo> visibleInfos = getVisibleInfos();
90
91     Insets insets = getTabsBorder().getEffectiveBorder();
92
93     int maxOffset = 0;
94     int maxLength = 0;
95
96     for (int i = visibleInfos.size() - 1; i >= 0; i--) {
97       TabInfo visibleInfo = visibleInfos.get(i);
98       TabLabel tabLabel = myInfo2Label.get(visibleInfo);
99       Rectangle r = tabLabel.getBounds();
100       if (r.width == 0 || r.height == 0) continue;
101       maxOffset = r.x + r.width;
102       maxLength = r.height;
103       break;
104     }
105
106     maxOffset++;
107
108     Rectangle r2 = getBounds();
109
110     Rectangle rectangle;
111     int y = r2.y + insets.top;
112     int height = maxLength - insets.top - insets.bottom;
113     height -= TabsUtil.ACTIVE_TAB_UNDERLINE_HEIGHT;
114
115     rectangle = new Rectangle(maxOffset, y, r2.width - maxOffset - insets.left - insets.right, height);
116
117     g2d.setPaint(UIUtil.getPanelBackground());
118     g2d.fillRect(rectangle.x, rectangle.y, rectangle.width, rectangle.height);
119     g2d.fillRect(0, 0, rectangle.x + rectangle.width, 3);
120     g2d.fillRect(2, maxLength, getSize().width, getSize().height);
121     g2d.drawLine(0, 0, 0, getSize().height);
122   }
123
124   protected void paintSelectionAndBorder(Graphics2D g2d) {
125     if (getSelectedInfo() == null) return;
126
127     TabLabel label = getSelectedLabel();
128     Rectangle r = label.getBounds();
129     r = new Rectangle(r.x, r.y + 3, r.width, r.height - 3);
130
131     ShapeInfo selectedShape = _computeSelectedLabelShape(r);
132
133     Insets insets = getTabsBorder().getEffectiveBorder();
134     Insets i = selectedShape.path.transformInsets(insets);
135
136     int _x = r.x;
137     int _y = r.y;
138     int _height = r.height;
139
140     if (!isHideTabs()) {
141       g2d.setPaint(new GradientPaint(_x, _y, new SameColor(255), _x, _y + _height - 3, UIUtil.getPanelBackground()));
142
143       g2d.fill(selectedShape.fillPath.getShape());
144
145       g2d.setColor(new Color(255, 255, 255, 180));
146       g2d.draw(selectedShape.fillPath.getShape());
147
148       // fix right side due to swing stupidity (fill & draw will occupy different shapes)
149       g2d.draw(selectedShape.labelPath
150                  .transformLine(selectedShape.labelPath.getMaxX() - selectedShape.labelPath.deltaX(1), selectedShape.labelPath.getY() +
151                                                                                                        selectedShape.labelPath.deltaY(1),
152                                 selectedShape.labelPath.getMaxX() - selectedShape.labelPath.deltaX(1), selectedShape.labelPath.getMaxY() -
153                                                                                                        selectedShape.labelPath.deltaY(4)));
154     }
155     g2d.setColor(UIUtil.getPanelBackground());
156     g2d.fillRect(2, selectedShape.labelPath.getMaxY() - 2, selectedShape.path.getMaxX() - 2, 3);
157     g2d.drawLine(1, selectedShape.labelPath.getMaxY(), 1, getHeight() - 1);
158     g2d.drawLine(selectedShape.path.getMaxX() - 1, selectedShape.labelPath.getMaxY() - 4,
159                  selectedShape.path.getMaxX() - 1, getHeight() - 1);
160
161     if (isHideTabs()) return;
162     g2d.setColor(new Color(0, 0, 0, 50));
163     g2d.drawLine(1, selectedShape.labelPath.getMaxY(), 1, getHeight() - 1);
164     g2d.drawLine(selectedShape.path.getMaxX() - 1, selectedShape.labelPath.getMaxY() - 4,
165                  selectedShape.path.getMaxX() - 1, getHeight() - 1);
166   }
167
168   @Override
169   public Color getBackground() {
170     return Gray._142;
171   }
172
173   protected ShapeInfo _computeSelectedLabelShape(Rectangle r) {
174     final ShapeInfo shape = new ShapeInfo();
175
176     shape.path = getEffectiveLayout().createShapeTransform(getSize());
177     shape.insets = shape.path.transformInsets(getLayoutInsets());
178     shape.labelPath = shape.path.createTransform(r);
179
180     shape.labelBottomY = shape.labelPath.getMaxY() - shape.labelPath.deltaY(TabsUtil.ACTIVE_TAB_UNDERLINE_HEIGHT - 1);
181     shape.labelTopY = shape.labelPath.getY() + shape.labelPath.deltaY(1);
182     shape.labelLeftX = shape.labelPath.getX();
183     shape.labelRightX = shape.labelPath.getMaxX() - shape.labelPath.deltaX(1);
184
185     int leftX = shape.insets.left;
186
187     shape.path.moveTo(leftX, shape.labelBottomY);
188     shape.path.lineTo(shape.labelLeftX, shape.labelBottomY);
189     shape.path.lineTo(shape.labelLeftX, shape.labelTopY);
190     shape.path.lineTo(shape.labelRightX, shape.labelTopY);
191     shape.path.lineTo(shape.labelRightX, shape.labelBottomY);
192
193     int lastX = shape.path.getWidth() - shape.path.deltaX(shape.insets.right);
194
195     shape.path.lineTo(lastX, shape.labelBottomY);
196     shape.path.lineTo(lastX, shape.labelBottomY + shape.labelPath.deltaY(TabsUtil.ACTIVE_TAB_UNDERLINE_HEIGHT - 1));
197     shape.path.lineTo(leftX, shape.labelBottomY + shape.labelPath.deltaY(TabsUtil.ACTIVE_TAB_UNDERLINE_HEIGHT - 1));
198
199     shape.path.closePath();
200     shape.fillPath = shape.path.copy();
201
202     return shape;
203   }
204
205   @Override
206   public int getToolbarInset() {
207     return 8;
208   }
209
210   public boolean shouldAddToGlobal(Point point) {
211     final TabLabel label = getSelectedLabel();
212     if (label == null || point == null) {
213       return true;
214     }
215     final Rectangle bounds = label.getBounds();
216     return point.y <= bounds.y + bounds.height;
217   }
218
219   @Override
220   public Rectangle layout(JComponent c, Rectangle bounds) {
221     if (c instanceof Toolbar) {
222       bounds.height -= 5;
223       return super.layout(c, bounds);
224     }
225     if (c instanceof GridImpl) {
226       bounds.x -= 1;
227       bounds.width += 1;
228       if (!isHideTabs()) {
229         bounds.y -= 1;
230         bounds.height += 1;
231       }
232     }
233     return super.layout(c, bounds);
234   }
235
236   @Override
237   public void processDropOver(TabInfo over, RelativePoint relativePoint) {
238     super.processDropOver(over, relativePoint);
239     final Point point = relativePoint.getPoint(getComponent());
240     for (Map.Entry<TabInfo, TabLabel> entry : myInfo2Label.entrySet()) {
241       final TabLabel label = entry.getValue();
242       if (label.getBounds().contains(point) && myDropInfo != entry.getKey()) {
243         select(entry.getKey(), false);
244         break;
245       }
246     }
247   }
248
249   @Override
250   protected TabLabel createTabLabel(TabInfo info) {
251     return new MyTabLabel(this, info);
252   }
253
254   private static class MyTabLabel extends TabLabel {
255     public MyTabLabel(JBTabsImpl tabs, final TabInfo info) {
256       super(tabs, info);
257     }
258
259     @Override
260     public void apply(UiDecorator.UiDecoration decoration) {
261       setFont(UIUtil.getLabelFont(UIUtil.FontSize.SMALL));
262       myLabel.setFont(UIUtil.getLabelFont(UIUtil.FontSize.SMALL));
263       setBorder(new EmptyBorder(5, 5, 7, 5));
264     }
265
266     @Override
267     public void setTabActionsAutoHide(boolean autoHide) {
268       super.setTabActionsAutoHide(autoHide);
269       apply(null);
270     }
271
272     @Override
273     public void setTabActions(ActionGroup group) {
274       super.setTabActions(group);
275       if (myActionPanel != null) {
276         final JComponent wrapper = (JComponent)myActionPanel.getComponent(0);
277         wrapper.remove(0);
278         wrapper.add(Box.createHorizontalStrut(6), BorderLayout.WEST);
279       }
280     }
281
282     @Override
283     protected int getSelectedOffset() {
284       return getNonSelectedOffset();
285     }
286   }
287 }