001/* 002 * Copyright 2010-2015 Institut Pasteur. 003 * 004 * This file is part of Icy. 005 * 006 * Icy is free software: you can redistribute it and/or modify 007 * it under the terms of the GNU General Public License as published by 008 * the Free Software Foundation, either version 3 of the License, or 009 * (at your option) any later version. 010 * 011 * Icy is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 014 * GNU General Public License for more details. 015 * 016 * You should have received a copy of the GNU General Public License 017 * along with Icy. If not, see <http://www.gnu.org/licenses/>. 018 */ 019package icy.gui.lut; 020 021import icy.canvas.IcyCanvas3D; 022import icy.file.xml.XMLPersistentHelper; 023import icy.gui.component.button.IcyButton; 024import icy.gui.component.button.IcyToggleButton; 025import icy.gui.component.renderer.ColormapComboBoxRenderer; 026import icy.gui.dialog.OpenDialog; 027import icy.gui.dialog.SaveDialog; 028import icy.gui.util.ComponentUtil; 029import icy.gui.util.GuiUtil; 030import icy.gui.viewer.Viewer; 031import icy.image.colormap.IcyColorMap; 032import icy.image.colormap.IcyColorMap.IcyColorMapType; 033import icy.image.colormap.IcyColorMapEvent; 034import icy.image.colormap.IcyColorMapListener; 035import icy.image.lut.LUT; 036import icy.image.lut.LUT.LUTChannel; 037import icy.resource.ResourceUtil; 038import icy.resource.icon.IcyIcon; 039import icy.sequence.Sequence; 040 041import java.awt.BorderLayout; 042import java.awt.event.ActionEvent; 043import java.awt.event.ActionListener; 044import java.util.List; 045 046import javax.swing.BorderFactory; 047import javax.swing.Box; 048import javax.swing.ButtonGroup; 049import javax.swing.JComboBox; 050import javax.swing.JPanel; 051import javax.swing.JSeparator; 052import javax.swing.SwingConstants; 053 054/** 055 * @author stephane 056 */ 057public class ColormapPanel extends JPanel implements IcyColorMapListener 058{ 059 /** 060 * 061 */ 062 private static final long serialVersionUID = -4042084504553770641L; 063 064 private static final String DEFAULT_COLORMAP_DIR = IcyColorMap.DEFAULT_COLORMAP_DIR; 065 private static final String DEFAULT_COLORMAP_NAME = "colormap.xml"; 066 067 /** 068 * gui 069 */ 070 private final ColormapViewer colormapViewer; 071 final IcyToggleButton rgbBtn; 072 final IcyToggleButton grayBtn; 073 final IcyToggleButton alphaBtn; 074 final ButtonGroup colormapTypeBtnGrp; 075 final JComboBox colormapComboBox; 076 077 /** 078 * associated Viewer & LUTBand 079 */ 080 public final Viewer viewer; 081 public final LUTChannel lutChannel; 082 083 /** 084 * cached 085 */ 086 final IcyColorMap colormap; 087 088 private boolean modifyingColormap; 089 090 public ColormapPanel(final Viewer viewer, final LUTChannel lutChannel) 091 { 092 super(); 093 094 this.viewer = viewer; 095 this.lutChannel = lutChannel; 096 modifyingColormap = false; 097 098 colormap = lutChannel.getColorMap(); 099 colormap.setName("Custom"); 100 101 colormapViewer = new ColormapViewer(lutChannel); 102 103 // colormap type 104 rgbBtn = new IcyToggleButton(new IcyIcon(ResourceUtil.ICON_RGB_COLOR, false)); 105 rgbBtn.setToolTipText("Set colormap type to Color"); 106 rgbBtn.setFocusPainted(false); 107 ComponentUtil.setFixedWidth(rgbBtn, 26); 108 grayBtn = new IcyToggleButton(new IcyIcon(ResourceUtil.ICON_GRAY_COLOR, false)); 109 grayBtn.setToolTipText("Set colormap type to Gray"); 110 grayBtn.setFocusPainted(false); 111 ComponentUtil.setFixedWidth(grayBtn, 26); 112 alphaBtn = new IcyToggleButton(new IcyIcon(ResourceUtil.ICON_ALPHA_COLOR, false)); 113 alphaBtn.setToolTipText("Set colormap type to Alpha (transparency)"); 114 alphaBtn.setFocusPainted(false); 115 ComponentUtil.setFixedWidth(alphaBtn, 26); 116 117 colormapTypeBtnGrp = new ButtonGroup(); 118 119 colormapTypeBtnGrp.add(rgbBtn); 120 colormapTypeBtnGrp.add(grayBtn); 121 colormapTypeBtnGrp.add(alphaBtn); 122 123 // select item according to current colormap type 124 updateColormapType(colormap.getType()); 125 126 rgbBtn.addActionListener(new ActionListener() 127 { 128 @Override 129 public void actionPerformed(ActionEvent e) 130 { 131 colormap.setType(IcyColorMapType.RGB); 132 } 133 }); 134 grayBtn.addActionListener(new ActionListener() 135 { 136 @Override 137 public void actionPerformed(ActionEvent e) 138 { 139 colormap.setType(IcyColorMapType.GRAY); 140 } 141 }); 142 alphaBtn.addActionListener(new ActionListener() 143 { 144 @Override 145 public void actionPerformed(ActionEvent e) 146 { 147 colormap.setType(IcyColorMapType.ALPHA); 148 } 149 }); 150 151 // alpha checkbox 152 // final JCheckBox alphaEnabled = new JCheckBox("alpha", null, true); 153 // alphaEnabled.setToolTipText("Enable alpha control"); 154 // alphaEnabled.addItemListener(new ItemListener() 155 // { 156 // @Override 157 // public void itemStateChanged(ItemEvent e) 158 // { 159 // // set alpha 160 // colormapViewer.setAlphaEnabled(e.getStateChange() == ItemEvent.SELECTED); 161 // } 162 // }); 163 164 final IcyColorMap defaultColormap; 165 // retrieve the default sequence LUT 166 final LUT defaultLUT = viewer.getSequence().getDefaultLUT(); 167 168 // compatible colormap (should always be the case) 169 if (defaultLUT.isCompatible(lutChannel.getLut())) 170 { 171 defaultColormap = defaultLUT.getLutChannel(lutChannel.getChannel()).getColorMap(); 172 defaultColormap.setName("Default"); 173 } 174 else 175 { 176 // asynchronous sequence change, get a default colormap from current one 177 defaultColormap = new IcyColorMap("Default"); 178 // copy from current colormap 179 defaultColormap.copyFrom(colormap); 180 } 181 182 // copy it in the sequence user colormap 183 updateSequenceColormap(); 184 185 // get colormap list 186 final List<IcyColorMap> colormaps = IcyColorMap.getAllColorMaps(true, true); 187 188 // remove the default colormap if already present in the list 189 colormaps.remove(defaultColormap); 190 // and set it at position 0 191 colormaps.add(0, defaultColormap); 192 193 // this is the user customized colormap 194 colormaps.add(colormap); 195 196 // build colormap selector 197 colormapComboBox = new JComboBox(colormaps.toArray()); 198 colormapComboBox.setRenderer(new ColormapComboBoxRenderer(colormapComboBox)); 199 // limit size 200 ComponentUtil.setFixedWidth(colormapComboBox, 96); 201 colormapComboBox.setToolTipText("Select colormap model"); 202 // don't want focusable here 203 colormapComboBox.setFocusable(false); 204 // set to current colormap 205 colormapComboBox.setSelectedItem(colormap); 206 207 colormapComboBox.addActionListener(new ActionListener() 208 { 209 @Override 210 public void actionPerformed(ActionEvent e) 211 { 212 setColorMap((IcyColorMap) colormapComboBox.getSelectedItem()); 213 } 214 }); 215 216 // load button 217 final IcyButton loadButton = new IcyButton(new IcyIcon(ResourceUtil.ICON_OPEN)); 218 loadButton.setFlat(true); 219 loadButton.setToolTipText("Load colormap from file"); 220 221 // action to load colormap 222 loadButton.addActionListener(new ActionListener() 223 { 224 @Override 225 public void actionPerformed(ActionEvent e) 226 { 227 final String filename = OpenDialog.chooseFile("Load colormap...", DEFAULT_COLORMAP_DIR, 228 DEFAULT_COLORMAP_NAME); 229 230 if (filename != null) 231 { 232 final IcyColorMap map = new IcyColorMap(); 233 234 if (XMLPersistentHelper.loadFromXML(map, filename)) 235 setColorMap(map); 236 } 237 } 238 }); 239 240 // save button 241 final IcyButton saveButton = new IcyButton(new IcyIcon(ResourceUtil.ICON_SAVE)); 242 saveButton.setFlat(true); 243 saveButton.setToolTipText("Save colormap to file"); 244 245 // action to save colormap 246 saveButton.addActionListener(new ActionListener() 247 { 248 @Override 249 public void actionPerformed(ActionEvent e) 250 { 251 final String filename = SaveDialog.chooseFile("Save colormap...", DEFAULT_COLORMAP_DIR, 252 DEFAULT_COLORMAP_NAME); 253 254 if (filename != null) 255 XMLPersistentHelper.saveToXML(colormap, filename); 256 } 257 }); 258 259 // set up GUI 260 final JPanel bottomPanel = new JPanel(); 261 bottomPanel.setLayout(new BorderLayout()); 262 bottomPanel.setBorder(BorderFactory.createEmptyBorder(2, 0, 0, 0)); 263 264 bottomPanel.add(GuiUtil.createLineBoxPanel(rgbBtn, grayBtn, alphaBtn), BorderLayout.WEST); 265 bottomPanel.add(Box.createGlue(), BorderLayout.CENTER); 266 bottomPanel.add( 267 GuiUtil.createLineBoxPanel(colormapComboBox, new JSeparator(SwingConstants.VERTICAL), loadButton, 268 Box.createHorizontalStrut(2), saveButton), BorderLayout.EAST); 269 // bottomPanel.add(Box.createHorizontalStrut(6)); 270 // bottomPanel.add(alphaEnabled); 271 272 bottomPanel.validate(); 273 274 setLayout(new BorderLayout()); 275 276 add(colormapViewer, BorderLayout.CENTER); 277 add(bottomPanel, BorderLayout.SOUTH); 278 279 validate(); 280 } 281 282 @Override 283 public void addNotify() 284 { 285 super.addNotify(); 286 287 // listen colormap changes 288 colormap.addListener(this); 289 } 290 291 @Override 292 public void removeNotify() 293 { 294 colormap.removeListener(this); 295 296 super.removeNotify(); 297 } 298 299 /** 300 * @return the colormapViewer 301 */ 302 public ColormapViewer getColormapViewer() 303 { 304 return colormapViewer; 305 } 306 307 private void updateColormapType(IcyColorMapType type) 308 { 309 switch (type) 310 { 311 case RGB: 312 colormapTypeBtnGrp.setSelected(rgbBtn.getModel(), true); 313 break; 314 case GRAY: 315 colormapTypeBtnGrp.setSelected(grayBtn.getModel(), true); 316 break; 317 case ALPHA: 318 colormapTypeBtnGrp.setSelected(alphaBtn.getModel(), true); 319 break; 320 } 321 } 322 323 /** 324 * Set the colormap. 325 */ 326 public void setColorMap(IcyColorMap src) 327 { 328 if (colormap == src) 329 return; 330 331 modifyingColormap = true; 332 try 333 { 334 if (viewer.getCanvas() instanceof IcyCanvas3D) 335 { 336 // copy alpha component only if we have specific alpha info 337 // copyAlpha = !src.alpha.isAllSame(); 338 colormap.beginUpdate(); 339 try 340 { 341 colormap.copyFrom(src, false); 342 colormap.setAlphaToLinear3D(); 343 } 344 finally 345 { 346 colormap.endUpdate(); 347 } 348 } 349 else 350 colormap.copyFrom(src, true); 351 } 352 finally 353 { 354 modifyingColormap = false; 355 } 356 357 colormapComboBox.setSelectedItem(colormap); 358 } 359 360 void updateSequenceColormap() 361 { 362 // set the current colormap in the sequence 363 final Sequence seq = viewer.getSequence(); 364 365 if (seq != null) 366 { 367 final int ch = lutChannel.getChannel(); 368 369 if (ch < seq.getSizeC()) 370 seq.setColormap(ch, colormap, true); 371 } 372 } 373 374 /** 375 * @deprecated Use {@link #setColorMap(IcyColorMap)} instead. 376 */ 377 @Deprecated 378 public void copyColorMap(IcyColorMap src) 379 { 380 setColorMap(src); 381 } 382 383 @Override 384 public void colorMapChanged(IcyColorMapEvent e) 385 { 386 switch (e.getType()) 387 { 388 case TYPE_CHANGED: 389 // colormap type has changed ? --> update combo state 390 updateColormapType(e.getColormap().getType()); 391 break; 392 393 case MAP_CHANGED: 394 // colormap has been manually changed, set name to custom 395 if (!modifyingColormap) 396 colormap.setName("Custom"); 397 // update the combo box colormap representation 398 colormapComboBox.setSelectedItem(colormap); 399 colormapComboBox.repaint(); 400 break; 401 } 402 403 updateSequenceColormap(); 404 } 405}