001 /* 002 * $Id: JXGradientChooser.java 3360 2009-06-14 20:29:45Z kschaefe $ 003 * 004 * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, 005 * Santa Clara, California 95054, U.S.A. All rights reserved. 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * You should have received a copy of the GNU Lesser General Public 018 * License along with this library; if not, write to the Free Software 019 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 020 */ 021 022 package org.jdesktop.swingx; 023 024 import java.awt.BorderLayout; 025 import java.awt.Color; 026 import java.awt.Component; 027 import java.awt.Dimension; 028 import java.awt.GridBagConstraints; 029 import java.awt.GridBagLayout; 030 import java.awt.GridLayout; 031 import java.awt.MultipleGradientPaint; 032 import java.awt.RadialGradientPaint; 033 import java.awt.event.ActionEvent; 034 import java.awt.event.ActionListener; 035 import java.awt.event.ItemEvent; 036 import java.awt.event.ItemListener; 037 import java.awt.event.MouseEvent; 038 import java.beans.PropertyChangeEvent; 039 import java.beans.PropertyChangeListener; 040 import java.util.logging.Logger; 041 042 import javax.swing.ActionMap; 043 import javax.swing.ButtonGroup; 044 import javax.swing.DefaultComboBoxModel; 045 import javax.swing.JButton; 046 import javax.swing.JCheckBox; 047 import javax.swing.JComboBox; 048 import javax.swing.JDialog; 049 import javax.swing.JFrame; 050 import javax.swing.JLabel; 051 import javax.swing.JPanel; 052 import javax.swing.JRadioButton; 053 import javax.swing.JSlider; 054 import javax.swing.JSpinner; 055 import javax.swing.JTextField; 056 import javax.swing.SpinnerNumberModel; 057 import javax.swing.SwingUtilities; 058 import javax.swing.event.ChangeEvent; 059 import javax.swing.event.ChangeListener; 060 061 import org.jdesktop.swingx.action.AbstractActionExt; 062 import org.jdesktop.swingx.color.ColorUtil; 063 import org.jdesktop.swingx.color.GradientPreviewPanel; 064 import org.jdesktop.swingx.color.GradientThumbRenderer; 065 import org.jdesktop.swingx.color.GradientTrackRenderer; 066 import org.jdesktop.swingx.multislider.Thumb; 067 import org.jdesktop.swingx.multislider.ThumbListener; 068 069 /** 070 * <p>A specialized JXPanel that allows the user to construct and choose a Gradient. 071 * The returned values will be one of: LinearGradientPaint or RadialGradientPaint.</p> 072 * 073 * <p><b>Dependency</b>: Because this class relies on LinearGradientPaint and 074 * RadialGradientPaint, it requires the optional MultipleGradientPaint.jar</p> 075 * 076 * @author joshy 077 */ 078 public class JXGradientChooser extends JXPanel { 079 private enum GradientStyle { Linear, Radial } 080 081 /** 082 * The multi-thumb slider to use for the gradient stops 083 */ 084 private JXMultiThumbSlider<Color> slider; 085 private JButton deleteThumbButton; 086 private JButton addThumbButton; 087 088 private JTextField colorField; 089 private JXColorSelectionButton changeColorButton; 090 private JSpinner colorLocationSpinner; 091 private JSpinner alphaSpinner; 092 private JSlider alphaSlider; 093 094 private JComboBox styleCombo; 095 private GradientPreviewPanel gradientPreview; 096 097 private JRadioButton noCycleRadio; 098 private JRadioButton reflectedRadio; 099 private JRadioButton repeatedRadio; 100 private JCheckBox reversedCheck; 101 private MultipleGradientPaint gradient; 102 103 /** 104 * Creates new JXGradientChooser 105 */ 106 public JXGradientChooser() { 107 initComponents2(); 108 } 109 110 /** 111 * Returns the MultipleGradientPaint currently choosen by the user. 112 * @return the currently selected gradient 113 */ 114 public MultipleGradientPaint getGradient() { 115 return gradient; 116 } 117 118 private boolean thumbsMoving = false; 119 private Logger log = Logger.getLogger(JXGradientChooser.class.getName()); 120 121 /** 122 * Sets the gradient within this panel to the new gradient. This will delete 123 * the old gradient all of it's settings, resetting the slider, gradient 124 * type selection, and other gradient configuration options to match the 125 * new gradient. 126 * 127 * @param mgrad The desired gradient. 128 */ 129 public void setGradient(MultipleGradientPaint mgrad) { 130 if(gradient == mgrad) { 131 return; 132 } 133 float[] fracts = mgrad.getFractions(); 134 Color[] colors = mgrad.getColors(); 135 136 if(!thumbsMoving) { 137 // update the slider properly 138 if(slider.getModel().getThumbCount() != 139 mgrad.getColors().length) { 140 // removing all thumbs; 141 while(slider.getModel().getThumbCount() > 0) { 142 slider.getModel().removeThumb(0); 143 } 144 // add them back 145 for(int i=0; i<fracts.length; i++) { 146 slider.getModel().addThumb(fracts[i],colors[i]); 147 } 148 } else { 149 for(int i=0; i<fracts.length; i++) { 150 slider.getModel().getThumbAt(i).setObject(colors[i]); 151 slider.getModel().getThumbAt(i).setPosition(fracts[i]); 152 } 153 } 154 } else { 155 log.fine("not updating because it's moving"); 156 } 157 if(mgrad instanceof RadialGradientPaint) { 158 if(styleCombo.getSelectedItem() != GradientStyle.Radial) { 159 styleCombo.setSelectedItem(GradientStyle.Radial); 160 } 161 } else { 162 if(styleCombo.getSelectedItem() != GradientStyle.Linear) { 163 styleCombo.setSelectedItem(GradientStyle.Linear); 164 } 165 } 166 167 if(mgrad.getCycleMethod() == MultipleGradientPaint.CycleMethod.REFLECT) { 168 this.reflectedRadio.setSelected(true); 169 gradientPreview.setReflected(true); 170 } 171 if(mgrad.getCycleMethod() == MultipleGradientPaint.CycleMethod.REPEAT) { 172 this.repeatedRadio.setSelected(true); 173 gradientPreview.setRepeated(true); 174 } 175 gradientPreview.setGradient(mgrad); 176 //reflectedRadio.setSelected() 177 MultipleGradientPaint old = this.getGradient(); 178 gradient = mgrad; 179 firePropertyChange("gradient",old,getGradient()); 180 repaint(); 181 } 182 183 private void recalcGradientFromStops() { 184 setGradient(gradientPreview.getGradient()); 185 } 186 187 private void updateFromStop(Thumb<Color> thumb) { 188 if(thumb == null) { 189 updateFromStop(-1,-1,Color.black); 190 } else { 191 updateFromStop(1,thumb.getPosition(),thumb.getObject()); 192 } 193 } 194 195 private void updateFromStop(int thumb, float position, Color color) { 196 log.fine("updating: " + thumb + " " + position + " " + color); 197 if(thumb == -1) { 198 colorLocationSpinner.setEnabled(false); 199 alphaSpinner.setEnabled(false); 200 alphaSlider.setEnabled(false); 201 colorField.setEnabled(false); 202 changeColorButton.setEnabled(false); 203 changeColorButton.setBackground(Color.black); 204 deleteThumbButton.setEnabled(false); 205 } else { 206 colorLocationSpinner.setEnabled(true); 207 alphaSpinner.setEnabled(true); 208 alphaSlider.setEnabled(true); 209 colorField.setEnabled(true); 210 changeColorButton.setEnabled(true); 211 colorLocationSpinner.setValue((int)(100*position)); 212 colorField.setText(Integer.toHexString(color.getRGB()).substring(2)); 213 alphaSpinner.setValue(color.getAlpha()*100/255); 214 alphaSlider.setValue(color.getAlpha()*100/255); 215 changeColorButton.setBackground(color); 216 deleteThumbButton.setEnabled(true); 217 } 218 updateDeleteButtons(); 219 recalcGradientFromStops(); 220 } 221 222 private void updateDeleteButtons() { 223 if(slider.getModel().getThumbCount() <= 2) { 224 deleteThumbButton.setEnabled(false); 225 } 226 } 227 228 private void updateGradientProperty() { 229 firePropertyChange("gradient",null,getGradient()); 230 gradientPreview.repaint(); 231 } 232 233 234 /** This method is called from within the constructor to 235 * initialize the form. 236 */ 237 238 private JPanel topPanel, previewPanel; 239 private void initComponents() { 240 // declarations for anonymous components 241 JPanel jPanel1, jPanel2, jPanel3, jPanel4; 242 JLabel jLabel1, jLabel5, jLabel2, jLabel6, jLabel4, jLabel7, jLabel8, jLabel9; 243 ButtonGroup typeGroup; 244 // pre-init stuff 245 slider = new JXMultiThumbSlider<Color>(); 246 gradientPreview = new GradientPreviewPanel(); 247 gradientPreview.setMultiThumbModel(slider.getModel()); 248 249 java.awt.GridBagConstraints gridBagConstraints; 250 251 typeGroup = new javax.swing.ButtonGroup(); 252 jPanel1 = new javax.swing.JPanel(); 253 topPanel = new javax.swing.JPanel(); 254 jPanel2 = new javax.swing.JPanel(); 255 jLabel1 = new javax.swing.JLabel(); 256 jLabel5 = new javax.swing.JLabel(); 257 colorField = new javax.swing.JTextField(); 258 jLabel2 = new javax.swing.JLabel(); 259 jLabel6 = new javax.swing.JLabel(); 260 colorLocationSpinner = new javax.swing.JSpinner(); 261 jLabel4 = new javax.swing.JLabel(); 262 jLabel7 = new javax.swing.JLabel(); 263 alphaSpinner = new javax.swing.JSpinner(); 264 changeColorButton = new JXColorSelectionButton(); 265 alphaSlider = new javax.swing.JSlider(); 266 //slider = new javax.swing.JSlider(); 267 jPanel4 = new javax.swing.JPanel(); 268 addThumbButton = new javax.swing.JButton(); 269 deleteThumbButton = new javax.swing.JButton(); 270 previewPanel = new javax.swing.JPanel(); 271 jPanel3 = new javax.swing.JPanel(); 272 jLabel8 = new javax.swing.JLabel(); 273 styleCombo = new javax.swing.JComboBox(); 274 jLabel9 = new javax.swing.JLabel(); 275 noCycleRadio = new javax.swing.JRadioButton(); 276 reflectedRadio = new javax.swing.JRadioButton(); 277 repeatedRadio = new javax.swing.JRadioButton(); 278 reversedCheck = new javax.swing.JCheckBox(); 279 //gradientPreview = new javax.swing.JPanel(); 280 281 //setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); 282 jPanel1.setLayout(new java.awt.GridBagLayout()); 283 284 topPanel.setLayout(new java.awt.GridBagLayout()); 285 286 topPanel.setBorder(javax.swing.BorderFactory.createTitledBorder("Gradient")); 287 jPanel2.setLayout(new java.awt.GridBagLayout()); 288 289 jLabel1.setText("Color:"); 290 gridBagConstraints = new java.awt.GridBagConstraints(); 291 gridBagConstraints.gridx = 0; 292 gridBagConstraints.gridy = 0; 293 gridBagConstraints.ipadx = 2; 294 gridBagConstraints.ipady = 2; 295 gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST; 296 gridBagConstraints.insets = new java.awt.Insets(4, 4, 4, 4); 297 jPanel2.add(jLabel1, gridBagConstraints); 298 299 jLabel5.setText("#"); 300 gridBagConstraints = new java.awt.GridBagConstraints(); 301 gridBagConstraints.gridx = 1; 302 gridBagConstraints.gridy = 0; 303 gridBagConstraints.insets = new java.awt.Insets(4, 0, 4, 4); 304 jPanel2.add(jLabel5, gridBagConstraints); 305 306 colorField.setColumns(6); 307 colorField.setEnabled(false); 308 colorField.setPreferredSize(null); 309 gridBagConstraints = new java.awt.GridBagConstraints(); 310 gridBagConstraints.gridy = 0; 311 gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; 312 jPanel2.add(colorField, gridBagConstraints); 313 314 jLabel2.setText("Location:"); 315 gridBagConstraints = new java.awt.GridBagConstraints(); 316 gridBagConstraints.gridy = 1; 317 gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST; 318 gridBagConstraints.insets = new java.awt.Insets(4, 4, 4, 4); 319 jPanel2.add(jLabel2, gridBagConstraints); 320 321 jLabel6.setText("%"); 322 gridBagConstraints = new java.awt.GridBagConstraints(); 323 gridBagConstraints.gridy = 1; 324 jPanel2.add(jLabel6, gridBagConstraints); 325 326 colorLocationSpinner.setEnabled(false); 327 colorLocationSpinner.setPreferredSize(null); 328 gridBagConstraints = new java.awt.GridBagConstraints(); 329 gridBagConstraints.gridy = 1; 330 gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; 331 jPanel2.add(colorLocationSpinner, gridBagConstraints); 332 333 jLabel4.setText("Opacity:"); 334 gridBagConstraints = new java.awt.GridBagConstraints(); 335 gridBagConstraints.gridy = 2; 336 gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST; 337 gridBagConstraints.insets = new java.awt.Insets(4, 4, 4, 4); 338 jPanel2.add(jLabel4, gridBagConstraints); 339 340 jLabel7.setText("%"); 341 gridBagConstraints = new java.awt.GridBagConstraints(); 342 gridBagConstraints.gridy = 2; 343 jPanel2.add(jLabel7, gridBagConstraints); 344 345 alphaSpinner.setEnabled(false); 346 alphaSpinner.setPreferredSize(null); 347 gridBagConstraints = new java.awt.GridBagConstraints(); 348 gridBagConstraints.gridy = 2; 349 gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; 350 jPanel2.add(alphaSpinner, gridBagConstraints); 351 352 changeColorButton.setText("00"); 353 changeColorButton.setEnabled(false); 354 gridBagConstraints = new java.awt.GridBagConstraints(); 355 gridBagConstraints.fill = java.awt.GridBagConstraints.NONE; 356 gridBagConstraints.weightx = 1.0; 357 gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; 358 gridBagConstraints.insets = new java.awt.Insets(0, 4, 0, 0); 359 jPanel2.add(changeColorButton, gridBagConstraints); 360 361 alphaSlider.setEnabled(false); 362 alphaSlider.setPreferredSize(new java.awt.Dimension(20, 25)); 363 gridBagConstraints = new java.awt.GridBagConstraints(); 364 gridBagConstraints.gridy = 2; 365 gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; 366 gridBagConstraints.weightx = 1.0; 367 jPanel2.add(alphaSlider, gridBagConstraints); 368 369 gridBagConstraints = new java.awt.GridBagConstraints(); 370 gridBagConstraints.gridx = 0; 371 gridBagConstraints.gridy = 2; 372 gridBagConstraints.gridwidth = 2; 373 gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; 374 gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; 375 gridBagConstraints.weightx = 1.0; 376 gridBagConstraints.weighty = 1.0; 377 gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5); 378 topPanel.add(jPanel2, gridBagConstraints); 379 380 gridBagConstraints = new java.awt.GridBagConstraints(); 381 gridBagConstraints.gridy = 0; 382 gridBagConstraints.gridwidth = 2; 383 gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; 384 topPanel.add(slider, gridBagConstraints); 385 386 jPanel4.setLayout(new java.awt.GridLayout(1, 0, 2, 0)); 387 388 addThumbButton.setText("Add"); 389 jPanel4.add(addThumbButton); 390 391 deleteThumbButton.setText("Delete"); 392 jPanel4.add(deleteThumbButton); 393 394 gridBagConstraints = new java.awt.GridBagConstraints(); 395 gridBagConstraints.gridy = 1; 396 gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST; 397 gridBagConstraints.weightx = 1.0; 398 gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5); 399 topPanel.add(jPanel4, gridBagConstraints); 400 401 gridBagConstraints = new java.awt.GridBagConstraints(); 402 gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; 403 gridBagConstraints.weightx = 1.0; 404 jPanel1.add(topPanel, gridBagConstraints); 405 406 previewPanel.setLayout(new java.awt.GridBagLayout()); 407 408 previewPanel.setBorder(javax.swing.BorderFactory.createTitledBorder("Preview")); 409 jPanel3.setLayout(new java.awt.GridBagLayout()); 410 411 jLabel8.setText("Style:"); 412 gridBagConstraints = new java.awt.GridBagConstraints(); 413 gridBagConstraints.gridy = 0; 414 gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST; 415 gridBagConstraints.insets = new java.awt.Insets(4, 4, 4, 4); 416 jPanel3.add(jLabel8, gridBagConstraints); 417 418 styleCombo.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Linear", "Radial" })); 419 gridBagConstraints = new java.awt.GridBagConstraints(); 420 gridBagConstraints.gridy = 0; 421 gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; 422 gridBagConstraints.insets = new java.awt.Insets(4, 4, 4, 4); 423 jPanel3.add(styleCombo, gridBagConstraints); 424 425 jLabel9.setText("Type:"); 426 gridBagConstraints = new java.awt.GridBagConstraints(); 427 gridBagConstraints.gridy = 1; 428 gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST; 429 gridBagConstraints.insets = new java.awt.Insets(4, 4, 4, 4); 430 jPanel3.add(jLabel9, gridBagConstraints); 431 432 typeGroup.add(noCycleRadio); 433 noCycleRadio.setSelected(true); 434 noCycleRadio.setText("None"); 435 noCycleRadio.setBorder(javax.swing.BorderFactory.createEmptyBorder(0, 0, 0, 0)); 436 noCycleRadio.setMargin(new java.awt.Insets(0, 0, 0, 0)); 437 gridBagConstraints = new java.awt.GridBagConstraints(); 438 gridBagConstraints.gridy = 1; 439 gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; 440 gridBagConstraints.insets = new java.awt.Insets(4, 4, 4, 4); 441 jPanel3.add(noCycleRadio, gridBagConstraints); 442 443 typeGroup.add(reflectedRadio); 444 reflectedRadio.setText("Reflect"); 445 reflectedRadio.setBorder(javax.swing.BorderFactory.createEmptyBorder(0, 0, 0, 0)); 446 reflectedRadio.setMargin(new java.awt.Insets(0, 0, 0, 0)); 447 gridBagConstraints = new java.awt.GridBagConstraints(); 448 gridBagConstraints.gridx = 1; 449 gridBagConstraints.gridy = 2; 450 gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; 451 gridBagConstraints.insets = new java.awt.Insets(4, 4, 4, 4); 452 jPanel3.add(reflectedRadio, gridBagConstraints); 453 454 typeGroup.add(repeatedRadio); 455 repeatedRadio.setText("Repeat"); 456 repeatedRadio.setBorder(javax.swing.BorderFactory.createEmptyBorder(0, 0, 0, 0)); 457 repeatedRadio.setMargin(new java.awt.Insets(0, 0, 0, 0)); 458 gridBagConstraints = new java.awt.GridBagConstraints(); 459 gridBagConstraints.gridx = 1; 460 gridBagConstraints.gridy = 3; 461 gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; 462 gridBagConstraints.insets = new java.awt.Insets(4, 4, 4, 4); 463 jPanel3.add(repeatedRadio, gridBagConstraints); 464 465 reversedCheck.setText("Reverse"); 466 reversedCheck.setBorder(javax.swing.BorderFactory.createEmptyBorder(0, 0, 0, 0)); 467 reversedCheck.setMargin(new java.awt.Insets(0, 0, 0, 0)); 468 gridBagConstraints = new java.awt.GridBagConstraints(); 469 gridBagConstraints.gridx = 1; 470 gridBagConstraints.gridy = 4; 471 gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; 472 gridBagConstraints.insets = new java.awt.Insets(4, 4, 4, 4); 473 jPanel3.add(reversedCheck, gridBagConstraints); 474 475 gridBagConstraints = new java.awt.GridBagConstraints(); 476 gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; 477 previewPanel.add(jPanel3, gridBagConstraints); 478 479 gradientPreview.setBorder(javax.swing.BorderFactory.createEtchedBorder()); 480 gradientPreview.setPreferredSize(new java.awt.Dimension(130, 130)); 481 gridBagConstraints = new java.awt.GridBagConstraints(); 482 gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; 483 gridBagConstraints.weightx = 10.0; 484 gridBagConstraints.weighty = 10.0; 485 previewPanel.add(gradientPreview, gridBagConstraints); 486 487 gridBagConstraints = new java.awt.GridBagConstraints(); 488 gridBagConstraints.gridy = 1; 489 gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; 490 gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTH; 491 gridBagConstraints.weightx = 1.0; 492 gridBagConstraints.weighty = 1.0; 493 jPanel1.add(previewPanel, gridBagConstraints); 494 495 }// </editor-fold> 496 private void initComponents2() { 497 this.initComponents(); 498 setLayout(new BorderLayout()); 499 add(topPanel, BorderLayout.NORTH); 500 add(previewPanel, BorderLayout.CENTER); 501 502 503 // do event handling stuff 504 //create the actions and load them in the action map 505 AddThumbAction addThumbAction = new AddThumbAction(); 506 DeleteThumbAction deleteThumbAction = new DeleteThumbAction(); 507 deleteThumbAction.setEnabled(false); //disabled to begin with 508 //TODO Add to the action map with proper keys, etc 509 ActionMap actions = getActionMap(); 510 actions.put("add-thumb", addThumbAction); 511 actions.put("delete-thumb", deleteThumbAction); 512 //actions.put("change-color", changeColorAction); 513 addThumbButton.setAction(addThumbAction); 514 deleteThumbButton.setAction(deleteThumbAction); 515 changeColorButton.addPropertyChangeListener("background", new PropertyChangeListener() { 516 public void propertyChange(PropertyChangeEvent evt) { 517 selectColorForThumb(); 518 updateGradientProperty(); 519 } 520 }); 521 colorLocationSpinner.addChangeListener(new ChangeLocationListener()); 522 ChangeAlphaListener changeAlphaListener = new ChangeAlphaListener(); 523 alphaSpinner.addChangeListener(changeAlphaListener); 524 alphaSlider.addChangeListener(changeAlphaListener); 525 RepaintOnEventListener repaintListener = new RepaintOnEventListener(); 526 styleCombo.addItemListener(repaintListener); 527 styleCombo.setModel(new DefaultComboBoxModel(GradientStyle.values())); 528 noCycleRadio.addActionListener(repaintListener); 529 reflectedRadio.addActionListener(repaintListener); 530 repeatedRadio.addActionListener(repaintListener); 531 reversedCheck.addActionListener(repaintListener); 532 gradientPreview.picker = this; //wow, nasty 533 534 535 ///To still refactor below:: 536 SpinnerNumberModel alpha_model = new SpinnerNumberModel(100,0,100,1); 537 alphaSpinner.setModel(alpha_model); 538 SpinnerNumberModel location_model = new SpinnerNumberModel(100,0,100,1); 539 colorLocationSpinner.setModel(location_model); 540 541 slider.setOpaque(false); 542 slider.setPreferredSize(new Dimension(100,35)); 543 slider.getModel().setMinimumValue(0f); 544 slider.getModel().setMaximumValue(1.0f); 545 546 slider.getModel().addThumb(0,Color.black); 547 slider.getModel().addThumb(0.5f,Color.red); 548 slider.getModel().addThumb(1.0f,Color.white); 549 550 slider.setThumbRenderer(new GradientThumbRenderer()); 551 slider.setTrackRenderer(new GradientTrackRenderer()); 552 slider.addMultiThumbListener(new StopListener()); 553 554 // called when the gradient property of the preview pane changes 555 gradientPreview.addPropertyChangeListener("gradient", new PropertyChangeListener() { 556 public void propertyChange(PropertyChangeEvent propertyChangeEvent) { 557 recalcGradientFromStops(); 558 } 559 }); 560 561 recalcGradientFromStops(); 562 563 } 564 565 // called whenever the color location spinner is changed 566 private final class ChangeLocationListener implements ChangeListener { 567 public void stateChanged(ChangeEvent evt) { 568 if(slider.getSelectedIndex() >= 0) { 569 Thumb<Color> thumb = slider.getModel().getThumbAt(slider.getSelectedIndex()); 570 thumb.setPosition((Integer)colorLocationSpinner.getValue()/100f); 571 updateFromStop(thumb); 572 updateGradientProperty(); 573 } 574 } 575 } 576 577 // called when the alpha slider moves 578 private final class ChangeAlphaListener implements ChangeListener { 579 public void stateChanged(ChangeEvent changeEvent) { 580 if(slider.getSelectedIndex() >= 0 && !thumbsMoving) { 581 // get the selected thumb 582 Thumb<Color> thumb = slider.getModel().getThumbAt(slider.getSelectedIndex()); 583 // get the new alpha value 584 int alpha = changeEvent.getSource() == alphaSpinner ? 585 (Integer)alphaSpinner.getValue() 586 : alphaSlider.getValue(); 587 588 589 // calc new color and set it on thumb 590 Color col = thumb.getObject(); 591 col = ColorUtil.setAlpha(col, alpha*255/100); 592 thumb.setObject(col); 593 594 // set the new alpha value on the other alpha control 595 if (changeEvent.getSource() == alphaSpinner) { 596 alphaSlider.setValue(alpha); 597 } else { 598 alphaSpinner.setValue(alpha); 599 } 600 601 recalcGradientFromStops(); 602 } 603 } 604 } 605 606 607 private final class AddThumbAction extends AbstractActionExt { 608 public AddThumbAction() { 609 super("Add"); 610 } 611 612 public void actionPerformed(ActionEvent actionEvent) { 613 float pos = 0.2f; 614 Color color = Color.black; 615 int num = slider.getModel().addThumb(pos,color); 616 log.fine("new number = " + num); 617 /* 618 for (int i = 0; i < slider.getModel().getThumbCount(); i++) { 619 float pos2 = slider.getModel().getThumbAt(i).getPosition(); 620 if (pos2 < pos) { 621 continue; 622 } 623 slider.getModel().insertThumb(pos, color, i); 624 updateFromStop(i,pos,color); 625 break; 626 } 627 */ 628 629 } 630 } 631 632 private final class DeleteThumbAction extends AbstractActionExt { 633 public DeleteThumbAction() { 634 super("Delete"); 635 } 636 637 public void actionPerformed(ActionEvent actionEvent) { 638 int index = slider.getSelectedIndex(); 639 if (index >= 0) { 640 slider.getModel().removeThumb(index); 641 updateFromStop(-1,-1,null); 642 } 643 } 644 } 645 646 private class StopListener implements ThumbListener { 647 648 public StopListener() { 649 super(); 650 } 651 652 public void thumbMoved(int thumb, float pos) { 653 log.fine("moved: " + thumb + " " + pos); 654 Color color = slider.getModel().getThumbAt(thumb).getObject(); 655 thumbsMoving = true; 656 updateFromStop(thumb,pos,color); 657 updateDeleteButtons(); 658 thumbsMoving = false; 659 660 } 661 662 public void thumbSelected(int thumb) { 663 664 if(thumb == -1) { 665 updateFromStop(-1,-1,Color.black); 666 return; 667 } 668 thumbsMoving = true; 669 float pos = slider.getModel().getThumbAt(thumb).getPosition(); 670 Color color = slider.getModel().getThumbAt(thumb).getObject(); 671 log.fine("selected = " + thumb + " " + pos + " " + color); 672 updateFromStop(thumb,pos,color); 673 updateDeleteButtons(); 674 slider.repaint(); 675 thumbsMoving = false; 676 677 } 678 679 public void mousePressed(MouseEvent e) { 680 if(e.getClickCount() > 1) { 681 selectColorForThumb(); 682 } 683 } 684 } 685 686 private final class RepaintOnEventListener implements ActionListener, ItemListener { 687 public void actionPerformed(ActionEvent e) { 688 gradientPreview.setReflected(reflectedRadio.isSelected()); 689 gradientPreview.setReversed(reversedCheck.isSelected()); 690 gradientPreview.setRepeated(repeatedRadio.isSelected()); 691 //updateGradientProperty(); 692 recalcGradientFromStops(); 693 gradientPreview.repaint(); 694 } 695 696 public void itemStateChanged(ItemEvent e) { 697 if(styleCombo.getSelectedItem() == GradientStyle.Radial) { 698 gradientPreview.setRadial(true); 699 } else { 700 gradientPreview.setRadial(false); 701 } 702 recalcGradientFromStops(); 703 } 704 } 705 706 private void selectColorForThumb() { 707 int index = slider.getSelectedIndex(); 708 if (index >= 0) { 709 Color color = changeColorButton.getBackground(); 710 slider.getModel().getThumbAt(index).setObject(color); 711 updateFromStop(index, slider.getModel().getThumbAt(index).getPosition(), color); 712 } 713 } 714 715 /** 716 * This static utility method <b>cannot</b> be called from the 717 * ETD, or your application will lock up. Call it from a separate 718 * thread or create a new Thread with a Runnable. 719 * @param comp The component to use when finding a top level window or frame for 720 * the dialog. 721 * @param title The desired title of the gradient chooser dialog. 722 * @param mgrad The gradient to initialize the chooser too. 723 * @return The gradient the user chose. 724 */ 725 public static MultipleGradientPaint showDialog(Component comp, String title, MultipleGradientPaint mgrad) { 726 Component root = SwingUtilities.getRoot(comp); 727 final JDialog dialog = new JDialog((JFrame)root,title,true); 728 final JXGradientChooser picker = new JXGradientChooser(); 729 if(mgrad != null) { 730 picker.setGradient(mgrad); 731 } 732 dialog.add(picker); 733 734 735 JPanel panel = new JPanel(); 736 JButton cancel = new JButton("Cancel"); 737 cancel.addActionListener(new ActionListener() { 738 public void actionPerformed(ActionEvent actionEvent) { 739 dialog.setVisible(false); 740 } 741 }); 742 JButton okay = new JButton("Ok"); 743 okay.addActionListener(new ActionListener() { 744 public void actionPerformed(ActionEvent actionEvent) { 745 dialog.setVisible(false); 746 } 747 }); 748 okay.setDefaultCapable(true); 749 750 751 GridLayout gl = new GridLayout(); 752 gl.setHgap(2); 753 panel.setLayout(gl); 754 panel.add(cancel); 755 panel.add(okay); 756 757 JPanel p2 = new JPanel(); 758 p2.setLayout(new GridBagLayout()); 759 GridBagConstraints gbc = new GridBagConstraints(); 760 gbc.anchor = GridBagConstraints.EAST; 761 gbc.weightx = 1.0; 762 p2.add(panel,gbc); 763 dialog.add(p2,"South"); 764 765 dialog.getRootPane().setDefaultButton(okay); 766 dialog.pack(); 767 dialog.setResizable(false); 768 dialog.setVisible(true); 769 770 return picker.getGradient(); 771 } 772 773 /** 774 * Creates a string representation of a {@code MultipleGradientPaint}. This 775 * string is used for debugging purposes. Its contents cannot be guaranteed 776 * between releases. 777 * 778 * @param paint 779 * the {@code paint} to create a string for 780 * @return a string representing the supplied {@code paint} 781 */ 782 public static String toString(MultipleGradientPaint paint) { 783 StringBuffer buffer = new StringBuffer(); 784 buffer.append(paint.getClass().getName()); 785 Color[] colors = paint.getColors(); 786 float[] values = paint.getFractions(); 787 buffer.append("["); 788 for(int i=0; i<colors.length; i++) { 789 buffer.append("#").append(Integer.toHexString(colors[i].getRGB())); 790 buffer.append(":"); 791 buffer.append(values[i]); 792 buffer.append(", "); 793 } 794 buffer.append("]"); 795 return buffer.toString(); 796 } 797 798 } 799 800