2
* Copyright (c) 2005-2010 Flamingo / Substance Kirill Grouchnikov. All Rights Reserved.
4
* Redistribution and use in source and binary forms, with or without
5
* modification, are permitted provided that the following conditions are met:
7
* o Redistributions of source code must retain the above copyright notice,
8
* this list of conditions and the following disclaimer.
10
* o Redistributions in binary form must reproduce the above copyright notice,
11
* this list of conditions and the following disclaimer in the documentation
12
* and/or other materials provided with the distribution.
14
* o Neither the name of Flamingo Kirill Grouchnikov nor the names of
15
* its contributors may be used to endorse or promote products derived
16
* from this software without specific prior written permission.
18
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
20
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
22
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
25
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
27
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
28
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
package org.pushingpixels.substance.flamingo.ribbon.ui;
32
import org.pushingpixels.flamingo.api.ribbon.AbstractRibbonBand;
33
import org.pushingpixels.flamingo.api.ribbon.RibbonContextualTaskGroup;
34
import org.pushingpixels.flamingo.api.ribbon.RibbonTask;
35
import org.pushingpixels.flamingo.internal.ui.ribbon.BasicRibbonUI;
36
import org.pushingpixels.flamingo.internal.ui.ribbon.JRibbonRootPane;
37
import org.pushingpixels.flamingo.internal.ui.ribbon.JRibbonTaskToggleButton;
38
import org.pushingpixels.flamingo.internal.utils.FlamingoUtilities;
39
import org.pushingpixels.substance.api.*;
40
import org.pushingpixels.substance.api.painter.border.SubstanceBorderPainter;
41
import org.pushingpixels.substance.internal.painter.BackgroundPaintingUtils;
42
import org.pushingpixels.substance.internal.painter.DecorationPainterUtils;
43
import org.pushingpixels.substance.internal.painter.SeparatorPainterUtils;
44
import org.pushingpixels.substance.internal.utils.SubstanceColorSchemeUtilities;
45
import org.pushingpixels.substance.internal.utils.SubstanceCoreUtilities;
46
import org.pushingpixels.substance.internal.utils.SubstanceSizeUtils;
49
import javax.swing.plaf.ColorUIResource;
50
import javax.swing.plaf.ComponentUI;
51
import javax.swing.plaf.UIResource;
53
import java.util.HashSet;
57
* UI for ribbon in <b>Substance</b> look and feel.
59
* @author Kirill Grouchnikov
61
public class SubstanceRibbonUI extends BasicRibbonUI {
64
* This component extends across the full width of the tab row
65
* so that header backgrounds can be properly painted
67
protected JComponent tabPanelHeaderBackground;
70
* Panel for hosting task toggle buttons.
72
* @author Kirill Grouchnikov
74
protected class SubstanceTaskToggleButtonsHostPanel extends
75
TaskToggleButtonsHostPanel {
77
protected void paintContextualTaskGroupOutlines(Graphics g,
78
RibbonContextualTaskGroup group, Rectangle groupBounds) {
79
Graphics2D g2d = (Graphics2D) g.create();
81
// SubstanceColorScheme scheme = SubstanceColorSchemeUtilities
82
// .getBorderColorScheme(ribbon, ComponentState.DEFAULT);
84
g2d.translate(groupBounds.x, 0);
85
SeparatorPainterUtils.paintSeparator(ribbon, g2d, 2,
86
groupBounds.height * 3 / 4, SwingConstants.VERTICAL, false,
87
0, groupBounds.height / 3, true);
89
g2d.translate(groupBounds.width - 1, 0);
90
SeparatorPainterUtils.paintSeparator(ribbon, g2d, 2,
91
groupBounds.height * 3 / 4, SwingConstants.VERTICAL, false,
92
0, groupBounds.height / 3, true);
98
protected void paintTaskOutlines(Graphics g) {
99
Graphics2D g2d = (Graphics2D) g.create();
100
SubstanceColorScheme scheme = SubstanceColorSchemeUtilities
101
.getColorScheme(ribbon,
102
ColorSchemeAssociationKind.SEPARATOR,
103
ComponentState.ENABLED);
105
Set<RibbonTask> tasksWithTrailingSeparators = new HashSet<RibbonTask>();
106
// add all regular tasks except the last
107
for (int i = 0; i < ribbon.getTaskCount() - 1; i++) {
108
RibbonTask task = ribbon.getTask(i);
109
tasksWithTrailingSeparators.add(task);
110
// System.out.println("Added " + task.getTitle());
112
// add all tasks of visible contextual groups except last task in
114
for (int i = 0; i < ribbon.getContextualTaskGroupCount(); i++) {
115
RibbonContextualTaskGroup group = ribbon
116
.getContextualTaskGroup(i);
117
if (ribbon.isVisible(group)) {
118
for (int j = 0; j < group.getTaskCount() - 1; j++) {
119
RibbonTask task = group.getTask(j);
120
tasksWithTrailingSeparators.add(task);
125
for (RibbonTask taskWithTrailingSeparator : tasksWithTrailingSeparators) {
126
JRibbonTaskToggleButton taskToggleButton = taskToggleButtons
127
.get(taskWithTrailingSeparator);
128
Rectangle bounds = taskToggleButton.getBounds();
129
int x = bounds.x + bounds.width + getTabButtonGap() / 2 - 1;
131
SeparatorPainterUtils.paintSeparator(ribbon, g2d, scheme, 2,
132
getHeight(), SwingConstants.VERTICAL, false,
133
getHeight() / 3, 0, true);
134
g2d.translate(-x, 0);
142
* Panel for hosting ribbon bands.
144
* @author Kirill Grouchnikov
146
protected class SubstanceBandHostPanel extends BandHostPanel {
148
protected void paintComponent(Graphics g) {
150
for (int i = 0; i < getComponentCount(); i++) {
151
Component child = getComponent(i);
152
if (child instanceof AbstractRibbonBand) {
153
dy = child.getBounds().y;
157
SubstanceRibbonBandUI.paintRibbonBandBackground(g, this, 0.0f, dy);
161
protected class SubstanceRibbonLayout extends BasicRibbonUI.RibbonLayout {
164
public void layoutContainer(Container c) {
165
super.layoutContainer(c);
167
tabPanelHeaderBackground.setBounds(
168
0, taskToggleButtonsScrollablePanel.getY(),
169
ribbon.getWidth(), taskToggleButtonsScrollablePanel.getHeight()
171
ribbon.setComponentZOrder(tabPanelHeaderBackground, ribbon.getComponentCount() - 1);
178
* @see javax.swing.plaf.ComponentUI#createUI(javax.swing.JComponent)
180
public static ComponentUI createUI(JComponent comp) {
181
SubstanceCoreUtilities.testComponentCreationThreadingViolation(comp);
182
return new SubstanceRibbonUI();
188
* @see org.jvnet.flamingo.ribbon.ui.BasicRibbonUI#installDefaults()
191
protected void installDefaults() {
192
super.installDefaults();
193
SubstanceLookAndFeel.setDecorationType(this.ribbon,
194
DecorationAreaType.HEADER);
195
Color backgr = this.ribbon.getBackground();
196
if (backgr == null || backgr instanceof UIResource) {
197
Color toSet = SubstanceColorSchemeUtilities.getColorScheme(
198
this.ribbon, ComponentState.ENABLED)
199
.getBackgroundFillColor();
200
this.ribbon.setBackground(new ColorUIResource(toSet));
207
* @see org.jvnet.flamingo.ribbon.ui.BasicRibbonUI#uninstallDefaults()
210
protected void uninstallDefaults() {
211
DecorationPainterUtils.clearDecorationType(this.ribbon);
212
super.uninstallDefaults();
218
* @see org.jvnet.flamingo.ribbon.ui.BasicRibbonUI#installComponents()
221
protected void installComponents() {
222
super.installComponents();
224
tabPanelHeaderBackground = new JPanel();
225
ribbon.add(tabPanelHeaderBackground);
226
SubstanceLookAndFeel.setDecorationType(this.tabPanelHeaderBackground,
227
DecorationAreaType.HEADER);
229
SubstanceLookAndFeel.setDecorationType(this.taskBarPanel,
230
DecorationAreaType.PRIMARY_TITLE_PANE);
231
SubstanceLookAndFeel.setDecorationType(this.ribbon,
232
DecorationAreaType.HEADER);
233
SubstanceLookAndFeel.setDecorationType(this.bandScrollablePanel,
234
DecorationAreaType.GENERAL);
238
protected void uninstallComponents() {
239
this.ribbon.remove(tabPanelHeaderBackground);
240
DecorationPainterUtils.clearDecorationType(this.taskBarPanel);
241
super.uninstallComponents();
245
protected LayoutManager createLayoutManager() {
246
return new SubstanceRibbonLayout();
253
* org.jvnet.flamingo.ribbon.ui.BasicRibbonUI#createTaskToggleButtonsHostPanel
257
protected TaskToggleButtonsHostPanel createTaskToggleButtonsHostPanel() {
258
return new SubstanceTaskToggleButtonsHostPanel();
264
* @see org.jvnet.flamingo.ribbon.ui.BasicRibbonUI#createBandHostPanel()
267
protected BandHostPanel createBandHostPanel() {
268
return new SubstanceBandHostPanel();
275
* org.jvnet.flamingo.ribbon.ui.BasicRibbonUI#paintBackground(java.awt.Graphics
279
protected void paintBackground(Graphics g) {
280
BackgroundPaintingUtils.update(g, this.ribbon, false);
287
* org.jvnet.flamingo.ribbon.ui.BasicRibbonUI#paintTaskArea(java.awt.Graphics
288
* , int, int, int, int)
291
protected void paintTaskArea(Graphics g, int x, int y, int width, int height) {
292
if (this.ribbon.getTaskCount() == 0)
295
Graphics2D g2d = (Graphics2D) g.create();
297
RibbonTask selectedTask = this.ribbon.getSelectedTask();
298
JRibbonTaskToggleButton selectedTaskButton = this.taskToggleButtons
300
Rectangle selectedTaskButtonBounds = selectedTaskButton.getBounds();
301
Point converted = SwingUtilities.convertPoint(selectedTaskButton
302
.getParent(), selectedTaskButtonBounds.getLocation(),
304
float radius = SubstanceSizeUtils
305
.getClassicButtonCornerRadius(SubstanceSizeUtils
306
.getComponentFontSize(this.ribbon));
308
int borderDelta = (int) Math.floor(SubstanceSizeUtils
309
.getBorderStrokeWidth(SubstanceSizeUtils
310
.getComponentFontSize(this.ribbon)) / 2.0);
312
SubstanceBorderPainter borderPainter = SubstanceCoreUtilities
313
.getBorderPainter(this.ribbon);
314
int borderThickness = (int) SubstanceSizeUtils
315
.getBorderStrokeWidth(SubstanceSizeUtils
316
.getComponentFontSize(this.ribbon));
318
AbstractRibbonBand band = (selectedTask.getBandCount() == 0) ? null
319
: selectedTask.getBand(0);
320
SubstanceColorScheme borderScheme = SubstanceColorSchemeUtilities
321
.getColorScheme(band, ColorSchemeAssociationKind.BORDER,
322
ComponentState.ENABLED);
324
Rectangle taskToggleButtonsViewportBounds = taskToggleButtonsScrollablePanel
325
.getView().getParent().getBounds();
326
taskToggleButtonsViewportBounds.setLocation(SwingUtilities
327
.convertPoint(taskToggleButtonsScrollablePanel,
328
taskToggleButtonsViewportBounds.getLocation(),
330
int startSelectedX = Math.max(converted.x + 1,
331
(int) taskToggleButtonsViewportBounds.getMinX());
332
startSelectedX = Math.min(startSelectedX,
333
(int) taskToggleButtonsViewportBounds.getMaxX());
334
int endSelectedX = Math.min(converted.x
335
+ selectedTaskButtonBounds.width - 1,
336
(int) taskToggleButtonsViewportBounds.getMaxX());
337
endSelectedX = Math.max(endSelectedX,
338
(int) taskToggleButtonsViewportBounds.getMinX());
340
Shape outerContour = RibbonBorderShaper.getRibbonBorderOutline(
341
this.ribbon, x + borderDelta, x + width - 2 * borderDelta - 1,
342
startSelectedX + borderDelta, endSelectedX - 2 * borderDelta,
343
converted.y + borderDelta, y + borderDelta, y + height - 2
344
* borderDelta, radius);
346
Shape innerContour = RibbonBorderShaper.getRibbonBorderOutline(
347
this.ribbon, x + borderDelta + borderThickness, x + width - 2
348
* (borderDelta + borderThickness) - 1, startSelectedX
349
+ borderDelta + borderThickness, endSelectedX - 2
350
* (borderDelta + borderThickness), converted.y
351
+ borderDelta + borderThickness, y + borderDelta
352
+ borderThickness, y + height - 2
353
* (borderDelta + borderThickness) + 1, radius);
355
g2d.setColor(SubstanceColorSchemeUtilities.getColorScheme(band,
356
ComponentState.ENABLED).getBackgroundFillColor());
357
g2d.clipRect(x, y, width, height + 2);
358
g2d.fill(outerContour);
360
borderPainter.paintBorder(g2d, this.ribbon, width, height
361
+ selectedTaskButtonBounds.height + 1, outerContour,
362
innerContour, borderScheme);
364
// check whether the currently selected task is a contextual task
365
RibbonTask selected = selectedTask;
366
RibbonContextualTaskGroup contextualGroup = selected
367
.getContextualGroup();
368
if (contextualGroup != null) {
369
// paint a small gradient directly below the task area
370
Insets ins = this.ribbon.getInsets();
371
int topY = ins.top + getTaskbarHeight();
372
int bottomY = topY + 5;
373
Color hueColor = contextualGroup.getHueColor();
374
Paint paint = new GradientPaint(0, topY, FlamingoUtilities
375
.getAlphaColor(hueColor,
376
(int) (255 * RibbonContextualTaskGroup.HUE_ALPHA)),
377
0, bottomY, FlamingoUtilities.getAlphaColor(hueColor, 0));
379
g2d.clip(outerContour);
380
g2d.fillRect(0, topY, width, bottomY - topY + 1);
383
// paint outlines of the contextual task groups
384
// paintContextualTaskGroupsOutlines(g);
392
* @see org.jvnet.flamingo.ribbon.ui.BasicRibbonUI#getTabButtonGap()
395
protected int getTabButtonGap() {
396
return SubstanceSizeUtils.getAdjustedSize(SubstanceSizeUtils
397
.getComponentFontSize(this.ribbon), super.getTabButtonGap(), 3,
405
* org.jvnet.flamingo.ribbon.ui.BasicRibbonUI#syncApplicationMenuRichTooltip
409
protected void syncApplicationMenuTips() {
410
JRibbonRootPane ribbonRootPane = (JRibbonRootPane) SwingUtilities
411
.getRootPane(this.ribbon);
412
if (ribbonRootPane == null)
414
SubstanceRibbonRootPaneUI ribbonRootPaneUI = (SubstanceRibbonRootPaneUI) ribbonRootPane
416
ribbonRootPaneUI.syncApplicationMenuTips();
423
* org.jvnet.flamingo.ribbon.ui.BasicRibbonUI#paintMinimizedRibbonSeparator
424
* (java.awt.Graphics)
427
protected void paintMinimizedRibbonSeparator(Graphics g) {
428
Graphics2D g2d = (Graphics2D) g.create();
429
g2d.translate(0, this.ribbon.getHeight() - 1);
430
SeparatorPainterUtils.paintSeparator(this.ribbon, g2d, this.ribbon
431
.getWidth(), 0, JSeparator.HORIZONTAL, false, 0);