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