001package jmri.jmrit.display.palette; 002 003import java.awt.Color; 004import java.awt.FlowLayout; 005import java.awt.Frame; 006import java.awt.event.ActionEvent; 007import java.awt.event.ActionListener; 008import java.awt.event.KeyEvent; 009import java.awt.event.KeyListener; 010import javax.swing.Box; 011import javax.swing.BoxLayout; 012import javax.swing.JButton; 013import javax.swing.JColorChooser; 014import javax.swing.JComponent; 015import javax.swing.JDialog; 016import javax.swing.JPanel; 017import javax.swing.JTextField; 018import javax.swing.SpinnerNumberModel; 019import javax.swing.event.ChangeEvent; 020import javax.swing.event.ChangeListener; 021import jmri.InstanceManager; 022import jmri.jmrit.display.Positionable; 023import jmri.jmrit.display.PositionableLabel; 024import jmri.jmrit.display.PositionablePopupUtil; 025import jmri.jmrit.display.palette.TextItemPanel.AJSpinner; 026import jmri.util.swing.JmriColorChooser; 027 028/** 029 * A dialog to color a Component in a Window. The ColorChooser 030 * interactively modifies the color of the component on the window 031 * until the user either cancels or decides to keep the changes. 032 * 033 * @author Pete Cressman Copyright (C) 2018 034 * @since 4.13.1 035 */ 036public class ColorDialog extends JDialog implements ChangeListener { 037 038 public static final int STRUT = 6; 039 040 public static final int ONLY = 0; 041 public static final int BORDER = 1; // (= 1) 042 public static final int MARGIN = 2; // (= 2) 043 public static final int FWIDTH = 3; // (= 3) 044 public static final int FHEIGHT = 4; // (= 4) 045 public static final int FONT = 5; 046 public static final int TEXT = 6; 047 048 JColorChooser _chooser; 049 JComponent _target; 050 int _type; 051 Color _saveColor; 052 boolean _saveOpaque; 053 String _saveText; 054 PositionablePopupUtil _util; 055 PositionablePopupUtil _saveUtil; 056 ActionListener _colorAction; 057 JPanel _preview; 058 059 /** 060 * 061 * @param client Window holding the component 062 * @param t target whose color may be changed 063 * @param type which attribute is being changed 064 * @param ca callback to tell client the component's color was changed. 065 * May be null if client doesen't care. 066 */ 067 public ColorDialog(Frame client, JComponent t, int type, ActionListener ca) { 068 super(client, true); 069 _target = t; 070 _type = type; 071 if (t instanceof Positionable) { 072 Positionable pos = (Positionable)t; 073 _util = pos.getPopupUtility(); 074 if (_util != null) { 075 _util.setSuppressRecentColor(true); 076 Positionable p = pos.deepClone(); 077 _saveUtil = p.getPopupUtility(); 078 p.remove(); 079 } 080 } else { 081 _util = null; 082 } 083 _saveOpaque = t.isOpaque(); 084 _colorAction = ca; 085 086 JPanel panel = new JPanel(); 087 panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); 088 panel.add(Box.createVerticalGlue()); 089 090 String title; 091 switch (type) { 092 case ONLY: 093 title = "PanelColor"; 094 _saveColor = t.getBackground(); 095 break; 096 case BORDER: 097 title = "SetBorderSizeColor"; 098 _saveColor = _util.getBorderColor(); 099 SpinnerNumberModel model = new SpinnerNumberModel(_util.getBorderSize(), 0, 100, 1); 100 JPanel p = makePanel(TextItemPanel.makeSpinPanel("borderSize", new AJSpinner(model, BORDER), this)); 101 panel.add(p); 102 break; 103 case MARGIN: 104 title = "SetMarginSizeColor"; 105 _saveColor = _util.getBackground(); 106 model = new SpinnerNumberModel(_util.getMargin(), 0, 100, 1); 107 p = makePanel(TextItemPanel.makeSpinPanel("marginSize", new AJSpinner(model, MARGIN), this)); 108 panel.add(p); 109 break; 110 case FONT: 111 title = "SetFontSizeColor"; 112 _saveColor = _util.getForeground(); 113 ActionListener fontAction = ((ActionEvent event) -> { 114 update(); // callback 115 }); 116 FontPanel fontPanel = new FontPanel(_util, fontAction); 117 panel.add(fontPanel); 118 fontPanel.setFontSelections(); 119 break; 120 case TEXT: 121 title = "SetTextSizeColor"; 122 _saveColor = _util.getBackground(); 123 _saveText = ((PositionableLabel)t).getUnRotatedText(); 124 panel.add(makePanel(makeTextSpinnerPanel())); 125 panel.add(Box.createVerticalGlue()); 126 panel.add(makePanel(makeTextPanel())); 127 break; 128 default: 129 title = "ColorChooser"; 130 _saveColor = t.getBackground(); 131 } 132 panel.add(Box.createVerticalStrut(STRUT)); 133 setTitle(Bundle.getMessage(title)); 134 135 _chooser = JmriColorChooser.extendColorChooser(new JColorChooser(_saveColor)); 136 _chooser.getSelectionModel().addChangeListener(this); 137 _chooser.setPreviewPanel(new JPanel()); 138 JmriColorChooser.suppressAddRecentColor(true); 139 panel.add(_chooser); 140 panel.add(Box.createVerticalStrut(STRUT)); 141 142 panel.add(makeDoneButtonPanel()); 143 panel.add(Box.createVerticalGlue()); 144 145 super.addWindowListener(new java.awt.event.WindowAdapter() { 146 @Override 147 public void windowClosing(java.awt.event.WindowEvent e) { 148 cancel(); 149 } 150 }); 151 setContentPane(panel); 152 153 pack(); 154 InstanceManager.getDefault(jmri.util.PlaceWindow.class).nextTo(client, t, this); 155 setVisible(true); 156 } 157 158 JPanel makePanel(JPanel p) { 159 JPanel panel = new JPanel(); 160 panel.add(p); 161 return panel; 162 } 163 164 JPanel makeTextSpinnerPanel() { 165 JPanel panel = new JPanel(); 166 panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS)); 167 SpinnerNumberModel model = new SpinnerNumberModel(_util.getFixedWidth(), 0, 1000, 1); 168 panel.add(TextItemPanel.makeSpinPanel("fixedWidth", new AJSpinner(model, FWIDTH), this)); 169 panel.add(Box.createHorizontalStrut(STRUT)); 170 model = new SpinnerNumberModel(_util.getFixedHeight(), 0, 1000, 1); 171 panel.add(TextItemPanel.makeSpinPanel("fixedHeight", new AJSpinner(model, FHEIGHT), this)); 172 return panel; 173 } 174 175 JPanel makeTextPanel() { 176 JPanel panel = new JPanel(); 177 JTextField textField = new JTextField(_saveText, 25); 178 textField.addKeyListener(new KeyListener() { 179 @Override 180 public void keyTyped(KeyEvent evt) { 181 } 182 @Override 183 public void keyPressed(KeyEvent evt) { 184 } 185 @Override 186 public void keyReleased(KeyEvent evt) { 187 JTextField tmp = (JTextField) evt.getSource(); 188 ((PositionableLabel)_target).setText(tmp.getText()); 189 update(); 190 } 191 }); 192 panel.add(textField); 193 return panel; 194 } 195 196 protected JPanel makeDoneButtonPanel() { 197 JPanel panel = new JPanel(); 198 panel.setLayout(new FlowLayout()); 199 JButton doneButton = new JButton(Bundle.getMessage("ButtonDone")); 200 doneButton.addActionListener((ActionEvent event) -> { 201 done(); 202 }); 203 panel.add(doneButton); 204 205 JButton cancelButton = new JButton(Bundle.getMessage("ButtonCancel")); 206 cancelButton.addActionListener((ActionEvent event) -> cancel()); 207 208 panel.add(cancelButton); 209 return panel; 210 } 211 212 void done() { 213 log.debug("Done button: color= {}", _chooser.getColor()); 214 if (_colorAction != null) { 215 _colorAction.actionPerformed(null); 216 } 217 if (_util != null) { 218 _util.setSuppressRecentColor(false); 219 } 220 JmriColorChooser.suppressAddRecentColor(false); 221 JmriColorChooser.addRecentColor(_chooser.getColor()); 222 dispose(); 223 } 224 225 void cancel() { 226 if (_util != null) { 227 Positionable pl = (Positionable)_target; 228 pl.getEditor().setAttributes(_saveUtil, pl); 229 _util.setSuppressRecentColor(false); 230 pl.updateSize(); 231 if (_type == TEXT) { 232 ((PositionableLabel)_target).setText(_saveText); 233 } 234 } else { 235 _target.setBackground(_saveColor); 236 } 237 _target.setOpaque(_saveOpaque); 238 log.debug("Cancel: color= {}", _saveColor); 239 JmriColorChooser.suppressAddRecentColor(false); 240 dispose(); 241 } 242 243 private void update() { 244 if (_util != null) { 245 Positionable pl = (Positionable)_target; 246 pl.getEditor().setAttributes(_util, pl); 247 } 248 } 249 250 @Override 251 public void stateChanged(ChangeEvent e) { 252 Object obj = e.getSource(); 253 if (obj instanceof AJSpinner) { 254 int num = ((Number) ((AJSpinner) obj).getValue()).intValue(); 255 switch (((AJSpinner) obj)._which) { 256 case BORDER: 257 _util.setBorderSize(num); 258 break; 259 case MARGIN: 260 _util.setMargin(num); 261 break; 262 case FWIDTH: 263 _util.setFixedWidth(num); 264 break; 265 case FHEIGHT: 266 _util.setFixedHeight(num); 267 break; 268 default: 269 log.warn("Unexpected _which {} in stateChanged", ((AJSpinner) obj)._which); 270 break; 271 } 272 } else { 273 log.debug("stateChanged: color= {}", _chooser.getColor()); 274 if (_util != null) { 275 switch (_type) { 276 case BORDER: 277 _util.setBorderColor(_chooser.getColor()); 278 break; 279 case MARGIN: 280 _util.setBackgroundColor(_chooser.getColor()); 281 break; 282 case FONT: 283 case TEXT: 284 _util.setForeground(_chooser.getColor()); 285 break; 286 default: 287 } 288 } else { 289 _target.setOpaque(true); 290 _target.setBackground(_chooser.getColor()); 291 } 292 } 293 update(); 294 } 295 296 private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ColorDialog.class); 297} 298