/*
* Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.apple.laf;
import java.awt.*;
import java.beans.PropertyVetoException;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.plaf.UIResource;
import sun.swing.SwingUtilities2;
import apple.laf.*;
import apple.laf.JRSUIConstants.*;
import apple.laf.JRSUIState.TitleBarHeightState;
import com.apple.laf.AquaUtils.RecyclableSingleton;
import com.apple.laf.AquaInternalFrameBorderMetrics;
import java.awt.geom.AffineTransform;
public class AquaInternalFrameBorder implements Border, UIResource {
private static final int kCloseButton = 0;
private static final int kIconButton = 1;
private static final int kGrowButton = 2;
private static final int sMaxIconWidth = 15;
private static final int sMaxIconHeight = sMaxIconWidth;
private static final int sAfterButtonPad = 11;
private static final int sAfterIconPad = 5;
private static final int sRightSideTitleClip = 0;
private static final int kContentTester = 100; // For getting region insets
private static final RecyclableSingleton<AquaInternalFrameBorder> documentWindowFrame = new RecyclableSingleton<AquaInternalFrameBorder>() {
protected AquaInternalFrameBorder getInstance() {
return new AquaInternalFrameBorder(WindowType.DOCUMENT);
}
};
protected static AquaInternalFrameBorder window() {
return documentWindowFrame.get();
}
private static final RecyclableSingleton<AquaInternalFrameBorder> utilityWindowFrame = new RecyclableSingleton<AquaInternalFrameBorder>() {
protected AquaInternalFrameBorder getInstance() {
return new AquaInternalFrameBorder(WindowType.UTILITY);
}
};
protected static AquaInternalFrameBorder utility() {
return utilityWindowFrame.get();
}
private static final RecyclableSingleton<AquaInternalFrameBorder> dialogWindowFrame = new RecyclableSingleton<AquaInternalFrameBorder>() {
protected AquaInternalFrameBorder getInstance() {
return new AquaInternalFrameBorder(WindowType.DOCUMENT);
}
};
protected static AquaInternalFrameBorder dialog() {
return dialogWindowFrame.get();
}
private final AquaInternalFrameBorderMetrics metrics;
private final int fThisButtonSpan;
private final int fThisLeftSideTotal;
private final boolean fIsUtility;
// Instance variables
private final WindowType fWindowKind; // Which kind of window to draw
private Insets fBorderInsets; // Cached insets object
private Color selectedTextColor;
private Color notSelectedTextColor;
private Rectangle fInBounds; // Cached bounds rect object
protected final AquaPainter<TitleBarHeightState> titleBarPainter = AquaPainter.create(JRSUIStateFactory.getTitleBar());
protected final AquaPainter<JRSUIState> widgetPainter = AquaPainter.create(JRSUIState.getInstance());
protected AquaInternalFrameBorder(final WindowType kind) {
fWindowKind = kind;
titleBarPainter.state.set(WindowClipCorners.YES);
if (fWindowKind == WindowType.UTILITY) {
fIsUtility = true;
metrics = AquaInternalFrameBorderMetrics.getMetrics(true);
widgetPainter.state.set(WindowType.UTILITY);
titleBarPainter.state.set(WindowType.UTILITY);
} else {
fIsUtility = false;
metrics = AquaInternalFrameBorderMetrics.getMetrics(false);
widgetPainter.state.set(WindowType.DOCUMENT);
titleBarPainter.state.set(WindowType.DOCUMENT);
}
titleBarPainter.state.setValue(metrics.titleBarHeight);
titleBarPainter.state.set(WindowTitleBarSeparator.YES);
widgetPainter.state.set(AlignmentVertical.CENTER);
fThisButtonSpan = (metrics.buttonWidth * 3) + (metrics.buttonPadding * 2);
fThisLeftSideTotal = metrics.leftSidePadding + fThisButtonSpan + sAfterButtonPad;
}
public void setColors(final Color inSelectedTextColor, final Color inNotSelectedTextColor) {
selectedTextColor = inSelectedTextColor;
notSelectedTextColor = inNotSelectedTextColor;
}
// Utility to lazy-init and fill in fInBounds
protected void setInBounds(final int x, final int y, final int w, final int h) {
if (fInBounds == null) fInBounds = new Rectangle();
fInBounds.x = x;
fInBounds.y = y;
fInBounds.width = w;
fInBounds.height = h;
}
// Border interface
public boolean isBorderOpaque() {
return false;
}
// Border interface
public void paintBorder(final Component c, final Graphics g, final int x, final int y, final int w, final int h) {
// For expanded InternalFrames, the frame & component are the same object
paintBorder((JInternalFrame)c, c, g, x, y, w, h);
}
protected void paintTitleContents(final Graphics g, final JInternalFrame frame, final int x, final int y, final int w, final int h) {
final boolean isSelected = frame.isSelected();
final Font f = g.getFont();
g.setFont(metrics.font);
// Center text vertically.
final FontMetrics fm = g.getFontMetrics();
final int baseline = (metrics.titleBarHeight + fm.getAscent() - fm.getLeading() - fm.getDescent()) / 2;
// max button is the rightmost so use it
final int usedWidth = fThisLeftSideTotal + sRightSideTitleClip;
int iconWidth = getIconWidth(frame);
if (iconWidth > 0) iconWidth += sAfterIconPad;
final int totalWidth = w;
// window title looks like: | 0 0 0(sAfterButtonPad)IconWidth Title(right pad) |
final int availTextWidth = totalWidth - usedWidth - iconWidth - sAfterButtonPad;
final String title = frame.getTitle();
String text = title;
int totalTextWidth = 0;
int startXPosition = fThisLeftSideTotal;
boolean wasTextShortened = false;
// shorten the string to fit in the
if (text != null && !text.isEmpty()) {
totalTextWidth = SwingUtilities.computeStringWidth(fm, text);
final String clipString = "\u2026";
if (totalTextWidth > availTextWidth) {
wasTextShortened = true;
totalTextWidth = SwingUtilities.computeStringWidth(fm, clipString);
int nChars;
for (nChars = 0; nChars < text.length(); nChars++) {
final int nextCharWidth = fm.charWidth(text.charAt(nChars));
if ((totalTextWidth + nextCharWidth) > availTextWidth) {
break;
}
totalTextWidth += nextCharWidth;
}
text = text.substring(0, nChars) + clipString;
}
if (!wasTextShortened) {
// center it!
startXPosition = (totalWidth - (totalTextWidth + iconWidth)) / 2;
if (startXPosition < fThisLeftSideTotal) {
startXPosition = fThisLeftSideTotal;
}
}
if (isSelected || fIsUtility) {
g.setColor(Color.lightGray);
} else {
g.setColor(Color.white);
}
SwingUtilities2.drawString(frame, g, text, x + startXPosition + iconWidth, y + baseline + 1);
if (isSelected || fIsUtility) {
g.setColor(selectedTextColor);
} else {
g.setColor(notSelectedTextColor);
}
SwingUtilities2.drawString(frame, g, text, x + startXPosition + iconWidth, y + baseline);
g.setFont(f);
}
// sja fix x & y
final int iconYPostion = (metrics.titleBarHeight - getIconHeight(frame)) / 2;
paintTitleIcon(g, frame, x + startXPosition, y + iconYPostion);
}
public int getWhichButtonHit(final JInternalFrame frame, final int x, final int y) {
int buttonHit = -1;
final Insets i = frame.getInsets();
int startX = i.left + metrics.leftSidePadding - 1;
if (isInsideYButtonArea(i, y) && x >= startX) {
if (x <= (startX + metrics.buttonWidth)) {
if (frame.isClosable()) {
buttonHit = kCloseButton;
}
} else {
startX += metrics.buttonWidth + metrics.buttonPadding;
if (x >= startX && x <= (startX + metrics.buttonWidth)) {
if (frame.isIconifiable()) {
buttonHit = kIconButton;
}
} else {
startX += metrics.buttonWidth + metrics.buttonPadding;
if (x >= startX && x <= (startX + metrics.buttonWidth)) {
if (frame.isMaximizable()) {
buttonHit = kGrowButton;
}
}
}
}
}
return buttonHit;
}
public void doButtonAction(final JInternalFrame frame, final int whichButton) {
switch (whichButton) {
case kCloseButton:
frame.doDefaultCloseAction();
break;
case kIconButton:
if (frame.isIconifiable()) {
if (!frame.isIcon()) {
try {
frame.setIcon(true);
} catch(final PropertyVetoException e1) {}
} else {
try {
frame.setIcon(false);
} catch(final PropertyVetoException e1) {}
}
}
break;
case kGrowButton:
if (frame.isMaximizable()) {
if (!frame.isMaximum()) {
try {
frame.setMaximum(true);
} catch(final PropertyVetoException e5) {}
} else {
try {
frame.setMaximum(false);
} catch(final PropertyVetoException e6) {}
}
}
break;
default:
System.err.println("AquaInternalFrameBorder should never get here!!!!");
Thread.dumpStack();
break;
}
}
public boolean isInsideYButtonArea(final Insets i, final int y) {
final int startY = (i.top - metrics.titleBarHeight / 2) - (metrics.buttonHeight / 2) - 1;
final int endY = startY + metrics.buttonHeight;
return y >= startY && y <= endY;
}
public boolean getWithinRolloverArea(final Insets i, final int x, final int y) {
final int startX = i.left + metrics.leftSidePadding;
final int endX = startX + fThisButtonSpan;
return isInsideYButtonArea(i, y) && x >= startX && x <= endX;
}
protected void paintTitleIcon(final Graphics g, final JInternalFrame frame,
final int x, final int y) {
Icon icon = frame.getFrameIcon();
if (icon == null) {
icon = UIManager.getIcon("InternalFrame.icon");
}
if (icon == null) {
return;
}
if (icon.getIconWidth() > sMaxIconWidth
|| icon.getIconHeight() > sMaxIconHeight) {
final Graphics2D g2 = (Graphics2D) g;
final AffineTransform savedAT = g2.getTransform();
double xScaleFactor = (double) sMaxIconWidth / icon.getIconWidth();
double yScaleFactor = (double) sMaxIconHeight / icon.getIconHeight();
//Coordinates are after a translation hence relative origin shifts
g2.translate(x, y);
//scaling factor is needed to scale while maintaining aspect ratio
double scaleMaintainAspectRatio = Math.min(xScaleFactor, yScaleFactor);
//minimum value is taken to set to a maximum Icon Dimension
g2.scale(scaleMaintainAspectRatio, scaleMaintainAspectRatio);
icon.paintIcon(frame, g2, 0, 0);
g2.setTransform(savedAT);
} else {
icon.paintIcon(frame, g, x, y);
}
}
protected int getIconWidth(final JInternalFrame frame) {
int width = 0;
Icon icon = frame.getFrameIcon();
if (icon == null) {
icon = UIManager.getIcon("InternalFrame.icon");
}
if (icon != null) {
width = Math.min(icon.getIconWidth(), sMaxIconWidth);
}
return width;
}
protected int getIconHeight(final JInternalFrame frame) {
int height = 0;
Icon icon = frame.getFrameIcon();
if (icon == null) {
icon = UIManager.getIcon("InternalFrame.icon");
}
if (icon != null) {
height = Math.min(icon.getIconHeight(), sMaxIconHeight);
}
return height;
}
public void drawWindowTitle(final Graphics g, final JInternalFrame frame, final int inX, final int inY, final int inW, final int inH) {
final int x = inX;
final int y = inY;
final int w = inW;
int h = inH;
h = metrics.titleBarHeight + inH;
// paint the background
titleBarPainter.state.set(frame.isSelected() ? State.ACTIVE : State.INACTIVE);
titleBarPainter.paint(g, frame, x, y, w, h);
// now the title and the icon
paintTitleContents(g, frame, x, y, w, h);
// finally the widgets
drawAllWidgets(g, frame); // rollover is last attribute
}
// Component could be a JInternalFrame or a JDesktopIcon
void paintBorder(final JInternalFrame frame, final Component c, final Graphics g, final int x, final int y, final int w, final int h) {
if (fBorderInsets == null) getBorderInsets(c);
// Set the contentRect - inset by border size
setInBounds(x + fBorderInsets.left, y + fBorderInsets.top, w - (fBorderInsets.right + fBorderInsets.left), h - (fBorderInsets.top + fBorderInsets.bottom));
// Set parameters
setMetrics(frame, c);
// Draw the frame
drawWindowTitle(g, frame, x, y, w, h);
}
// defaults to false
boolean isDirty(final JInternalFrame frame) {
final Object dirty = frame.getClientProperty("windowModified");
if (dirty == null || dirty == Boolean.FALSE) return false;
return true;
}
// Border interface
public Insets getBorderInsets(final Component c) {
if (fBorderInsets == null) fBorderInsets = new Insets(0, 0, 0, 0);
// Paranoia check
if (!(c instanceof JInternalFrame)) return fBorderInsets;
final JInternalFrame frame = (JInternalFrame)c;
// Set the contentRect to an arbitrary value (in case the current real one is too small)
setInBounds(0, 0, kContentTester, kContentTester);
// Set parameters
setMetrics(frame, c);
fBorderInsets.left = 0;
fBorderInsets.top = metrics.titleBarHeight;
fBorderInsets.right = 0;
fBorderInsets.bottom = 0;
return fBorderInsets;
}
public void repaintButtonArea(final JInternalFrame frame) {
final Insets i = frame.getInsets();
final int x = i.left + metrics.leftSidePadding;
final int y = i.top - metrics.titleBarHeight + 1;
frame.repaint(x, y, fThisButtonSpan, metrics.titleBarHeight - 2);
}
// Draw all the widgets this frame supports
void drawAllWidgets(final Graphics g, final JInternalFrame frame) {
int x = metrics.leftSidePadding;
int y = (metrics.titleBarHeight - metrics.buttonHeight) / 2 - metrics.titleBarHeight;
final Insets insets = frame.getInsets();
x += insets.left;
y += insets.top + metrics.downShift;
final AquaInternalFrameUI ui = (AquaInternalFrameUI)frame.getUI();
final int buttonPressedIndex = ui.getWhichButtonPressed();
final boolean overButton = ui.getMouseOverPressedButton();
final boolean rollover = ui.getRollover();
final boolean frameSelected = frame.isSelected() || fIsUtility;
final boolean generalActive = rollover || frameSelected;
final boolean dirty = isDirty(frame);
paintButton(g, frame, x, y, kCloseButton, buttonPressedIndex, overButton, frame.isClosable(), generalActive, rollover, dirty);
x += metrics.buttonPadding + metrics.buttonWidth;
paintButton(g, frame, x, y, kIconButton, buttonPressedIndex, overButton, frame.isIconifiable(), generalActive, rollover, false);
x += metrics.buttonPadding + metrics.buttonWidth;
/**代码未完, 请加载全部代码(NowJava.com).**/