buffered painting of tabs - take 1
[fedora-idea.git] / platform / platform-api / src / com / intellij / ui / tabs / impl / TabLabel.java
blobf638f019468cb084d2c732081a839f2815030f7f
1 package com.intellij.ui.tabs.impl;
3 import com.intellij.ide.DataManager;
4 import com.intellij.openapi.actionSystem.ActionGroup;
5 import com.intellij.openapi.actionSystem.ActionPlaces;
6 import com.intellij.openapi.actionSystem.DefaultActionGroup;
7 import com.intellij.openapi.util.Pass;
8 import com.intellij.openapi.util.SystemInfo;
9 import com.intellij.ui.LayeredIcon;
10 import com.intellij.ui.SimpleColoredComponent;
11 import com.intellij.ui.SimpleColoredText;
12 import com.intellij.ui.components.panels.Wrapper;
13 import com.intellij.ui.tabs.JBTabsPosition;
14 import com.intellij.ui.tabs.TabInfo;
15 import com.intellij.ui.tabs.UiDecorator;
16 import com.intellij.util.ui.Centerizer;
18 import javax.swing.*;
19 import javax.swing.border.EmptyBorder;
20 import java.awt.*;
21 import java.awt.event.MouseAdapter;
22 import java.awt.event.MouseEvent;
23 import java.awt.image.BufferedImage;
25 public class TabLabel extends JPanel {
26 private final SimpleColoredComponent myLabel = new SimpleColoredComponent();
27 private final LayeredIcon myIcon;
28 private Icon myOverlayedIcon;
30 private final TabInfo myInfo;
31 private ActionPanel myActionPanel;
32 private boolean myCentered;
34 private final Wrapper myLabelPlaceholder = new Wrapper();
35 private final JBTabsImpl myTabs;
37 private BufferedImage myImage;
38 private BufferedImage myInactiveStateImage;
40 public TabLabel(JBTabsImpl tabs, final TabInfo info) {
41 myTabs = tabs;
42 myInfo = info;
43 myLabel.setOpaque(false);
44 myLabel.setBorder(null);
45 myLabel.setIconTextGap(new JLabel().getIconTextGap());
46 myLabel.setIconOpaque(false);
47 myLabel.setIpad(new Insets(0, 0, 0, 0));
48 setOpaque(false);
49 setLayout(new BorderLayout());
52 myLabelPlaceholder.setOpaque(false);
53 add(myLabelPlaceholder, BorderLayout.CENTER);
55 setAligmentToCenter(true);
57 myIcon = new LayeredIcon(2);
58 myLabel.setIcon(myIcon);
60 addMouseListener(new MouseAdapter() {
61 public void mousePressed(final MouseEvent e) {
62 if (myTabs.isSelectionClick(e, false) && myInfo.isEnabled()) {
63 myTabs.select(info, true);
65 else {
66 handlePopup(e);
70 public void mouseClicked(final MouseEvent e) {
71 handlePopup(e);
74 public void mouseReleased(final MouseEvent e) {
75 handlePopup(e);
77 });
80 public void setAligmentToCenter(boolean toCenter) {
81 if (myCentered == toCenter && myLabel.getParent() != null) return;
83 myLabelPlaceholder.removeAll();
85 if (toCenter) {
86 final Centerizer center = new Centerizer(myLabel);
87 myLabelPlaceholder.setContent(center);
88 } else {
89 myLabelPlaceholder.setContent(myLabel);
92 myCentered = toCenter;
95 public void paint(final Graphics g) {
96 if (myTabs.getSelectedInfo() != myInfo) {
97 myImage = null;
98 doPaint(g);
99 } else if (!SystemInfo.isMac) {
100 myImage = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB);
101 final Graphics2D lg = myImage.createGraphics();
102 doPaint(lg);
103 lg.dispose();
107 public void paintImage(Graphics g) {
108 final Rectangle b = getBounds();
109 if (myImage != null) {
110 g.drawImage(myImage, b.x, b.y, getWidth(), getHeight(), null);
111 } else {
112 final Graphics lG = g.create(b.x, b.y, b.width, b.height);
113 try {
114 lG.setColor(Color.red);
115 doPaint(lG);
117 finally {
118 lG.dispose();
123 private void doPaint(Graphics g) {
124 final JBTabsPosition pos = myTabs.getTabsPosition();
126 int dX = 0, dXs = 0, dY = 0, dYs = 0;
127 int selected = 1, plain = 2;
129 switch (pos) {
130 case bottom:
131 dY = -plain;
132 dYs = -selected;
133 break;
134 case left:
135 dX = plain;
136 dXs = selected;
137 break;
138 case right:
139 dX = -plain;
140 dXs = -selected;
141 break;
142 case top:
143 dY = plain;
144 dYs = selected;
145 break;
148 if (myTabs.getSelectedInfo() != myInfo) {
149 g.translate(dX, dY);
150 } else {
151 g.translate(dXs, dYs);
154 super.paint(g);
156 if (myTabs.getSelectedInfo() != myInfo) {
157 g.translate(dX, -dY);
158 } else {
159 g.translate(dX, dY);
163 private void handlePopup(final MouseEvent e) {
164 if (e.getClickCount() != 1 || !e.isPopupTrigger()) return;
166 if (e.getX() < 0 || e.getX() >= e.getComponent().getWidth() || e.getY() < 0 || e.getY() >= e.getComponent().getHeight()) return;
168 String place = myTabs.getPopupPlace();
169 place = place != null ? place : ActionPlaces.UNKNOWN;
170 myTabs.myPopupInfo = myInfo;
172 final DefaultActionGroup toShow = new DefaultActionGroup();
173 if (myTabs.getPopupGroup() != null) {
174 toShow.addAll(myTabs.getPopupGroup());
175 toShow.addSeparator();
178 Object tabs =
179 DataManager.getInstance().getDataContext(e.getComponent(), e.getX(), e.getY()).getData(JBTabsImpl.NAVIGATION_ACTIONS_KEY.getName());
180 if (tabs == myTabs && myTabs.myAddNavigationGroup) {
181 toShow.addAll(myTabs.myNavigationActions);
184 if (toShow.getChildrenCount() == 0) return;
186 myTabs.myActivePopup = myTabs.myActionManager.createActionPopupMenu(place, toShow).getComponent();
187 myTabs.myActivePopup.addPopupMenuListener(myTabs.myPopupListener);
189 myTabs.myActivePopup.addPopupMenuListener(myTabs);
190 myTabs.myActivePopup.show(e.getComponent(), e.getX(), e.getY());
191 myTabs.onPopup(myTabs.myPopupInfo);
195 public void setText(final SimpleColoredText text) {
196 clear(false);
197 if (text != null) {
198 text.appendToComponent(myLabel);
200 invalidateIfNeeded();
203 private void clear(final boolean invalidate) {
204 myLabel.clear();
205 myLabel.setIcon(myIcon);
207 if (invalidate) {
208 invalidateIfNeeded();
212 private void invalidateIfNeeded() {
213 if (myLabel.getRootPane() == null) return;
215 if (myLabel.getSize() != null && myLabel.getSize().equals(myLabel.getPreferredSize())) return;
217 myInactiveStateImage = null;
218 myLabel.getParent().invalidate();
219 myTabs.revalidateAndRepaint(false);
222 public void setIcon(final Icon icon) {
223 getLayeredIcon().setIcon(icon, 0);
224 invalidateIfNeeded();
227 private LayeredIcon getLayeredIcon() {
228 return myIcon;
231 public void setAttraction(boolean enabled) {
232 getLayeredIcon().setLayerEnabled(1, enabled);
235 public boolean isAttractionEnabled() {
236 return getLayeredIcon().isLayerEnabled(1);
239 public TabInfo getInfo() {
240 return myInfo;
243 public void apply(UiDecorator.UiDecoration decoration) {
244 if (decoration.getLabelFont() != null) {
245 setFont(decoration.getLabelFont());
248 Insets insets = decoration.getLabelInsets();
249 if (insets != null) {
250 Insets current = JBTabsImpl.ourDefaultDecorator.getDecoration().getLabelInsets();
251 setBorder(new EmptyBorder(getValue(current.top, insets.top), getValue(current.left, insets.left),
252 getValue(current.bottom, insets.bottom), getValue(current.right, insets.right)));
256 private int getValue(int curentValue, int newValue) {
257 return newValue != -1 ? newValue : curentValue;
260 public void setTabActions(ActionGroup group) {
261 removeOldActionPanel();
263 if (group == null) return;
265 myActionPanel = new ActionPanel(myTabs, myInfo, new Pass<MouseEvent>() {
266 public void pass(final MouseEvent event) {
267 final MouseEvent me = SwingUtilities.convertMouseEvent(event.getComponent(), event, TabLabel.this);
268 processMouseEvent(me);
272 toggleShowActions(false);
274 add(myActionPanel, BorderLayout.EAST);
276 myTabs.revalidateAndRepaint(false);
279 @Override
280 protected void processMouseEvent(final MouseEvent e) {
281 super.processMouseEvent(e);
284 private void removeOldActionPanel() {
285 if (myActionPanel != null) {
286 myActionPanel.getParent().remove(myActionPanel);
287 myActionPanel = null;
291 public boolean updateTabActions() {
292 return myActionPanel != null && myActionPanel.update();
296 private void setAttractionIcon(Icon icon) {
297 if (myIcon.getIcon(0) == null) {
298 getLayeredIcon().setIcon(null, 1);
299 myOverlayedIcon = icon;
300 } else {
301 getLayeredIcon().setIcon(icon, 1);
302 myOverlayedIcon = null;
306 public boolean repaintAttraction() {
307 if (!myTabs.myAttractions.contains(myInfo)) {
308 if (getLayeredIcon().isLayerEnabled(1)) {
309 getLayeredIcon().setLayerEnabled(1, false);
310 setAttractionIcon(null);
311 invalidateIfNeeded();
312 return true;
314 return false;
317 boolean needsUpdate = false;
319 if (getLayeredIcon().getIcon(1) != myInfo.getAlertIcon()) {
320 setAttractionIcon(myInfo.getAlertIcon());
321 needsUpdate = true;
324 int maxInitialBlinkCount = 5;
325 int maxRefireBlinkCount = maxInitialBlinkCount + 2;
326 if (myInfo.getBlinkCount() < maxInitialBlinkCount && myInfo.isAlertRequested()) {
327 getLayeredIcon().setLayerEnabled(1, !getLayeredIcon().isLayerEnabled(1));
328 if (myInfo.getBlinkCount() == 0) {
329 needsUpdate = true;
331 myInfo.setBlinkCount(myInfo.getBlinkCount() + 1);
333 if (myInfo.getBlinkCount() == maxInitialBlinkCount) {
334 myInfo.resetAlertRequest();
337 repaint();
339 else {
340 if (myInfo.getBlinkCount() < maxRefireBlinkCount && myInfo.isAlertRequested()) {
341 getLayeredIcon().setLayerEnabled(1, !getLayeredIcon().isLayerEnabled(1));
342 myInfo.setBlinkCount(myInfo.getBlinkCount() + 1);
344 if (myInfo.getBlinkCount() == maxRefireBlinkCount) {
345 myInfo.setBlinkCount(maxInitialBlinkCount);
346 myInfo.resetAlertRequest();
349 repaint();
351 else {
352 needsUpdate = !getLayeredIcon().isLayerEnabled(1);
353 getLayeredIcon().setLayerEnabled(1, true);
357 invalidateIfNeeded();
359 return needsUpdate;
362 protected void paintChildren(final Graphics g) {
363 super.paintChildren(g);
365 if (myOverlayedIcon == null || myLabel.getParent() == null) return;
367 final Rectangle textBounds = SwingUtilities.convertRectangle(myLabel.getParent(), myLabel.getBounds(), this);
368 if (getLayeredIcon().isLayerEnabled(1)) {
370 final int top = (getSize().height - myOverlayedIcon.getIconHeight()) / 2;
372 myOverlayedIcon.paintIcon(this, g, textBounds.x - myOverlayedIcon.getIconWidth() / 2, top);
377 public void setTabActionsAutoHide(final boolean autoHide) {
378 if (myActionPanel == null || myActionPanel.isAutoHide() == autoHide) {
379 return;
382 myActionPanel.setAutoHide(autoHide);
385 public void toggleShowActions(boolean show) {
386 if (myActionPanel != null) {
387 myActionPanel.toggleShowActtions(show);
391 @Override
392 public String toString() {
393 return myInfo.getText();
396 public void setTabEnabled(boolean enabled) {
397 myLabel.setEnabled(enabled);
401 public BufferedImage getInactiveStateImage() {
402 return myInactiveStateImage;
405 public void setInactiveStateImage(BufferedImage img) {
406 if (myImage != null && img != myImage) {
407 myImage.flush();
409 myInactiveStateImage = img;