1 /* 2 * Copyright (c) 2007, 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. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /* 25 * @test 26 * @bug 6296064 6521533 27 * @summary A simple manual test for visual verification of GradientPaint 28 * LinearGradientPaint, and RadialGradientPaint. 29 * @run main/manual MultiGradientTest 30 * @author campbelc 31 */ 32 33 import java.awt.BorderLayout; 34 import java.awt.Color; 35 import java.awt.Dimension; 36 import java.awt.GradientPaint; 37 import java.awt.Graphics; 38 import java.awt.Graphics2D; 39 import java.awt.LinearGradientPaint; 40 import java.awt.MultipleGradientPaint.ColorSpaceType; 41 import java.awt.MultipleGradientPaint.CycleMethod; 42 import java.awt.Paint; 43 import java.awt.Polygon; 44 import java.awt.RadialGradientPaint; 45 import java.awt.Rectangle; 46 import java.awt.RenderingHints; 47 import java.awt.geom.AffineTransform; 48 import java.awt.geom.NoninvertibleTransformException; 49 import java.awt.geom.Point2D; 50 import java.awt.event.ActionEvent; 51 import java.awt.event.ActionListener; 52 import java.awt.event.MouseAdapter; 53 import java.awt.event.MouseEvent; 54 import java.awt.event.WindowAdapter; 55 import java.awt.event.WindowEvent; 56 import java.util.Arrays; 57 import java.util.ArrayList; 58 import java.util.EnumSet; 59 import java.util.List; 60 import javax.swing.AbstractListModel; 61 import javax.swing.BoxLayout; 62 import javax.swing.ComboBoxModel; 63 import javax.swing.JCheckBox; 64 import javax.swing.JComboBox; 65 import javax.swing.JFrame; 66 import javax.swing.JLabel; 67 import javax.swing.JPanel; 68 import javax.swing.JSpinner; 69 import javax.swing.SpinnerNumberModel; 70 import javax.swing.event.ChangeEvent; 71 import javax.swing.event.ChangeListener; 72 73 public class MultiGradientTest extends JPanel { 74 75 private static final Color[] COLORS = { 76 new Color(0, 0, 0), 77 new Color(128, 128, 128), 78 new Color(255, 0, 0), 79 new Color(255, 255, 0), 80 new Color(0, 255, 0), 81 new Color(0, 255, 255), 82 new Color(128, 0, 255), 83 new Color(128, 128, 128), 84 }; 85 86 private static enum PaintType {BASIC, LINEAR, RADIAL}; 87 private static enum ShapeType {RECT, ELLIPSE, MULTIPLE}; 88 private static enum XformType {IDENTITY, TRANSLATE, SCALE, SHEAR, ROTATE}; 89 90 private PaintType paintType = PaintType.LINEAR; 91 private ShapeType shapeType = ShapeType.RECT; 92 private XformType xformType = XformType.IDENTITY; 93 private CycleMethod cycleMethod = CycleMethod.NO_CYCLE; 94 private ColorSpaceType colorSpace = ColorSpaceType.SRGB; 95 private Object antialiasHint = RenderingHints.VALUE_ANTIALIAS_OFF; 96 private Object renderHint = RenderingHints.VALUE_RENDER_SPEED; 97 private AffineTransform transform = new AffineTransform(); 98 99 private int numColors; 100 101 private GradientPanel gradientPanel; 102 private ControlsPanel controlsPanel; 103 MultiGradientTest()104 private MultiGradientTest() { 105 numColors = COLORS.length; 106 107 setLayout(new BorderLayout()); 108 gradientPanel = new GradientPanel(); 109 add(gradientPanel, BorderLayout.CENTER); 110 controlsPanel = new ControlsPanel(); 111 add(controlsPanel, BorderLayout.SOUTH); 112 } 113 114 private class GradientPanel extends JPanel { 115 private int startX, startY, endX, endY; 116 private int ctrX, ctrY, focusX, focusY; 117 private float radius; 118 private Paint paint; 119 GradientPanel()120 private GradientPanel() { 121 startX = 20; 122 startY = 20; 123 endX = 100; 124 endY = 100; 125 ctrX = 100; 126 ctrY = 100; 127 focusX = 100; 128 focusY = 100; 129 radius = 100.0f; 130 131 makeNewPaint(); 132 133 MouseAdapter l = new MyMouseAdapter(); 134 addMouseListener(l); 135 addMouseMotionListener(l); 136 } 137 paintComponent(Graphics g)138 public void paintComponent(Graphics g) { 139 Graphics2D g2d = (Graphics2D)g.create(); 140 141 int w = getWidth(); 142 int h = getHeight(); 143 g2d.setColor(Color.black); 144 g2d.fillRect(0, 0, w, h); 145 146 g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 147 antialiasHint); 148 g2d.setRenderingHint(RenderingHints.KEY_RENDERING, 149 renderHint); 150 151 g2d.transform(transform); 152 g2d.setPaint(paint); 153 154 switch (shapeType) { 155 default: 156 case RECT: 157 g2d.fillRect(0, 0, w, h); 158 break; 159 160 case ELLIPSE: 161 g2d.fillOval(0, 0, w, h); 162 break; 163 164 case MULTIPLE: 165 g2d.fillRect(0, 0, w/2, h/2); 166 g2d.fillOval(w/2, 0, w/2, h/2); 167 g2d.drawOval(0, h/2, w/2, h/2); 168 g2d.drawLine(0, h/2, w/2, h); 169 g2d.drawLine(0, h, w/2, h/2); 170 Polygon p = new Polygon(); 171 p.addPoint(w/2, h); 172 p.addPoint(w, h); 173 p.addPoint(3*w/4, h/2); 174 g2d.fillPolygon(p); 175 break; 176 } 177 178 switch (paintType) { 179 default: 180 case BASIC: 181 case LINEAR: 182 g2d.setColor(Color.white); 183 g2d.fillRect(startX-1, startY-1, 2, 2); 184 g2d.drawString("1", startX, startY + 12); 185 g2d.fillRect(endX-1, endY-1, 2, 2); 186 g2d.drawString("2", endX, endY + 12); 187 break; 188 189 case RADIAL: 190 g2d.setColor(Color.white); 191 g2d.fillRect(ctrX-1, ctrY-1, 2, 2); 192 g2d.drawString("C", ctrX, ctrY + 12); 193 g2d.fillRect(focusX-1, focusY-1, 2, 2); 194 g2d.drawString("F", focusX, focusY + 12); 195 break; 196 } 197 198 g2d.dispose(); 199 } 200 updatePoints(int x, int y)201 private void updatePoints(int x, int y) { 202 Point2D inv = new Point2D.Double(x, y); 203 204 try { 205 inv = transform.inverseTransform(inv, null); 206 } catch (NoninvertibleTransformException e) { 207 e.printStackTrace(); 208 } 209 210 x = (int)inv.getX(); 211 y = (int)inv.getY(); 212 213 switch (paintType) { 214 default: 215 case BASIC: 216 case LINEAR: 217 // pick the closest point to move 218 if (inv.distance(startX, startY) < inv.distance(endX, endY)) { 219 startX = x; 220 startY = y; 221 } else { 222 endX = x; 223 endY = y; 224 } 225 break; 226 227 case RADIAL: 228 // pick the closest point to move 229 if (inv.distance(ctrX, ctrY) < inv.distance(focusX, focusY)) { 230 ctrX = x; 231 ctrY = y; 232 } else { 233 focusX = x; 234 focusY = y; 235 } 236 break; 237 } 238 239 updatePaint(); 240 } 241 makeNewPaint()242 private void makeNewPaint() { 243 Color[] colors = Arrays.copyOf(COLORS, numColors); 244 float[] fractions = new float[colors.length]; 245 for (int i = 0; i < fractions.length; i++) { 246 fractions[i] = ((float)i) / (fractions.length-1); 247 } 248 249 switch (paintType) { 250 case BASIC: 251 boolean cyclic = (cycleMethod != CycleMethod.NO_CYCLE); 252 paint = new GradientPaint(startX, startY, Color.RED, 253 endX, endY, Color.BLUE, cyclic); 254 break; 255 256 default: 257 case LINEAR: 258 paint = 259 new LinearGradientPaint(new Point2D.Float(startX, startY), 260 new Point2D.Float(endX, endY), 261 fractions, colors, 262 cycleMethod, colorSpace, 263 new AffineTransform()); 264 break; 265 266 case RADIAL: 267 paint = 268 new RadialGradientPaint(new Point2D.Float(ctrX, ctrY), 269 radius, 270 new Point2D.Float(focusX, focusY), 271 fractions, colors, 272 cycleMethod, colorSpace, 273 new AffineTransform()); 274 break; 275 } 276 277 switch (xformType) { 278 default: 279 case IDENTITY: 280 transform = new AffineTransform(); 281 break; 282 case TRANSLATE: 283 transform = AffineTransform.getTranslateInstance(2, 2); 284 break; 285 case SCALE: 286 transform = AffineTransform.getScaleInstance(1.2, 1.4); 287 break; 288 case SHEAR: 289 transform = AffineTransform.getShearInstance(0.1, 0.1); 290 break; 291 case ROTATE: 292 transform = AffineTransform.getRotateInstance(Math.PI / 4, 293 getWidth()/2, 294 getHeight()/2); 295 break; 296 } 297 } 298 updatePaint()299 public void updatePaint() { 300 makeNewPaint(); 301 repaint(); 302 } 303 304 private class MyMouseAdapter extends MouseAdapter { 305 @Override mouseClicked(MouseEvent e)306 public void mouseClicked(MouseEvent e) { 307 updatePoints(e.getX(), e.getY()); 308 } 309 310 @Override mouseDragged(MouseEvent e)311 public void mouseDragged(MouseEvent e) { 312 updatePoints(e.getX(), e.getY()); 313 } 314 } 315 getPreferredSize()316 public Dimension getPreferredSize() { 317 return new Dimension(400, 400); 318 } 319 } 320 321 private class ControlsPanel extends JPanel implements ActionListener { 322 private JComboBox cmbPaint, cmbCycle, cmbSpace, cmbShape, cmbXform; 323 private JCheckBox cbAntialias, cbRender; 324 private JSpinner spinNumColors; 325 ControlsPanel()326 private ControlsPanel() { 327 cmbPaint = createCombo(this, paintType); 328 cmbPaint.setSelectedIndex(1); 329 cmbCycle = createCombo(this, cycleMethod); 330 cmbSpace = createCombo(this, colorSpace); 331 cmbShape = createCombo(this, shapeType); 332 cmbXform = createCombo(this, xformType); 333 334 int max = COLORS.length; 335 SpinnerNumberModel model = new SpinnerNumberModel(max, 2, max, 1); 336 spinNumColors = new JSpinner(model); 337 spinNumColors.addChangeListener(new ChangeListener() { 338 public void stateChanged(ChangeEvent e) { 339 numColors = ((Integer)spinNumColors.getValue()).intValue(); 340 gradientPanel.updatePaint(); 341 } 342 }); 343 add(spinNumColors); 344 345 cbAntialias = createCheck(this, "Antialiasing"); 346 cbRender = createCheck(this, "Render Quality"); 347 } 348 createCombo(JPanel panel, Enum e)349 private JComboBox createCombo(JPanel panel, Enum e) { 350 JComboBox cmb = new JComboBox(); 351 cmb.setModel(new EnumComboBoxModel(e.getClass())); 352 cmb.addActionListener(this); 353 panel.add(cmb); 354 return cmb; 355 } 356 createCheck(JPanel panel, String name)357 private JCheckBox createCheck(JPanel panel, String name) { 358 JCheckBox cb = new JCheckBox(name); 359 cb.addActionListener(this); 360 panel.add(cb); 361 return cb; 362 } 363 actionPerformed(ActionEvent e)364 public void actionPerformed(ActionEvent e) { 365 Object source = e.getSource(); 366 367 if (source == cmbPaint) { 368 paintType = (PaintType)cmbPaint.getSelectedItem(); 369 } else if (source == cmbCycle) { 370 cycleMethod = (CycleMethod)cmbCycle.getSelectedItem(); 371 } else if (source == cmbSpace) { 372 colorSpace = (ColorSpaceType)cmbSpace.getSelectedItem(); 373 } else if (source == cmbShape) { 374 shapeType = (ShapeType)cmbShape.getSelectedItem(); 375 } else if (source == cmbXform) { 376 xformType = (XformType)cmbXform.getSelectedItem(); 377 } else if (source == cbAntialias) { 378 antialiasHint = cbAntialias.isSelected() ? 379 RenderingHints.VALUE_ANTIALIAS_ON : 380 RenderingHints.VALUE_ANTIALIAS_OFF; 381 } else if (source == cbRender) { 382 renderHint = cbRender.isSelected() ? 383 RenderingHints.VALUE_RENDER_QUALITY : 384 RenderingHints.VALUE_RENDER_SPEED; 385 } 386 387 gradientPanel.updatePaint(); 388 } 389 } 390 391 private static class EnumComboBoxModel<E extends Enum<E>> 392 extends AbstractListModel 393 implements ComboBoxModel 394 { 395 private E selected = null; 396 private List<E> list; 397 EnumComboBoxModel(Class<E> en)398 public EnumComboBoxModel(Class<E> en) { 399 EnumSet<E> ens = EnumSet.allOf(en); 400 list = new ArrayList<E>(ens); 401 selected = list.get(0); 402 } 403 getSize()404 public int getSize() { 405 return list.size(); 406 } 407 getElementAt(int index)408 public E getElementAt(int index) { 409 return list.get(index); 410 } 411 setSelectedItem(Object anItem)412 public void setSelectedItem(Object anItem) { 413 selected = (E)anItem; 414 this.fireContentsChanged(this, 0, getSize()); 415 } 416 getSelectedItem()417 public E getSelectedItem() { 418 return selected; 419 } 420 } 421 main(String[] args)422 public static void main(String[] args) { 423 final JFrame frame = new JFrame("Multistop Gradient Demo"); 424 frame.addWindowListener(new WindowAdapter() { 425 public void windowClosing(WindowEvent e) { 426 frame.dispose(); 427 } 428 }); 429 frame.add(new MultiGradientTest()); 430 frame.pack(); 431 frame.setLocationRelativeTo(null); 432 frame.setVisible(true); 433 } 434 } 435