/*
* @(#)BlueprintEngine.java 1.23 03/12/19
*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*/
package com.sun.java.swing.plaf.gtk;
import java.awt.*;
import java.awt.image.*;
import java.security.AccessController;
import java.util.*;
import javax.swing.*;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.synth.*;
import sun.security.action.GetPropertyAction;
import sun.swing.plaf.synth.SynthUI;
/**
* GTKEngine implementation that renders using images. The images to render
* are dictated by the BlueprintStyle.Info
.
*
* @version 1.23 12/19/03
* @author Joshua Outwater
*/
class BlueprintEngine extends GTKEngine implements GTKConstants {
/**
* By default we don't use smooth scaling as it is currently not optimized.
*/
private static final Object RENDERING_HINT;
private int COMPONENT_NORTH_WEST = 1;
private int COMPONENT_NORTH = 2;
private int COMPONENT_NORTH_EAST = 4;
private int COMPONENT_WEST = 8;
private int COMPONENT_CENTER = 16;
private int COMPONENT_EAST = 32;
private int COMPONENT_SOUTH_EAST = 64;
private int COMPONENT_SOUTH = 128;
private int COMPONENT_SOUTH_WEST = 256;
private int COMPONENT_ALL = 512;
private int _clipX1;
private int _clipX2;
private int _clipY1;
private int _clipY2;
static {
if ("true".equals((String)AccessController.doPrivileged(
new GetPropertyAction("swing.pixmap.smoothScaling")))) {
RENDERING_HINT = RenderingHints.VALUE_INTERPOLATION_BILINEAR;
}
else {
RENDERING_HINT = null;
}
}
public void paintSlider(SynthContext context, Graphics g, int state,
int shadowType, String info,
int x, int y, int w, int h, int orientation) {
if (!paintSimpleImage(context, g, x, y, w, h, true,
((BlueprintStyle)context.getStyle()).
getInfo("SLIDER", info, state, shadowType, orientation,
UNDEFINED, UNDEFINED, null))) {
super.paintSlider(context, g, state, shadowType, info,
x, y, w, h, orientation);
}
}
public void paintHline(SynthContext context, Graphics g, int state,
String info, int x, int y, int w, int h) {
SynthStyle style = context.getStyle();
Component c = context.getComponent();
// We have a different style to use if we are the child of
// a popup menu.
c = c.getParent();
if (c instanceof JPopupMenu) {
SynthStyle newStyle = getStyle((JPopupMenu)c,
((JPopupMenu)c).getUI());
if (newStyle != null) {
style = newStyle;
}
}
BlueprintStyle.Info blueprintInfo =
((BlueprintStyle)style).getInfo("HLINE", info,
state, UNDEFINED, GTKConstants.HORIZONTAL,
UNDEFINED, UNDEFINED, null);
if (blueprintInfo != null && blueprintInfo.getImage() != null) {
themeBlueprintRender(context, g, x, y, w, h,
blueprintInfo.getImage(), blueprintInfo.getImageInsets(),
COMPONENT_ALL, blueprintInfo.getStretch(), false,
blueprintInfo.isBkgMask(), blueprintInfo.isRecolorable(),
blueprintInfo.getColorizeColor());
} else {
super.paintHline(context, g, state, info, x, y, w, h);
}
}
public void paintVline(SynthContext context, Graphics g, int state,
String info, int x, int y, int w, int h) {
BlueprintStyle.Info blueprintInfo =
((BlueprintStyle)context.getStyle()).getInfo("VLINE", info,
state, UNDEFINED, GTKConstants.VERTICAL,
UNDEFINED, UNDEFINED, null);
if (blueprintInfo != null && blueprintInfo.getImage() != null) {
themeBlueprintRender(context, g, x, y, w, h, blueprintInfo.getImage(),
blueprintInfo.getImageInsets(), COMPONENT_ALL,
blueprintInfo.getStretch(), false,
blueprintInfo.isBkgMask(), blueprintInfo.isRecolorable(),
blueprintInfo.getColorizeColor());
} else {
super.paintVline(context, g, state, info, x, y, w, h);
}
}
public void paintArrow(SynthContext context, Graphics g, int state,
int shadowType, int direction, String info,
int x, int y, int w, int h) {
Component c = context.getComponent();
// Don't paint the arrow if we're in a spinner or combo box.
// We get that from the image.
if (c.getName() == "Spinner.nextButton" ||
c.getName() == "Spinner.previousButton" ||
c.getName() == "ComboBox.arrowButton") {
return;
}
String parentType = null;
c = c.getParent();
if (c != null && c instanceof JComponent) {
c = c.getParent();
if (c != null && c instanceof JComponent) {
parentType = getComponentType((JComponent)c);
}
}
if (!paintSimpleImage(context, g, x, y, w, h, true,
((BlueprintStyle)context.getStyle()).
getInfo("ARROW", info, state, shadowType,
UNDEFINED, UNDEFINED, direction, parentType))) {
super.paintArrow(context, g, state, shadowType, direction,
info, x, y, w, h);
}
}
public void paintBox(SynthContext context, Graphics g, int state,
int shadowType, String info, int x, int y,
int w, int h) {
int orientation;
Region id = context.getRegion();
Component c = context.getComponent();
SynthStyle style = context.getStyle();
// Blueprint checks to make sure that we aren't calling
// paintBox on a slider/scrollbar with detail hscrollbar or
// vscrollbar, because they do the work in paintArrow instead.
// We do it here because we have the correct bounds for the whole
// button.
Integer arrowDirection =
(Integer)((JComponent)c).getClientProperty("__arrow_direction__");
if (info == "vscrollbar" || info == "hscrollbar" &&
arrowDirection != null) {
int direction = arrowDirection.intValue();
switch (direction) {
case SwingConstants.NORTH:
direction = GTKConstants.ARROW_UP;
break;
case SwingConstants.SOUTH:
direction = GTKConstants.ARROW_DOWN;
break;
case SwingConstants.EAST:
direction = GTKConstants.ARROW_RIGHT;
break;
case SwingConstants.WEST:
direction = GTKConstants.ARROW_LEFT;
break;
}
c = (JComponent)c.getParent();
if (c == null || !(c instanceof JComponent)) {
return;
}
if (c instanceof JScrollBar) {
SynthStyle newStyle = getStyle((JScrollBar)c,
((JScrollBar)c).getUI());
if (newStyle != null) {
style = newStyle;
}
if (paintSimpleImage(context, g, x, y, w, h, true,
((BlueprintStyle)style).getInfo("STEPPER", info,
state, UNDEFINED, UNDEFINED, UNDEFINED,
direction, null))) {
return;
}
if (!paintSimpleImage(context, g, x, y, w, h, true,
((BlueprintStyle)style).getInfo("BOX", info, state,
shadowType, UNDEFINED, UNDEFINED,
UNDEFINED, null))) {
super.paintBox(context, g, state, shadowType, info,
x, y, w, h);
}
return;
}
}
// If the button is in a spinner get the style of the JSpinner.
if (c.getName() == "Spinner.nextButton" ||
c.getName() == "Spinner.previousButton" &&
arrowDirection != null) {
if (arrowDirection.intValue() == SwingConstants.NORTH) {
info = "spinbutton_up";
} else {
info = "spinbutton_down";
}
c = c.getParent();
if (c instanceof JSpinner) {
SynthStyle newStyle = getStyle((JSpinner)c,
((JSpinner)c).getUI());
if (newStyle != null) {
style = newStyle;
}
}
}
if (id == Region.SCROLL_BAR) {
if (((JScrollBar)c).getOrientation() ==
SwingConstants.HORIZONTAL) {
orientation = GTKConstants.HORIZONTAL;
}
else {
orientation = GTKConstants.VERTICAL;
}
}
else if (id == Region.SLIDER_TRACK) {
if (((JSlider)c).getOrientation() ==
SwingConstants.HORIZONTAL) {
orientation = GTKConstants.HORIZONTAL;
}
else {
orientation = GTKConstants.VERTICAL;
}
}
else {
orientation = UNDEFINED;
}
String parentType = null;
if (c != null) {
c = c.getParent();
if (c != null && c instanceof JComponent) {
parentType = getComponentType((JComponent)c);
}
}
if (!paintSimpleImage(context, g, x, y, w, h, true,
((BlueprintStyle)style).getInfo("BOX", info, state,
shadowType, orientation, UNDEFINED, UNDEFINED,
parentType))) {
super.paintBox(context, g, state, shadowType, info, x, y, w, h);
}
}
public void paintBoxGap(SynthContext context, Graphics g, int state,
int shadow, String key, int x, int y,
int w, int h, int gapSide, int gapStart,
int gapSize) {
BlueprintStyle.Info info = ((BlueprintStyle)context.getStyle()).getInfo(
"BOX_GAP", key, state, shadow, UNDEFINED, gapSide, UNDEFINED,
null);
if (info != null) {
paintGapImage(context, info, g, x, y, w, h, true, gapSide,
gapStart, gapSize);
} else {
super.paintBoxGap(context, g, state, shadow, key, x, y, w, h,
gapSide, gapStart, gapSize);
}
}
public void paintHandle(SynthContext context, Graphics g, int paintState,
int shadowType, String info, int x, int y,
int w, int h, int orientation) {
if (info == "handlebox" || info == "dockitem") {
w -=2;
h -=1;
}
if (!paintSimpleImage(context, g, x, y, w, h, true,
((BlueprintStyle)context.getStyle()).
getInfo("HANDLE", info, paintState, shadowType,
orientation, UNDEFINED, UNDEFINED, null))) {
super.paintHandle(context, g, paintState, shadowType, info, x, y,
w, h, orientation);
}
}
public void paintOption(SynthContext context, Graphics g, int paintState,
int shadowType, String info, int x, int y,
int w, int h) {
if (!paintSimpleImage(context, g, x, y, w, h, true,
((BlueprintStyle)context.getStyle()).
getInfo("OPTION", info, paintState, shadowType,
UNDEFINED, UNDEFINED, UNDEFINED, null))) {
super.paintOption(context, g, paintState, shadowType, info, x, y,
w, h);
}
}
public void paintFocus(SynthContext context, Graphics g, int state,
String key, int x, int y, int w, int h) {
if (!paintSimpleImage(context, g, x, y, w, h, true,
((BlueprintStyle)context.getStyle()).
getInfo("FOCUS", key, state, UNDEFINED, UNDEFINED,
UNDEFINED, UNDEFINED, null))) {
super.paintFocus(context, g, state, key, x, y, w, h);
}
}
public void paintShadow(SynthContext context, Graphics g, int state,
int shadowType, String info, int x, int y,
int w, int h) {
Component c = context.getComponent();
String parentType = null;
SynthStyle style = context.getStyle();
if (c.getName() == "ComboBox.textField") {
parentType = "GtkCombo";
} else if (c.getName() == "ComboBox.renderer") {
c = c.getParent();
if (c != null) {
c = c.getParent();
parentType = "GtkCombo";
}
}
if (c instanceof JComboBox) {
// Use the Style from the editor
JComboBox cb = (JComboBox)c;
Component editor = cb.getEditor().getEditorComponent();
if (editor instanceof JTextField) {
if (!cb.isEditable() && editor.getParent() == null) {
// GTKStyleFactory hands back a bogus Style when a
// Component doesn't have a parent. As the editor
// is only parented when the JComboBox is editable it
// means we can get back a bogus style. To force the
// real style to be assigned we parent the editor.
// YES, this is ugly!
cb.add(editor);
cb.remove(editor);
}
SynthStyle newStyle = getStyle((JTextField)editor,
((JTextField)editor).getUI());
if (newStyle != null) {
style = newStyle;
}
}
}
if (info == "menu" && parentType == "GtkHBox") {
return;
}
if (!paintSimpleImage(context, g, x, y, w, h, true,
((BlueprintStyle)style).getInfo("SHADOW", info, state,
shadowType, UNDEFINED, UNDEFINED, UNDEFINED,
parentType))) {
super.paintShadow(context, g, state, shadowType, info, x, y, w, h);
}
}
public void paintExpander(SynthContext context, Graphics g, int state,
int expanderStyle, String info, int x,
int y, int w, int h) {
// It does not appear that there is a way to override this.
super.paintExpander(context, g, state, expanderStyle, info, x, y, w,h);
}
public void paintCheck(SynthContext context, Graphics g, int state,
int shadowType, String info, int x, int y,
int w, int h) {
if (!paintSimpleImage(context, g, x, y, w, h, true,
((BlueprintStyle)context.getStyle()).
getInfo("CHECK", info, state, shadowType, UNDEFINED,
UNDEFINED, UNDEFINED, null))) {
super.paintCheck(context, g, state, shadowType, info, x, y, w, h);
}
}
public void paintExtension(SynthContext context, Graphics g, int state,
int shadowType, String info, int x, int y,
int w, int h, int placement, int tabIndex) {
if (!paintSimpleImage(context, g, x, y, w, h, true,
((BlueprintStyle)context.getStyle()).
getInfo("EXTENSION", info, state, shadowType,
UNDEFINED, placement, UNDEFINED, null))) {
super.paintExtension(context, g, state, shadowType, info, x, y,
w, h, placement, tabIndex);
}
}
public void paintFlatBox(SynthContext context, Graphics g, int state,
String key, int x, int y, int w, int h) {
if (key == "checkbutton" && state == SynthConstants.MOUSE_OVER) {
return;
}
Component c = context.getComponent();
String parentType = null;
c = c.getParent();
if (c instanceof CellRendererPane) {
// Skip the CellRendererPane
c = c.getParent();
}
if (c != null && c instanceof JComponent) {
parentType = getComponentType((JComponent)c);
}
if (!paintSimpleImage(context, g, x, y, w, h, true,
((BlueprintStyle)context.getStyle()).
getInfo("FLAT_BOX", key, state, UNDEFINED, UNDEFINED,
UNDEFINED, UNDEFINED, parentType))) {
super.paintFlatBox(context, g, state, key, x, y, w, h);
}
}
void paintBackground(SynthContext context, Graphics g, int state,
Color color, int x, int y, int w, int h) {
JComponent c = context.getComponent();
if (c instanceof JPopupMenu) {
if (paintSimpleImage(context, g, x, y, w, h, true,
((BlueprintStyle)context.getStyle()).
getInfo("BACKGROUND", null, state, UNDEFINED,
UNDEFINED, UNDEFINED, UNDEFINED, null))) {
return;
}
}
super.paintBackground(context, g, state, color, x, y, w, h);
}
/**
* Paints a gap image. This renders the image into a portion of
* the passed in region that is dictated
* by the gapSide
and size
arguments. For
* example, if gapSide
is GTKConstants.TOP
,
* this will render the image into the space:
*
x origin | x + gapStart
* |
y origin | y
* |
width | gapSize
* |
height | size
* |