001: package org.jvnet.substance.netbeans;
002:
003: import java.awt.Graphics;
004: import java.awt.Graphics2D;
005: import java.awt.geom.GeneralPath;
006: import java.awt.image.BufferedImage;
007: import java.util.HashMap;
008: import java.util.Map;
009: import javax.swing.AbstractButton;
010: import org.jvnet.substance.SubstanceImageCreator;
011: import org.jvnet.substance.SubstanceLookAndFeel;
012: import org.jvnet.substance.border.SubstanceBorderPainter;
013: import org.jvnet.substance.button.SubstanceButtonShaper;
014: import org.jvnet.substance.color.ColorScheme;
015: import org.jvnet.substance.painter.SubstanceGradientPainter;
016: import org.jvnet.substance.theme.SubstanceTheme;
017: import org.jvnet.substance.utils.ComponentState;
018: import org.jvnet.substance.utils.SubstanceCoreUtilities;
019: import org.netbeans.swing.tabcontrol.SlideBarDataModel;
020: import org.netbeans.swing.tabcontrol.SlidingButton;
021:
022: /**
023: * Delegate class for painting backgrounds of buttons in <b>NetBeans Substance</b>
024: * plugin.
025: *
026: * @author Kirill Grouchnikov
027: */
028: class NetbeansButtonBackgroundDelegate {
029:
030: /**
031: * Cache for background images with regular slightly-round corners. Each
032: * time {@link #getBackground(AbstractButton, int, int, boolean)} is called
033: * with <code>isRoundCorners</code> equal to <code>false</code>, it
034: * checks <code>this</code> map to see if it already contains such
035: * background. If so, the background from the map is returned.
036: */
037: private static Map<String, BufferedImage> regularBackgrounds = new HashMap<String, BufferedImage>();
038:
039: /**
040: * Resets image maps (used when setting new theme).
041: *
042: * @see SubstanceLookAndFeel#setCurrentTheme(String)
043: * @see SubstanceLookAndFeel#setCurrentTheme(SubstanceTheme)
044: */
045: static synchronized void reset() {
046: regularBackgrounds.clear();
047: }
048:
049: /**
050: * Retrieves background image for the specified button.
051: *
052: * @param button
053: * Button.
054: * @param width
055: * Button width.
056: * @param height
057: * Button height.
058: * @param isRoundCorners
059: * If <code>true</code>, the corners of the resulting button
060: * will be completely rounded.
061: * @return Button background image.
062: */
063: private static synchronized BufferedImage getBackground(
064: AbstractButton button, GeneralPath contour, int width,
065: int height) {
066: ComponentState state = ComponentState.getState(button
067: .getModel(), button);
068: int cyclePos = state.getCycleCount();
069:
070: SubstanceTheme theme = SubstanceCoreUtilities.getTheme(button,
071: state, true, true, true);
072: ColorScheme colorScheme = theme.getColorScheme();
073: ColorScheme borderScheme = theme.getBorderTheme()
074: .getColorScheme();
075:
076: SlidingButton slider = (SlidingButton) button;
077: int orientation = slider.getOrientation();
078: int rotation = 0;
079: switch (orientation) {
080: case SlideBarDataModel.EAST:
081: rotation = 3;
082: break;
083: case SlideBarDataModel.WEST:
084: rotation = 1;
085: break;
086: }
087:
088: String key = width + ":" + height + ":" + state.name() + ":"
089: + cyclePos + ":"
090: + SubstanceCoreUtilities.getSchemeId(colorScheme) + ":"
091: + SubstanceCoreUtilities.getSchemeId(borderScheme)
092: + ":" + rotation + ":" + button.getClass().getName();
093: Map<String, BufferedImage> backgrounds = regularBackgrounds;
094: if (!backgrounds.containsKey(key)) {
095: BufferedImage newBackground;
096:
097: SubstanceGradientPainter painter = SubstanceLookAndFeel
098: .getCurrentGradientPainter();
099: SubstanceBorderPainter borderPainter = SubstanceCoreUtilities
100: .getBorderPainter(button, painter);
101: BufferedImage contourImage = painter.getContourBackground(
102: width, height, contour, false, colorScheme,
103: colorScheme, cyclePos, true, false);
104: borderPainter.paintBorder(contourImage.getGraphics(),
105: button, width, height, contour, null, borderScheme,
106: borderScheme, cyclePos, false);
107: if (rotation == 0) {
108: newBackground = contourImage;
109: } else {
110: newBackground = SubstanceImageCreator.getRotated(
111: contourImage, 2);
112:
113: newBackground = SubstanceImageCreator.getRotated(
114: newBackground, rotation - 1);
115: }
116:
117: backgrounds.put(key, newBackground);
118: }
119: return backgrounds.get(key);
120: }
121:
122: /**
123: * Simple constructor.
124: */
125: public NetbeansButtonBackgroundDelegate() {
126: super ();
127: }
128:
129: /**
130: * Updates background of the specified button.
131: *
132: * @param g
133: * Graphic context.
134: * @param button
135: * Button to update.
136: * @param cycleCount
137: * Cycle count for transition effects.
138: */
139: public void updateBackground(Graphics g, AbstractButton button,
140: long cycleCount) {
141: button.setOpaque(false);
142: Graphics2D graphics = (Graphics2D) g;
143:
144: int width = button.getWidth();
145: int height = button.getHeight();
146:
147: if ((width <= 0) || (height <= 0)) {
148: return;
149: }
150: SubstanceButtonShaper shaper = SubstanceLookAndFeel
151: .getCurrentButtonShaper();
152: Object customShaperClass = button
153: .getClientProperty(SubstanceLookAndFeel.BUTTON_SHAPER_PROPERTY);
154: if (customShaperClass != null) {
155: try {
156: shaper = (SubstanceButtonShaper) Class.forName(
157: (String) customShaperClass).newInstance();
158: } catch (Exception exc) {
159: shaper = SubstanceLookAndFeel.getCurrentButtonShaper();
160: }
161: }
162: GeneralPath contour = shaper.getButtonOutline(button);
163: graphics.drawImage(
164: getBackground(button, contour, width, height), 0, 0,
165: null);
166: }
167:
168: /**
169: * Returns <code>true</code> if the specified <i>x,y</i> location is
170: * contained within the look and feel's defined shape of the specified
171: * component. <code>x</code> and <code>y</code> are defined to be
172: * relative to the coordinate system of the specified component.
173: *
174: * @param button
175: * the component where the <i>x,y</i> location is being queried;
176: * @param x
177: * the <i>x</i> coordinate of the point
178: * @param y
179: * the <i>y</i> coordinate of the point
180: */
181: public static boolean contains(AbstractButton button, int x, int y) {
182: int width = button.getWidth();
183: int height = button.getHeight();
184:
185: // rough estimation - outside the rectangle.
186: if ((x < 0) || (y < 0) || (x > width) || (y > height)) {
187: return false;
188: }
189: int radius = 2;
190:
191: // mirror
192: if (x >= (width / 2)) {
193: x = width - x;
194: }
195: if (y >= (height / 2)) {
196: y = height - y;
197: }
198:
199: if ((x < radius) && (y < radius)) {
200: int dx = radius - x;
201: int dy = radius - y;
202: int diff = dx * dx + dy * dy - radius * radius;
203: return diff <= 0;
204: } else {
205: return true;
206: }
207: }
208: }
|