Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.desktop/macosx/classes/com/apple/laf/AquaInternalFrameBorder.java
41154 views
1
/*
2
* Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
package com.apple.laf;
27
28
import java.awt.*;
29
import java.beans.PropertyVetoException;
30
31
import javax.swing.*;
32
import javax.swing.border.Border;
33
import javax.swing.plaf.UIResource;
34
35
import sun.swing.SwingUtilities2;
36
37
import apple.laf.*;
38
import apple.laf.JRSUIConstants.*;
39
import apple.laf.JRSUIState.TitleBarHeightState;
40
41
import com.apple.laf.AquaUtils.RecyclableSingleton;
42
import com.apple.laf.AquaInternalFrameBorderMetrics;
43
import java.awt.geom.AffineTransform;
44
45
public class AquaInternalFrameBorder implements Border, UIResource {
46
private static final int kCloseButton = 0;
47
private static final int kIconButton = 1;
48
private static final int kGrowButton = 2;
49
50
private static final int sMaxIconWidth = 15;
51
private static final int sMaxIconHeight = sMaxIconWidth;
52
private static final int sAfterButtonPad = 11;
53
private static final int sAfterIconPad = 5;
54
private static final int sRightSideTitleClip = 0;
55
56
private static final int kContentTester = 100; // For getting region insets
57
58
private static final RecyclableSingleton<AquaInternalFrameBorder> documentWindowFrame = new RecyclableSingleton<AquaInternalFrameBorder>() {
59
protected AquaInternalFrameBorder getInstance() {
60
return new AquaInternalFrameBorder(WindowType.DOCUMENT);
61
}
62
};
63
protected static AquaInternalFrameBorder window() {
64
return documentWindowFrame.get();
65
}
66
67
private static final RecyclableSingleton<AquaInternalFrameBorder> utilityWindowFrame = new RecyclableSingleton<AquaInternalFrameBorder>() {
68
protected AquaInternalFrameBorder getInstance() {
69
return new AquaInternalFrameBorder(WindowType.UTILITY);
70
}
71
};
72
protected static AquaInternalFrameBorder utility() {
73
return utilityWindowFrame.get();
74
}
75
76
private static final RecyclableSingleton<AquaInternalFrameBorder> dialogWindowFrame = new RecyclableSingleton<AquaInternalFrameBorder>() {
77
protected AquaInternalFrameBorder getInstance() {
78
return new AquaInternalFrameBorder(WindowType.DOCUMENT);
79
}
80
};
81
protected static AquaInternalFrameBorder dialog() {
82
return dialogWindowFrame.get();
83
}
84
85
private final AquaInternalFrameBorderMetrics metrics;
86
87
private final int fThisButtonSpan;
88
private final int fThisLeftSideTotal;
89
90
private final boolean fIsUtility;
91
92
// Instance variables
93
private final WindowType fWindowKind; // Which kind of window to draw
94
private Insets fBorderInsets; // Cached insets object
95
96
private Color selectedTextColor;
97
private Color notSelectedTextColor;
98
99
private Rectangle fInBounds; // Cached bounds rect object
100
101
protected final AquaPainter<TitleBarHeightState> titleBarPainter = AquaPainter.create(JRSUIStateFactory.getTitleBar());
102
protected final AquaPainter<JRSUIState> widgetPainter = AquaPainter.create(JRSUIState.getInstance());
103
104
protected AquaInternalFrameBorder(final WindowType kind) {
105
fWindowKind = kind;
106
107
titleBarPainter.state.set(WindowClipCorners.YES);
108
if (fWindowKind == WindowType.UTILITY) {
109
fIsUtility = true;
110
metrics = AquaInternalFrameBorderMetrics.getMetrics(true);
111
112
widgetPainter.state.set(WindowType.UTILITY);
113
titleBarPainter.state.set(WindowType.UTILITY);
114
} else {
115
fIsUtility = false;
116
metrics = AquaInternalFrameBorderMetrics.getMetrics(false);
117
118
widgetPainter.state.set(WindowType.DOCUMENT);
119
titleBarPainter.state.set(WindowType.DOCUMENT);
120
}
121
titleBarPainter.state.setValue(metrics.titleBarHeight);
122
titleBarPainter.state.set(WindowTitleBarSeparator.YES);
123
widgetPainter.state.set(AlignmentVertical.CENTER);
124
125
fThisButtonSpan = (metrics.buttonWidth * 3) + (metrics.buttonPadding * 2);
126
fThisLeftSideTotal = metrics.leftSidePadding + fThisButtonSpan + sAfterButtonPad;
127
}
128
129
public void setColors(final Color inSelectedTextColor, final Color inNotSelectedTextColor) {
130
selectedTextColor = inSelectedTextColor;
131
notSelectedTextColor = inNotSelectedTextColor;
132
}
133
134
// Utility to lazy-init and fill in fInBounds
135
protected void setInBounds(final int x, final int y, final int w, final int h) {
136
if (fInBounds == null) fInBounds = new Rectangle();
137
138
fInBounds.x = x;
139
fInBounds.y = y;
140
fInBounds.width = w;
141
fInBounds.height = h;
142
}
143
144
// Border interface
145
public boolean isBorderOpaque() {
146
return false;
147
}
148
149
// Border interface
150
public void paintBorder(final Component c, final Graphics g, final int x, final int y, final int w, final int h) {
151
// For expanded InternalFrames, the frame & component are the same object
152
paintBorder((JInternalFrame)c, c, g, x, y, w, h);
153
}
154
155
protected void paintTitleContents(final Graphics g, final JInternalFrame frame, final int x, final int y, final int w, final int h) {
156
final boolean isSelected = frame.isSelected();
157
final Font f = g.getFont();
158
159
g.setFont(metrics.font);
160
161
// Center text vertically.
162
final FontMetrics fm = g.getFontMetrics();
163
final int baseline = (metrics.titleBarHeight + fm.getAscent() - fm.getLeading() - fm.getDescent()) / 2;
164
165
// max button is the rightmost so use it
166
final int usedWidth = fThisLeftSideTotal + sRightSideTitleClip;
167
int iconWidth = getIconWidth(frame);
168
if (iconWidth > 0) iconWidth += sAfterIconPad;
169
170
final int totalWidth = w;
171
172
// window title looks like: | 0 0 0(sAfterButtonPad)IconWidth Title(right pad) |
173
final int availTextWidth = totalWidth - usedWidth - iconWidth - sAfterButtonPad;
174
175
final String title = frame.getTitle();
176
177
String text = title;
178
int totalTextWidth = 0;
179
180
int startXPosition = fThisLeftSideTotal;
181
boolean wasTextShortened = false;
182
// shorten the string to fit in the
183
if (text != null && !text.isEmpty()) {
184
totalTextWidth = SwingUtilities.computeStringWidth(fm, text);
185
final String clipString = "\u2026";
186
if (totalTextWidth > availTextWidth) {
187
wasTextShortened = true;
188
totalTextWidth = SwingUtilities.computeStringWidth(fm, clipString);
189
int nChars;
190
for (nChars = 0; nChars < text.length(); nChars++) {
191
final int nextCharWidth = fm.charWidth(text.charAt(nChars));
192
if ((totalTextWidth + nextCharWidth) > availTextWidth) {
193
break;
194
}
195
totalTextWidth += nextCharWidth;
196
}
197
text = text.substring(0, nChars) + clipString;
198
}
199
200
if (!wasTextShortened) {
201
// center it!
202
startXPosition = (totalWidth - (totalTextWidth + iconWidth)) / 2;
203
if (startXPosition < fThisLeftSideTotal) {
204
startXPosition = fThisLeftSideTotal;
205
}
206
}
207
208
if (isSelected || fIsUtility) {
209
g.setColor(Color.lightGray);
210
} else {
211
g.setColor(Color.white);
212
}
213
SwingUtilities2.drawString(frame, g, text, x + startXPosition + iconWidth, y + baseline + 1);
214
215
if (isSelected || fIsUtility) {
216
g.setColor(selectedTextColor);
217
} else {
218
g.setColor(notSelectedTextColor);
219
}
220
221
SwingUtilities2.drawString(frame, g, text, x + startXPosition + iconWidth, y + baseline);
222
g.setFont(f);
223
}
224
225
// sja fix x & y
226
final int iconYPostion = (metrics.titleBarHeight - getIconHeight(frame)) / 2;
227
paintTitleIcon(g, frame, x + startXPosition, y + iconYPostion);
228
}
229
230
public int getWhichButtonHit(final JInternalFrame frame, final int x, final int y) {
231
int buttonHit = -1;
232
233
final Insets i = frame.getInsets();
234
int startX = i.left + metrics.leftSidePadding - 1;
235
if (isInsideYButtonArea(i, y) && x >= startX) {
236
if (x <= (startX + metrics.buttonWidth)) {
237
if (frame.isClosable()) {
238
buttonHit = kCloseButton;
239
}
240
} else {
241
startX += metrics.buttonWidth + metrics.buttonPadding;
242
if (x >= startX && x <= (startX + metrics.buttonWidth)) {
243
if (frame.isIconifiable()) {
244
buttonHit = kIconButton;
245
}
246
} else {
247
startX += metrics.buttonWidth + metrics.buttonPadding;
248
if (x >= startX && x <= (startX + metrics.buttonWidth)) {
249
if (frame.isMaximizable()) {
250
buttonHit = kGrowButton;
251
}
252
}
253
}
254
}
255
}
256
257
return buttonHit;
258
}
259
260
public void doButtonAction(final JInternalFrame frame, final int whichButton) {
261
switch (whichButton) {
262
case kCloseButton:
263
frame.doDefaultCloseAction();
264
break;
265
266
case kIconButton:
267
if (frame.isIconifiable()) {
268
if (!frame.isIcon()) {
269
try {
270
frame.setIcon(true);
271
} catch(final PropertyVetoException e1) {}
272
} else {
273
try {
274
frame.setIcon(false);
275
} catch(final PropertyVetoException e1) {}
276
}
277
}
278
break;
279
280
case kGrowButton:
281
if (frame.isMaximizable()) {
282
if (!frame.isMaximum()) {
283
try {
284
frame.setMaximum(true);
285
} catch(final PropertyVetoException e5) {}
286
} else {
287
try {
288
frame.setMaximum(false);
289
} catch(final PropertyVetoException e6) {}
290
}
291
}
292
break;
293
294
default:
295
System.err.println("AquaInternalFrameBorder should never get here!!!!");
296
Thread.dumpStack();
297
break;
298
}
299
}
300
301
public boolean isInsideYButtonArea(final Insets i, final int y) {
302
final int startY = (i.top - metrics.titleBarHeight / 2) - (metrics.buttonHeight / 2) - 1;
303
final int endY = startY + metrics.buttonHeight;
304
return y >= startY && y <= endY;
305
}
306
307
public boolean getWithinRolloverArea(final Insets i, final int x, final int y) {
308
final int startX = i.left + metrics.leftSidePadding;
309
final int endX = startX + fThisButtonSpan;
310
return isInsideYButtonArea(i, y) && x >= startX && x <= endX;
311
}
312
313
protected void paintTitleIcon(final Graphics g, final JInternalFrame frame,
314
final int x, final int y) {
315
316
Icon icon = frame.getFrameIcon();
317
if (icon == null) {
318
icon = UIManager.getIcon("InternalFrame.icon");
319
}
320
321
if (icon == null) {
322
return;
323
}
324
325
if (icon.getIconWidth() > sMaxIconWidth
326
|| icon.getIconHeight() > sMaxIconHeight) {
327
final Graphics2D g2 = (Graphics2D) g;
328
final AffineTransform savedAT = g2.getTransform();
329
double xScaleFactor = (double) sMaxIconWidth / icon.getIconWidth();
330
double yScaleFactor = (double) sMaxIconHeight / icon.getIconHeight();
331
332
//Coordinates are after a translation hence relative origin shifts
333
g2.translate(x, y);
334
335
//scaling factor is needed to scale while maintaining aspect ratio
336
double scaleMaintainAspectRatio = Math.min(xScaleFactor, yScaleFactor);
337
338
//minimum value is taken to set to a maximum Icon Dimension
339
g2.scale(scaleMaintainAspectRatio, scaleMaintainAspectRatio);
340
341
icon.paintIcon(frame, g2, 0, 0);
342
g2.setTransform(savedAT);
343
344
} else {
345
icon.paintIcon(frame, g, x, y);
346
}
347
}
348
349
protected int getIconWidth(final JInternalFrame frame) {
350
int width = 0;
351
352
Icon icon = frame.getFrameIcon();
353
if (icon == null) {
354
icon = UIManager.getIcon("InternalFrame.icon");
355
}
356
if (icon != null) {
357
width = Math.min(icon.getIconWidth(), sMaxIconWidth);
358
}
359
360
return width;
361
}
362
363
protected int getIconHeight(final JInternalFrame frame) {
364
int height = 0;
365
366
Icon icon = frame.getFrameIcon();
367
if (icon == null) {
368
icon = UIManager.getIcon("InternalFrame.icon");
369
}
370
if (icon != null) {
371
height = Math.min(icon.getIconHeight(), sMaxIconHeight);
372
}
373
374
return height;
375
}
376
377
public void drawWindowTitle(final Graphics g, final JInternalFrame frame, final int inX, final int inY, final int inW, final int inH) {
378
final int x = inX;
379
final int y = inY;
380
final int w = inW;
381
int h = inH;
382
383
h = metrics.titleBarHeight + inH;
384
385
// paint the background
386
titleBarPainter.state.set(frame.isSelected() ? State.ACTIVE : State.INACTIVE);
387
titleBarPainter.paint(g, frame, x, y, w, h);
388
389
// now the title and the icon
390
paintTitleContents(g, frame, x, y, w, h);
391
392
// finally the widgets
393
drawAllWidgets(g, frame); // rollover is last attribute
394
}
395
396
// Component could be a JInternalFrame or a JDesktopIcon
397
void paintBorder(final JInternalFrame frame, final Component c, final Graphics g, final int x, final int y, final int w, final int h) {
398
if (fBorderInsets == null) getBorderInsets(c);
399
// Set the contentRect - inset by border size
400
setInBounds(x + fBorderInsets.left, y + fBorderInsets.top, w - (fBorderInsets.right + fBorderInsets.left), h - (fBorderInsets.top + fBorderInsets.bottom));
401
402
// Set parameters
403
setMetrics(frame, c);
404
405
// Draw the frame
406
drawWindowTitle(g, frame, x, y, w, h);
407
}
408
409
// defaults to false
410
boolean isDirty(final JInternalFrame frame) {
411
final Object dirty = frame.getClientProperty("windowModified");
412
if (dirty == null || dirty == Boolean.FALSE) return false;
413
return true;
414
}
415
416
// Border interface
417
public Insets getBorderInsets(final Component c) {
418
if (fBorderInsets == null) fBorderInsets = new Insets(0, 0, 0, 0);
419
420
// Paranoia check
421
if (!(c instanceof JInternalFrame)) return fBorderInsets;
422
423
final JInternalFrame frame = (JInternalFrame)c;
424
425
// Set the contentRect to an arbitrary value (in case the current real one is too small)
426
setInBounds(0, 0, kContentTester, kContentTester);
427
428
// Set parameters
429
setMetrics(frame, c);
430
431
fBorderInsets.left = 0;
432
fBorderInsets.top = metrics.titleBarHeight;
433
fBorderInsets.right = 0;
434
fBorderInsets.bottom = 0;
435
436
return fBorderInsets;
437
}
438
439
public void repaintButtonArea(final JInternalFrame frame) {
440
final Insets i = frame.getInsets();
441
final int x = i.left + metrics.leftSidePadding;
442
final int y = i.top - metrics.titleBarHeight + 1;
443
frame.repaint(x, y, fThisButtonSpan, metrics.titleBarHeight - 2);
444
}
445
446
// Draw all the widgets this frame supports
447
void drawAllWidgets(final Graphics g, final JInternalFrame frame) {
448
int x = metrics.leftSidePadding;
449
int y = (metrics.titleBarHeight - metrics.buttonHeight) / 2 - metrics.titleBarHeight;
450
451
final Insets insets = frame.getInsets();
452
x += insets.left;
453
y += insets.top + metrics.downShift;
454
455
final AquaInternalFrameUI ui = (AquaInternalFrameUI)frame.getUI();
456
final int buttonPressedIndex = ui.getWhichButtonPressed();
457
final boolean overButton = ui.getMouseOverPressedButton();
458
final boolean rollover = ui.getRollover();
459
460
final boolean frameSelected = frame.isSelected() || fIsUtility;
461
final boolean generalActive = rollover || frameSelected;
462
463
final boolean dirty = isDirty(frame);
464
465
paintButton(g, frame, x, y, kCloseButton, buttonPressedIndex, overButton, frame.isClosable(), generalActive, rollover, dirty);
466
467
x += metrics.buttonPadding + metrics.buttonWidth;
468
paintButton(g, frame, x, y, kIconButton, buttonPressedIndex, overButton, frame.isIconifiable(), generalActive, rollover, false);
469
470
x += metrics.buttonPadding + metrics.buttonWidth;
471
paintButton(g, frame, x, y, kGrowButton, buttonPressedIndex, overButton, frame.isMaximizable(), generalActive, rollover, false);
472
}
473
474
public 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) {
475
widgetPainter.state.set(getWidget(frame, buttonType));
476
widgetPainter.state.set(getState(buttonPressedIndex == buttonType && overButton, anyRollover, active, enabled));
477
widgetPainter.state.set(dirty ? BooleanValue.YES : BooleanValue.NO);
478
widgetPainter.paint(g, frame, x, y, metrics.buttonWidth, metrics.buttonHeight);
479
}
480
481
static Widget getWidget(final JInternalFrame frame, final int buttonType) {
482
switch (buttonType) {
483
case kIconButton: return Widget.TITLE_BAR_COLLAPSE_BOX;
484
case kGrowButton: return Widget.TITLE_BAR_ZOOM_BOX;
485
}
486
487
return Widget.TITLE_BAR_CLOSE_BOX;
488
}
489
490
static State getState(final boolean pressed, final boolean rollover, final boolean active, final boolean enabled) {
491
if (!enabled) return State.DISABLED;
492
if (!active) return State.INACTIVE;
493
if (pressed) return State.PRESSED;
494
if (rollover) return State.ROLLOVER;
495
return State.ACTIVE;
496
}
497
498
protected void setMetrics(final JInternalFrame frame, final Component window) {
499
final String title = frame.getTitle();
500
final FontMetrics fm = frame.getFontMetrics(UIManager.getFont("InternalFrame.titleFont"));
501
int titleWidth = 0;
502
int titleHeight = fm.getAscent();
503
if (title != null) {
504
titleWidth = SwingUtilities.computeStringWidth(fm, title);
505
}
506
// Icon space
507
final Icon icon = frame.getFrameIcon();
508
if (icon != null) {
509
titleWidth += icon.getIconWidth();
510
titleHeight = Math.max(titleHeight, icon.getIconHeight());
511
}
512
}
513
514
protected int getTitleHeight() {
515
return metrics.titleBarHeight;
516
}
517
}
518
519