Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/macosx/classes/com/apple/laf/AquaInternalFrameBorder.java
38831 views
/*1* Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package com.apple.laf;2627import java.awt.*;28import java.beans.PropertyVetoException;2930import javax.swing.*;31import javax.swing.border.Border;32import javax.swing.plaf.UIResource;3334import sun.swing.SwingUtilities2;3536import apple.laf.*;37import apple.laf.JRSUIConstants.*;38import apple.laf.JRSUIState.TitleBarHeightState;3940import com.apple.laf.AquaUtils.RecyclableSingleton;41import com.apple.laf.AquaInternalFrameBorderMetrics;4243public class AquaInternalFrameBorder implements Border, UIResource {44private static final int kCloseButton = 0;45private static final int kIconButton = 1;46private static final int kGrowButton = 2;4748private static final int sMaxIconWidth = 15;49private static final int sMaxIconHeight = sMaxIconWidth;50private static final int sAfterButtonPad = 11;51private static final int sAfterIconPad = 5;52private static final int sRightSideTitleClip = 0;5354private static final int kContentTester = 100; // For getting region insets5556static final RecyclableSingleton<AquaInternalFrameBorder> documentWindowFrame = new RecyclableSingleton<AquaInternalFrameBorder>() {57protected AquaInternalFrameBorder getInstance() {58return new AquaInternalFrameBorder(WindowType.DOCUMENT);59}60};61protected static AquaInternalFrameBorder window() {62return documentWindowFrame.get();63}6465static final RecyclableSingleton<AquaInternalFrameBorder> utilityWindowFrame = new RecyclableSingleton<AquaInternalFrameBorder>() {66protected AquaInternalFrameBorder getInstance() {67return new AquaInternalFrameBorder(WindowType.UTILITY);68}69};70protected static AquaInternalFrameBorder utility() {71return utilityWindowFrame.get();72}7374static final RecyclableSingleton<AquaInternalFrameBorder> dialogWindowFrame = new RecyclableSingleton<AquaInternalFrameBorder>() {75protected AquaInternalFrameBorder getInstance() {76return new AquaInternalFrameBorder(WindowType.DOCUMENT);77}78};79protected static AquaInternalFrameBorder dialog() {80return dialogWindowFrame.get();81}8283private final AquaInternalFrameBorderMetrics metrics;8485private final int fThisButtonSpan;86private final int fThisLeftSideTotal;8788private final boolean fIsUtility;8990// Instance variables91private final WindowType fWindowKind; // Which kind of window to draw92private Insets fBorderInsets; // Cached insets object9394private Color selectedTextColor;95private Color notSelectedTextColor;9697private Rectangle fInBounds; // Cached bounds rect object9899protected final AquaPainter<TitleBarHeightState> titleBarPainter = AquaPainter.create(JRSUIStateFactory.getTitleBar());100protected final AquaPainter<JRSUIState> widgetPainter = AquaPainter.create(JRSUIState.getInstance());101102protected AquaInternalFrameBorder(final WindowType kind) {103fWindowKind = kind;104105titleBarPainter.state.set(WindowClipCorners.YES);106if (fWindowKind == WindowType.UTILITY) {107fIsUtility = true;108metrics = AquaInternalFrameBorderMetrics.getMetrics(true);109110widgetPainter.state.set(WindowType.UTILITY);111titleBarPainter.state.set(WindowType.UTILITY);112} else {113fIsUtility = false;114metrics = AquaInternalFrameBorderMetrics.getMetrics(false);115116widgetPainter.state.set(WindowType.DOCUMENT);117titleBarPainter.state.set(WindowType.DOCUMENT);118}119titleBarPainter.state.setValue(metrics.titleBarHeight);120titleBarPainter.state.set(WindowTitleBarSeparator.YES);121widgetPainter.state.set(AlignmentVertical.CENTER);122123fThisButtonSpan = (metrics.buttonWidth * 3) + (metrics.buttonPadding * 2);124fThisLeftSideTotal = metrics.leftSidePadding + fThisButtonSpan + sAfterButtonPad;125}126127public void setColors(final Color inSelectedTextColor, final Color inNotSelectedTextColor) {128selectedTextColor = inSelectedTextColor;129notSelectedTextColor = inNotSelectedTextColor;130}131132// Utility to lazy-init and fill in fInBounds133protected void setInBounds(final int x, final int y, final int w, final int h) {134if (fInBounds == null) fInBounds = new Rectangle();135136fInBounds.x = x;137fInBounds.y = y;138fInBounds.width = w;139fInBounds.height = h;140}141142// Border interface143public boolean isBorderOpaque() {144return false;145}146147// Border interface148public void paintBorder(final Component c, final Graphics g, final int x, final int y, final int w, final int h) {149// For expanded InternalFrames, the frame & component are the same object150paintBorder((JInternalFrame)c, c, g, x, y, w, h);151}152153protected void paintTitleContents(final Graphics g, final JInternalFrame frame, final int x, final int y, final int w, final int h) {154final boolean isSelected = frame.isSelected();155final Font f = g.getFont();156157g.setFont(metrics.font);158159// Center text vertically.160final FontMetrics fm = g.getFontMetrics();161final int baseline = (metrics.titleBarHeight + fm.getAscent() - fm.getLeading() - fm.getDescent()) / 2;162163// max button is the rightmost so use it164final int usedWidth = fThisLeftSideTotal + sRightSideTitleClip;165int iconWidth = getIconWidth(frame);166if (iconWidth > 0) iconWidth += sAfterIconPad;167168final int totalWidth = w;169170// window title looks like: | 0 0 0(sAfterButtonPad)IconWidth Title(right pad) |171final int availTextWidth = totalWidth - usedWidth - iconWidth - sAfterButtonPad;172173final String title = frame.getTitle();174175String text = title;176int totalTextWidth = 0;177178int startXPosition = fThisLeftSideTotal;179boolean wasTextShortened = false;180// shorten the string to fit in the181if ((text != null) && !(text.equals(""))) {182totalTextWidth = SwingUtilities.computeStringWidth(fm, text);183final String clipString = "\u2026";184if (totalTextWidth > availTextWidth) {185wasTextShortened = true;186totalTextWidth = SwingUtilities.computeStringWidth(fm, clipString);187int nChars;188for (nChars = 0; nChars < text.length(); nChars++) {189final int nextCharWidth = fm.charWidth(text.charAt(nChars));190if ((totalTextWidth + nextCharWidth) > availTextWidth) {191break;192}193totalTextWidth += nextCharWidth;194}195text = text.substring(0, nChars) + clipString;196}197198if (!wasTextShortened) {199// center it!200startXPosition = (totalWidth - (totalTextWidth + iconWidth)) / 2;201if (startXPosition < fThisLeftSideTotal) {202startXPosition = fThisLeftSideTotal;203}204}205206if (isSelected || fIsUtility) {207g.setColor(Color.lightGray);208} else {209g.setColor(Color.white);210}211SwingUtilities2.drawString(frame, g, text, x + startXPosition + iconWidth, y + baseline + 1);212213if (isSelected || fIsUtility) {214g.setColor(selectedTextColor);215} else {216g.setColor(notSelectedTextColor);217}218219SwingUtilities2.drawString(frame, g, text, x + startXPosition + iconWidth, y + baseline);220g.setFont(f);221}222223// sja fix x & y224final int iconYPostion = (metrics.titleBarHeight - getIconHeight(frame)) / 2;225paintTitleIcon(g, frame, x + startXPosition, y + iconYPostion);226}227228public int getWhichButtonHit(final JInternalFrame frame, final int x, final int y) {229int buttonHit = -1;230231final Insets i = frame.getInsets();232int startX = i.left + metrics.leftSidePadding - 1;233if (isInsideYButtonArea(i, y) && x >= startX) {234if (x <= (startX + metrics.buttonWidth)) {235if (frame.isClosable()) {236buttonHit = kCloseButton;237}238} else {239startX += metrics.buttonWidth + metrics.buttonPadding;240if (x >= startX && x <= (startX + metrics.buttonWidth)) {241if (frame.isIconifiable()) {242buttonHit = kIconButton;243}244} else {245startX += metrics.buttonWidth + metrics.buttonPadding;246if (x >= startX && x <= (startX + metrics.buttonWidth)) {247if (frame.isMaximizable()) {248buttonHit = kGrowButton;249}250}251}252}253}254255return buttonHit;256}257258public void doButtonAction(final JInternalFrame frame, final int whichButton) {259switch (whichButton) {260case kCloseButton:261frame.doDefaultCloseAction();262break;263264case kIconButton:265if (frame.isIconifiable()) {266if (!frame.isIcon()) {267try {268frame.setIcon(true);269} catch(final PropertyVetoException e1) {}270} else {271try {272frame.setIcon(false);273} catch(final PropertyVetoException e1) {}274}275}276break;277278case kGrowButton:279if (frame.isMaximizable()) {280if (!frame.isMaximum()) {281try {282frame.setMaximum(true);283} catch(final PropertyVetoException e5) {}284} else {285try {286frame.setMaximum(false);287} catch(final PropertyVetoException e6) {}288}289}290break;291292default:293System.err.println("AquaInternalFrameBorder should never get here!!!!");294Thread.dumpStack();295break;296}297}298299public boolean isInsideYButtonArea(final Insets i, final int y) {300final int startY = (i.top - metrics.titleBarHeight / 2) - (metrics.buttonHeight / 2) - 1;301final int endY = startY + metrics.buttonHeight;302return y >= startY && y <= endY;303}304305public boolean getWithinRolloverArea(final Insets i, final int x, final int y) {306final int startX = i.left + metrics.leftSidePadding;307final int endX = startX + fThisButtonSpan;308return isInsideYButtonArea(i, y) && x >= startX && x <= endX;309}310311protected void paintTitleIcon(final Graphics g, final JInternalFrame frame, final int x, final int y) {312Icon icon = frame.getFrameIcon();313if (icon == null) icon = UIManager.getIcon("InternalFrame.icon");314if (icon == null) return;315316// Resize to 16x16 if necessary.317if (icon instanceof ImageIcon && (icon.getIconWidth() > sMaxIconWidth || icon.getIconHeight() > sMaxIconHeight)) {318final Image img = ((ImageIcon)icon).getImage();319((ImageIcon)icon).setImage(img.getScaledInstance(sMaxIconWidth, sMaxIconHeight, Image.SCALE_SMOOTH));320}321322icon.paintIcon(frame, g, x, y);323}324325protected int getIconWidth(final JInternalFrame frame) {326int width = 0;327328Icon icon = frame.getFrameIcon();329if (icon == null) {330icon = UIManager.getIcon("InternalFrame.icon");331}332333if (icon != null && icon instanceof ImageIcon) {334// Resize to 16x16 if necessary.335width = Math.min(icon.getIconWidth(), sMaxIconWidth);336}337338return width;339}340341protected int getIconHeight(final JInternalFrame frame) {342int height = 0;343344Icon icon = frame.getFrameIcon();345if (icon == null) {346icon = UIManager.getIcon("InternalFrame.icon");347}348349if (icon != null && icon instanceof ImageIcon) {350// Resize to 16x16 if necessary.351height = Math.min(icon.getIconHeight(), sMaxIconHeight);352}353354return height;355}356357public void drawWindowTitle(final Graphics g, final JInternalFrame frame, final int inX, final int inY, final int inW, final int inH) {358final int x = inX;359final int y = inY;360final int w = inW;361int h = inH;362363h = metrics.titleBarHeight + inH;364365// paint the background366titleBarPainter.state.set(frame.isSelected() ? State.ACTIVE : State.INACTIVE);367titleBarPainter.paint(g, frame, x, y, w, h);368369// now the title and the icon370paintTitleContents(g, frame, x, y, w, h);371372// finally the widgets373drawAllWidgets(g, frame); // rollover is last attribute374}375376// Component could be a JInternalFrame or a JDesktopIcon377void paintBorder(final JInternalFrame frame, final Component c, final Graphics g, final int x, final int y, final int w, final int h) {378if (fBorderInsets == null) getBorderInsets(c);379// Set the contentRect - inset by border size380setInBounds(x + fBorderInsets.left, y + fBorderInsets.top, w - (fBorderInsets.right + fBorderInsets.left), h - (fBorderInsets.top + fBorderInsets.bottom));381382// Set parameters383setMetrics(frame, c);384385// Draw the frame386drawWindowTitle(g, frame, x, y, w, h);387}388389// defaults to false390boolean isDirty(final JInternalFrame frame) {391final Object dirty = frame.getClientProperty("windowModified");392if (dirty == null || dirty == Boolean.FALSE) return false;393return true;394}395396// Border interface397public Insets getBorderInsets(final Component c) {398if (fBorderInsets == null) fBorderInsets = new Insets(0, 0, 0, 0);399400// Paranoia check401if (!(c instanceof JInternalFrame)) return fBorderInsets;402403final JInternalFrame frame = (JInternalFrame)c;404405// Set the contentRect to an arbitrary value (in case the current real one is too small)406setInBounds(0, 0, kContentTester, kContentTester);407408// Set parameters409setMetrics(frame, c);410411fBorderInsets.left = 0;412fBorderInsets.top = metrics.titleBarHeight;413fBorderInsets.right = 0;414fBorderInsets.bottom = 0;415416return fBorderInsets;417}418419public void repaintButtonArea(final JInternalFrame frame) {420final Insets i = frame.getInsets();421final int x = i.left + metrics.leftSidePadding;422final int y = i.top - metrics.titleBarHeight + 1;423frame.repaint(x, y, fThisButtonSpan, metrics.titleBarHeight - 2);424}425426// Draw all the widgets this frame supports427void drawAllWidgets(final Graphics g, final JInternalFrame frame) {428int x = metrics.leftSidePadding;429int y = (metrics.titleBarHeight - metrics.buttonHeight) / 2 - metrics.titleBarHeight;430431final Insets insets = frame.getInsets();432x += insets.left;433y += insets.top + metrics.downShift;434435final AquaInternalFrameUI ui = (AquaInternalFrameUI)frame.getUI();436final int buttonPressedIndex = ui.getWhichButtonPressed();437final boolean overButton = ui.getMouseOverPressedButton();438final boolean rollover = ui.getRollover();439440final boolean frameSelected = frame.isSelected() || fIsUtility;441final boolean generalActive = rollover || frameSelected;442443final boolean dirty = isDirty(frame);444445paintButton(g, frame, x, y, kCloseButton, buttonPressedIndex, overButton, frame.isClosable(), generalActive, rollover, dirty);446447x += metrics.buttonPadding + metrics.buttonWidth;448paintButton(g, frame, x, y, kIconButton, buttonPressedIndex, overButton, frame.isIconifiable(), generalActive, rollover, false);449450x += metrics.buttonPadding + metrics.buttonWidth;451paintButton(g, frame, x, y, kGrowButton, buttonPressedIndex, overButton, frame.isMaximizable(), generalActive, rollover, false);452}453454public void paintButton(final Graphics g, final JInternalFrame frame, final int x, final int y, final int buttonType, final int buttonPressedIndex, final boolean overButton, final boolean enabled, final boolean active, final boolean anyRollover, final boolean dirty) {455widgetPainter.state.set(getWidget(frame, buttonType));456widgetPainter.state.set(getState(buttonPressedIndex == buttonType && overButton, anyRollover, active, enabled));457widgetPainter.state.set(dirty ? BooleanValue.YES : BooleanValue.NO);458widgetPainter.paint(g, frame, x, y, metrics.buttonWidth, metrics.buttonHeight);459}460461static Widget getWidget(final JInternalFrame frame, final int buttonType) {462switch (buttonType) {463case kIconButton: return Widget.TITLE_BAR_COLLAPSE_BOX;464case kGrowButton: return Widget.TITLE_BAR_ZOOM_BOX;465}466467return Widget.TITLE_BAR_CLOSE_BOX;468}469470static State getState(final boolean pressed, final boolean rollover, final boolean active, final boolean enabled) {471if (!enabled) return State.DISABLED;472if (!active) return State.INACTIVE;473if (pressed) return State.PRESSED;474if (rollover) return State.ROLLOVER;475return State.ACTIVE;476}477478protected void setMetrics(final JInternalFrame frame, final Component window) {479final String title = frame.getTitle();480final FontMetrics fm = frame.getFontMetrics(UIManager.getFont("InternalFrame.titleFont"));481int titleWidth = 0;482int titleHeight = fm.getAscent();483if (title != null) {484titleWidth = SwingUtilities.computeStringWidth(fm, title);485}486// Icon space487final Icon icon = frame.getFrameIcon();488if (icon != null) {489titleWidth += icon.getIconWidth();490titleHeight = Math.max(titleHeight, icon.getIconHeight());491}492}493494protected int getTitleHeight() {495return metrics.titleBarHeight;496}497}498499500