blob: 43f06bff285005611d77dbd88d6c39a5e17927f4 [file] [log] [blame]
/*
* Copyright 2000-2014 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.
*/
package com.intellij.ui.tabs.impl;
import com.intellij.ide.ui.UISettings;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.wm.IdeFocusManager;
import com.intellij.ui.tabs.JBTabsPosition;
import com.intellij.ui.tabs.TabInfo;
import com.intellij.ui.tabs.TabsUtil;
import com.intellij.ui.tabs.impl.singleRow.ScrollableSingleRowLayout;
import com.intellij.ui.tabs.impl.singleRow.SingleRowLayout;
import com.intellij.ui.tabs.impl.table.TableLayout;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.awt.*;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
/**
* @author pegov
*/
public class JBEditorTabs extends JBTabsImpl {
public static final String TABS_ALPHABETICAL_KEY = "tabs.alphabetical";
static final String TABS_SHORTEN_TITLE_IF_NEED = "tabs.shorten.title.if.need";
private JBEditorTabsPainter myDarkPainter = new DarculaEditorTabsPainter();
private JBEditorTabsPainter myDefaultPainter = new DefaultEditorTabsPainter();
public JBEditorTabs(@Nullable Project project, @NotNull ActionManager actionManager, IdeFocusManager focusManager, @NotNull Disposable parent) {
super(project, actionManager, focusManager, parent);
}
@Override
protected SingleRowLayout createSingleRowLayout() {
if (ApplicationManager.getApplication().isInternal() || Registry.is("editor.use.scrollable.tabs")) {
return new ScrollableSingleRowLayout(this);
}
return super.createSingleRowLayout();
}
@Override
protected TabLabel createTabLabel(TabInfo info) {
TabLabel label = super.createTabLabel(info);
label.putClientProperty(TABS_SHORTEN_TITLE_IF_NEED, Boolean.TRUE);
return label;
}
@Override
public boolean isEditorTabs() {
return true;
}
@Override
protected void paintFirstGhost(Graphics2D g2d) {
}
@Override
protected void paintLastGhost(Graphics2D g2d) {
}
@Override
public boolean isGhostsAlwaysVisible() {
return false;
}
@Override
public boolean useSmallLabels() {
return UISettings.getInstance().USE_SMALL_LABELS_ON_TABS;
}
@Override
public boolean useBoldLabels() {
return SystemInfo.isMac && Registry.is("ide.mac.boldEditorTabs");
}
@Override
public boolean hasUnderline() {
return true;
}
protected void doPaintInactive(Graphics2D g2d,
boolean leftGhostExists,
TabLabel label,
Rectangle effectiveBounds,
boolean rightGhostExists, int row, int column) {
Insets insets = getTabsBorder().getEffectiveBorder();
int _x = effectiveBounds.x + insets.left;
int _y = effectiveBounds.y + insets.top;
int _width = effectiveBounds.width - insets.left - insets.right + (getTabsPosition() == JBTabsPosition.right ? 1 : 0);
int _height = effectiveBounds.height - insets.top - insets.bottom;
if ((!isSingleRow() /* for multiline */) || (isSingleRow() && isHorizontalTabs())) {
if (isSingleRow() && getPosition() == JBTabsPosition.bottom) {
_y += TabsUtil.ACTIVE_TAB_UNDERLINE_HEIGHT;
} else {
if (isSingleRow()) {
_height -= TabsUtil.ACTIVE_TAB_UNDERLINE_HEIGHT;
} else {
TabInfo info = label.getInfo();
if (((TableLayout)getEffectiveLayout()).isLastRow(info)) {
_height -= TabsUtil.ACTIVE_TAB_UNDERLINE_HEIGHT;
}
}
}
}
final boolean vertical = getTabsPosition() == JBTabsPosition.left || getTabsPosition() == JBTabsPosition.right;
final Color tabColor = label.getInfo().getTabColor();
getPainter().doPaintInactive(g2d, effectiveBounds, _x, _y, _width, _height, tabColor, row, column, vertical);
}
JBEditorTabsPainter getPainter() {
return UIUtil.isUnderDarcula() ? myDarkPainter : myDefaultPainter;
}
public boolean isAlphabeticalMode() {
return Registry.is(TABS_ALPHABETICAL_KEY);
}
public static void setAlphabeticalMode(boolean on) {
Registry.get(TABS_ALPHABETICAL_KEY).setValue(on);
}
@Override
protected void doPaintBackground(Graphics2D g2d, Rectangle clip) {
List<TabInfo> visibleInfos = getVisibleInfos();
if (isAlphabeticalMode()) {
Collections.sort(visibleInfos, new Comparator<TabInfo>() {
@Override
public int compare(TabInfo o1, TabInfo o2) {
return StringUtil.naturalCompare(o1.getText(), o2.getText());
}
});
}
final boolean vertical = getTabsPosition() == JBTabsPosition.left || getTabsPosition() == JBTabsPosition.right;
Insets insets = getTabsBorder().getEffectiveBorder();
int maxOffset = 0;
int maxLength = 0;
for (int i = visibleInfos.size() - 1; i >= 0; i--) {
TabInfo visibleInfo = visibleInfos.get(i);
TabLabel tabLabel = myInfo2Label.get(visibleInfo);
Rectangle r = tabLabel.getBounds();
if (r.width == 0 || r.height == 0) continue;
maxOffset = vertical ? r.y + r.height : r.x + r.width;
maxLength = vertical ? r.width : r.height;
break;
}
maxOffset++;
Rectangle r2 = getBounds();
Rectangle rectangle;
if (vertical) {
rectangle = new Rectangle(insets.left, maxOffset, getWidth(),
r2.height - maxOffset - insets.top - insets.bottom);
} else {
int y = r2.y + insets.top;
int height = maxLength - insets.top - insets.bottom;
if (getTabsPosition() == JBTabsPosition.bottom) {
y = r2.height - height - insets.top + TabsUtil.ACTIVE_TAB_UNDERLINE_HEIGHT;
} else {
height -= TabsUtil.ACTIVE_TAB_UNDERLINE_HEIGHT;
}
rectangle = new Rectangle(maxOffset, y, r2.width - maxOffset - insets.left - insets.right, height);
}
getPainter().doPaintBackground(g2d, clip, vertical, rectangle);
}
protected void paintSelectionAndBorder(Graphics2D g2d) {
if (getSelectedInfo() == null) return;
TabLabel label = getSelectedLabel();
Rectangle r = label.getBounds();
ShapeInfo selectedShape = _computeSelectedLabelShape();
Insets insets = getTabsBorder().getEffectiveBorder();
Color tabColor = label.getInfo().getTabColor();
final boolean isHorizontalTabs = isHorizontalTabs();
getPainter().paintSelectionAndBorder(g2d, r, selectedShape, insets, tabColor, isHorizontalTabs);
}
@Override
public Color getBackground() {
return getPainter().getBackgroundColor();
}
public Color getForeground() {
return UIUtil.getLabelForeground();
}
protected ShapeInfo _computeSelectedLabelShape() {
final ShapeInfo shape = new ShapeInfo();
shape.path = getEffectiveLayout().createShapeTransform(getSize());
shape.insets = shape.path.transformInsets(getLayoutInsets());
shape.labelPath = shape.path.createTransform(getSelectedLabel().getBounds());
shape.labelBottomY = shape.labelPath.getMaxY() - shape.labelPath.deltaY(TabsUtil.ACTIVE_TAB_UNDERLINE_HEIGHT - 1);
shape.labelTopY =
shape.labelPath.getY() + (getPosition() == JBTabsPosition.top || getPosition() == JBTabsPosition.bottom ? shape.labelPath.deltaY(1) : 0) ;
shape.labelLeftX = shape.labelPath.getX() + (getPosition() == JBTabsPosition.top || getPosition() == JBTabsPosition.bottom ? 0 : shape.labelPath.deltaX(
1));
shape.labelRightX = shape.labelPath.getMaxX() - shape.labelPath.deltaX(1);
int leftX = shape.insets.left + (getPosition() == JBTabsPosition.top || getPosition() == JBTabsPosition.bottom ? 0 : shape.labelPath.deltaX(1));
shape.path.moveTo(leftX, shape.labelBottomY);
shape.path.lineTo(shape.labelLeftX, shape.labelBottomY);
shape.path.lineTo(shape.labelLeftX, shape.labelTopY);
shape.path.lineTo(shape.labelRightX, shape.labelTopY);
shape.path.lineTo(shape.labelRightX, shape.labelBottomY);
int lastX = shape.path.getWidth() - shape.path.deltaX(shape.insets.right);
shape.path.lineTo(lastX, shape.labelBottomY);
shape.path.lineTo(lastX, shape.labelBottomY + shape.labelPath.deltaY(TabsUtil.ACTIVE_TAB_UNDERLINE_HEIGHT - 1));
shape.path.lineTo(leftX, shape.labelBottomY + shape.labelPath.deltaY(TabsUtil.ACTIVE_TAB_UNDERLINE_HEIGHT - 1));
shape.path.closePath();
shape.fillPath = shape.path.copy();
return shape;
}
}