blob: 183accc10cc7dcb420b9d28ca75710b715492d34 [file] [log] [blame]
/*
* Copyright 2000-2009 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;
import org.intellij.lang.annotations.JdkConstants;
import javax.swing.border.Border;
import javax.swing.border.TitledBorder;
import java.awt.*;
/**
* @author Konstantin Bulenkov
*/
public class TitledBorderWithMnemonic extends TitledBorder {
private final String myOriginalTitle;
public TitledBorderWithMnemonic(String title) {
this(null, title, LEADING, DEFAULT_POSITION, null, null);
}
public TitledBorderWithMnemonic(Border border) {
this(border, "", LEADING, DEFAULT_POSITION, null, null);
}
public TitledBorderWithMnemonic(Border border, String title) {
this(border, title, LEADING, DEFAULT_POSITION, null, null);
}
public TitledBorderWithMnemonic(Border border, String title, @JdkConstants.TitledBorderJustification int titleJustification, @JdkConstants.TitledBorderTitlePosition int titlePosition) {
this(border, title, titleJustification, titlePosition, null, null);
}
public TitledBorderWithMnemonic(Border border, String title, @JdkConstants.TitledBorderJustification int titleJustification, @JdkConstants.TitledBorderTitlePosition int titlePosition, Font titleFont) {
this(border, title, titleJustification, titlePosition, titleFont, null);
}
public TitledBorderWithMnemonic(Border border, String title, @JdkConstants.TitledBorderJustification int titleJustification, @JdkConstants.TitledBorderTitlePosition int titlePosition, Font titleFont,
Color titleColor) {
super(border, title.replaceAll("&", ""), titleJustification, titlePosition, titleFont, titleColor);
myOriginalTitle = title;
}
public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
Point textLoc = new Point();
Border border = getBorder();
if (getTitle() == null || getTitle().length() == 0) {
if (border != null) {
border.paintBorder(c, g, x, y, width, height);
}
return;
}
Rectangle grooveRect = new Rectangle(x + EDGE_SPACING, y + EDGE_SPACING,
width - (EDGE_SPACING * 2),
height - (EDGE_SPACING * 2));
Font font = g.getFont();
Color color = g.getColor();
g.setFont(getFont(c));
FontMetrics fm = g.getFontMetrics();
int fontHeight = fm.getHeight();
int descent = fm.getDescent();
int ascent = fm.getAscent();
int diff;
int stringWidth = fm.stringWidth(getTitle());
Insets insets;
if (border != null) {
insets = border.getBorderInsets(c);
} else {
insets = new Insets(0, 0, 0, 0);
}
int titlePos = getTitlePosition();
switch (titlePos) {
case ABOVE_TOP:
diff = ascent + descent + (Math.max(EDGE_SPACING,
TEXT_SPACING*2) - EDGE_SPACING);
grooveRect.y += diff;
grooveRect.height -= diff;
textLoc.y = grooveRect.y - (descent + TEXT_SPACING);
break;
case TOP:
case DEFAULT_POSITION:
diff = Math.max(0, ((ascent/2) + TEXT_SPACING) - EDGE_SPACING);
grooveRect.y += diff;
grooveRect.height -= diff;
textLoc.y = (grooveRect.y - descent) +
(insets.top + ascent + descent)/2;
break;
case BELOW_TOP:
textLoc.y = grooveRect.y + insets.top + ascent + TEXT_SPACING;
break;
case ABOVE_BOTTOM:
textLoc.y = (grooveRect.y + grooveRect.height) -
(insets.bottom + descent + TEXT_SPACING);
break;
case BOTTOM:
grooveRect.height -= fontHeight/2;
textLoc.y = ((grooveRect.y + grooveRect.height) - descent) +
((ascent + descent) - insets.bottom)/2;
break;
case BELOW_BOTTOM:
grooveRect.height -= fontHeight;
textLoc.y = grooveRect.y + grooveRect.height + ascent +
TEXT_SPACING;
break;
}
int justification = getTitleJustification();
if(c.getComponentOrientation().isLeftToRight()) {
if(justification==LEADING ||
justification==DEFAULT_JUSTIFICATION) {
justification = LEFT;
}
else if(justification==TRAILING) {
justification = RIGHT;
}
}
else {
if(justification==LEADING ||
justification==DEFAULT_JUSTIFICATION) {
justification = RIGHT;
}
else if(justification==TRAILING) {
justification = LEFT;
}
}
switch (justification) {
case LEFT:
textLoc.x = grooveRect.x + TEXT_INSET_H + insets.left;
break;
case RIGHT:
textLoc.x = (grooveRect.x + grooveRect.width) -
(stringWidth + TEXT_INSET_H + insets.right);
break;
case CENTER:
textLoc.x = grooveRect.x +
((grooveRect.width - stringWidth) / 2);
break;
}
// If title is positioned in middle of border AND its fontsize
// is greater than the border's thickness, we'll need to paint
// the border in sections to leave space for the component's background
// to show through the title.
//
if (border != null) {
if (((titlePos == TOP || titlePos == DEFAULT_POSITION) &&
(grooveRect.y > textLoc.y - ascent)) ||
(titlePos == BOTTOM &&
(grooveRect.y + grooveRect.height < textLoc.y + descent))) {
Rectangle clipRect = new Rectangle();
// save original clip
Rectangle saveClip = g.getClipBounds();
// paint strip left of text
clipRect.setBounds(saveClip);
if (computeIntersection2(clipRect, x, y, textLoc.x-1-x, height)) {
g.setClip(clipRect);
border.paintBorder(c, g, grooveRect.x, grooveRect.y,
grooveRect.width, grooveRect.height);
}
// paint strip right of text
clipRect.setBounds(saveClip);
if (computeIntersection2(clipRect, textLoc.x+stringWidth+1, y,
x+width-(textLoc.x+stringWidth+1), height)) {
g.setClip(clipRect);
border.paintBorder(c, g, grooveRect.x, grooveRect.y,
grooveRect.width, grooveRect.height);
}
if (titlePos == TOP || titlePos == DEFAULT_POSITION) {
// paint strip below text
clipRect.setBounds(saveClip);
if (computeIntersection2(clipRect, textLoc.x-1, textLoc.y+descent,
stringWidth+2, y+height-textLoc.y-descent)) {
g.setClip(clipRect);
border.paintBorder(c, g, grooveRect.x, grooveRect.y,
grooveRect.width, grooveRect.height);
}
} else { // titlePos == BOTTOM
// paint strip above text
clipRect.setBounds(saveClip);
if (computeIntersection2(clipRect, textLoc.x-1, y,
stringWidth+2, textLoc.y - ascent - y)) {
g.setClip(clipRect);
border.paintBorder(c, g, grooveRect.x, grooveRect.y,
grooveRect.width, grooveRect.height);
}
}
// restore clip
g.setClip(saveClip);
} else {
border.paintBorder(c, g, grooveRect.x, grooveRect.y,
grooveRect.width, grooveRect.height);
}
}
g.setColor(getTitleColor());
g.drawString(getTitle(), textLoc.x, textLoc.y);
final int index = myOriginalTitle.indexOf('&');
if (index != -1 && index != myOriginalTitle.length() - 1 && index == myOriginalTitle.lastIndexOf('&') && g instanceof Graphics2D) {
int x0 = fm.stringWidth(getTitle().substring(0, index));
int x1 = fm.stringWidth(getTitle().substring(0, index+1));
((Graphics2D)g).setPaint(getTitleColor());
g.drawLine(textLoc.x + x0 - 1, textLoc.y + 1, textLoc.x + x1 - 1, textLoc.y + 1);
((Graphics2D)g).setPaint(color);
}
g.setFont(font);
g.setColor(color);
}
private static boolean computeIntersection2(Rectangle dest,
int rx, int ry, int rw, int rh) {
int x1 = Math.max(rx, dest.x);
int x2 = Math.min(rx + rw, dest.x + dest.width);
int y1 = Math.max(ry, dest.y);
int y2 = Math.min(ry + rh, dest.y + dest.height);
dest.x = x1;
dest.y = y1;
dest.width = x2 - x1;
dest.height = y2 - y1;
if (dest.width <= 0 || dest.height <= 0) {
return false;
}
return true;
}
}