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.component.sequence; 020 021import icy.image.IcyBufferedImage; 022import icy.image.IcyBufferedImageUtil; 023import icy.sequence.SequenceModel; 024import icy.sequence.SequenceModel.SequenceModelListener; 025import icy.system.thread.ThreadUtil; 026import icy.util.GraphicsUtil; 027import icy.util.StringUtil; 028 029import java.awt.BorderLayout; 030import java.awt.Dimension; 031import java.awt.Font; 032import java.awt.Graphics; 033import java.awt.Graphics2D; 034import java.awt.GridBagConstraints; 035import java.awt.GridBagLayout; 036import java.awt.Insets; 037import java.awt.RenderingHints; 038import java.awt.image.BufferedImage; 039 040import javax.swing.JLabel; 041import javax.swing.JPanel; 042import javax.swing.JSlider; 043import javax.swing.SwingConstants; 044import javax.swing.border.EmptyBorder; 045import javax.swing.event.ChangeEvent; 046import javax.swing.event.ChangeListener; 047 048public class SequencePreviewPanel extends JPanel implements ChangeListener, SequenceModelListener 049{ 050 /** 051 * 052 */ 053 private static final long serialVersionUID = 4985194381532600393L; 054 055 private class CustomPanel extends JPanel implements Runnable 056 { 057 /** 058 * 059 */ 060 private static final long serialVersionUID = 6307431557815572470L; 061 062 private BufferedImage cache; 063 064 public CustomPanel() 065 { 066 super(); 067 068 cache = null; 069 } 070 071 @Override 072 protected void paintComponent(Graphics g) 073 { 074 super.paintComponent(g); 075 076 final int w = getWidth(); 077 final int h = getHeight(); 078 final Graphics2D g2 = (Graphics2D) g.create(); 079 080 g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); 081 g2.setFont(g2.getFont().deriveFont(Font.BOLD, 22)); 082 083 if (cache == null) 084 GraphicsUtil.drawCenteredString(g2, "No image", w / 2, h / 2, false); 085 else if ((w > 0) && (h > 0)) 086 { 087 final int sw = getSizeX(); 088 final int sh = getSizeY(); 089 final int iw = cache.getWidth(); 090 final int ih = cache.getHeight(); 091 final int fiw; 092 final int fih; 093 094 if (fitToView) 095 { 096 final double ratio1 = Math.max((double) iw / (double) sw, (double) ih / (double) sh); 097 final double ratio2 = Math.max((double) sw / (double) w, (double) sh / (double) h); 098 099 fiw = (int) (iw / (ratio1 * ratio2)); 100 fih = (int) (ih / (ratio1 * ratio2)); 101 } 102 else 103 { 104 final double ratio = Math.max((double) sw / (double) w, (double) sh / (double) h); 105 106 fiw = (int) (iw / ratio); 107 fih = (int) (ih / ratio); 108 } 109 110 g2.drawImage(cache, (w - fiw) / 2, (h - fih) / 2, fiw, fih, null); 111 } 112 113 g2.dispose(); 114 } 115 116 public void imageChanged() 117 { 118 // request rebuild cache 119 ThreadUtil.runSingle(this); 120 } 121 122 int getSizeX() 123 { 124 if (model != null) 125 return model.getSizeX(); 126 if (cache != null) 127 return cache.getWidth(); 128 return 0; 129 } 130 131 int getSizeY() 132 { 133 if (model != null) 134 return model.getSizeY(); 135 if (cache != null) 136 return cache.getHeight(); 137 return 0; 138 } 139 140 @Override 141 public void run() 142 { 143 // rebuild cache and repaint 144 final BufferedImage img = getImage(); 145 146 if (img instanceof IcyBufferedImage) 147 cache = IcyBufferedImageUtil.toBufferedImage((IcyBufferedImage) img, BufferedImage.TYPE_INT_ARGB); 148 else 149 cache = img; 150 151 repaint(); 152 } 153 } 154 155 protected boolean autoHideSliders; 156 protected boolean fitToView; 157 158 protected JSlider tSlider; 159 protected JSlider zSlider; 160 protected CustomPanel imagePanel; 161 protected SequenceModel model; 162 protected JLabel titleLabel; 163 protected JPanel mainPanel; 164 protected JPanel zPanel; 165 protected JPanel tPanel; 166 protected JLabel lblZ; 167 protected JLabel lblT; 168 protected JLabel lblZValue; 169 protected JLabel lblTValue; 170 171 /** 172 * Create the panel. 173 */ 174 public SequencePreviewPanel(String title, boolean autoHideSliders) 175 { 176 super(); 177 178 this.autoHideSliders = autoHideSliders; 179 fitToView = true; 180 181 model = null; 182 183 initializeGui(); 184 185 if (autoHideSliders) 186 { 187 zPanel.setVisible(false); 188 tPanel.setVisible(false); 189 } 190 191 setMaxZ(0); 192 setMaxT(0); 193 194 zSlider.addChangeListener(this); 195 tSlider.addChangeListener(this); 196 197 setTitle(title); 198 199 // setMinimumSize(new Dimension(320, 200)); 200 setPreferredSize(new Dimension(280, 200)); 201 202 validate(); 203 } 204 205 /** 206 * Create the panel. 207 */ 208 public SequencePreviewPanel(boolean autoHideSliders) 209 { 210 this(null, autoHideSliders); 211 } 212 213 /** 214 * Create the panel. 215 */ 216 public SequencePreviewPanel(String title) 217 { 218 this(title, true); 219 } 220 221 /** 222 * Create the panel. 223 */ 224 public SequencePreviewPanel() 225 { 226 this(null, true); 227 } 228 229 private void initializeGui() 230 { 231 setLayout(new BorderLayout(0, 0)); 232 233 titleLabel = new JLabel("Title"); 234 titleLabel.setBorder(new EmptyBorder(2, 0, 4, 0)); 235 titleLabel.setFont(new Font("Tahoma", Font.BOLD, 13)); 236 titleLabel.setHorizontalAlignment(SwingConstants.CENTER); 237 add(titleLabel, BorderLayout.NORTH); 238 239 mainPanel = new JPanel(); 240 add(mainPanel, BorderLayout.CENTER); 241 GridBagLayout gbl_mainPanel = new GridBagLayout(); 242 gbl_mainPanel.columnWidths = new int[] {0, 0, 0}; 243 gbl_mainPanel.rowHeights = new int[] {0, 0, 0}; 244 gbl_mainPanel.columnWeights = new double[] {0.0, 1.0, Double.MIN_VALUE}; 245 gbl_mainPanel.rowWeights = new double[] {1.0, 0.0, Double.MIN_VALUE}; 246 mainPanel.setLayout(gbl_mainPanel); 247 248 imagePanel = new CustomPanel(); 249 GridBagConstraints gbc_imagePanel = new GridBagConstraints(); 250 gbc_imagePanel.insets = new Insets(0, 0, 5, 5); 251 gbc_imagePanel.fill = GridBagConstraints.BOTH; 252 gbc_imagePanel.gridx = 1; 253 gbc_imagePanel.gridy = 0; 254 mainPanel.add(imagePanel, gbc_imagePanel); 255 256 zPanel = new JPanel(); 257 GridBagConstraints gbc_zPanel = new GridBagConstraints(); 258 gbc_zPanel.insets = new Insets(0, 0, 5, 5); 259 gbc_zPanel.fill = GridBagConstraints.BOTH; 260 gbc_zPanel.gridx = 0; 261 gbc_zPanel.gridy = 0; 262 mainPanel.add(zPanel, gbc_zPanel); 263 GridBagLayout gbl_zPanel = new GridBagLayout(); 264 gbl_zPanel.columnWidths = new int[] {0, 0}; 265 gbl_zPanel.rowHeights = new int[] {0, 0, 0, 0}; 266 gbl_zPanel.columnWeights = new double[] {0.0, Double.MIN_VALUE}; 267 gbl_zPanel.rowWeights = new double[] {0.0, 1.0, 0.0, Double.MIN_VALUE}; 268 zPanel.setLayout(gbl_zPanel); 269 270 lblZ = new JLabel("Z"); 271 GridBagConstraints gbc_lblZ = new GridBagConstraints(); 272 gbc_lblZ.fill = GridBagConstraints.BOTH; 273 gbc_lblZ.insets = new Insets(0, 0, 5, 0); 274 gbc_lblZ.gridx = 0; 275 gbc_lblZ.gridy = 0; 276 zPanel.add(lblZ, gbc_lblZ); 277 lblZ.setFont(new Font("Tahoma", Font.BOLD, 12)); 278 lblZ.setHorizontalAlignment(SwingConstants.CENTER); 279 280 zSlider = new JSlider(SwingConstants.VERTICAL); 281 GridBagConstraints gbc_zSlider = new GridBagConstraints(); 282 gbc_zSlider.fill = GridBagConstraints.BOTH; 283 gbc_zSlider.insets = new Insets(0, 0, 5, 0); 284 gbc_zSlider.gridx = 0; 285 gbc_zSlider.gridy = 1; 286 zPanel.add(zSlider, gbc_zSlider); 287 // zSlider.setFocusable(false); 288 289 lblZValue = new JLabel("0"); 290 GridBagConstraints gbc_lblZValue = new GridBagConstraints(); 291 gbc_lblZValue.fill = GridBagConstraints.BOTH; 292 gbc_lblZValue.gridx = 0; 293 gbc_lblZValue.gridy = 2; 294 zPanel.add(lblZValue, gbc_lblZValue); 295 lblZValue.setHorizontalAlignment(SwingConstants.CENTER); 296 lblZValue.setFont(new Font("Tahoma", Font.BOLD, 11)); 297 298 tPanel = new JPanel(); 299 GridBagConstraints gbc_tPanel = new GridBagConstraints(); 300 gbc_tPanel.fill = GridBagConstraints.BOTH; 301 gbc_tPanel.gridx = 1; 302 gbc_tPanel.gridy = 1; 303 mainPanel.add(tPanel, gbc_tPanel); 304 GridBagLayout gbl_tPanel = new GridBagLayout(); 305 gbl_tPanel.columnWidths = new int[] {0, 0, 0, 0}; 306 gbl_tPanel.rowHeights = new int[] {0, 0}; 307 gbl_tPanel.columnWeights = new double[] {0.0, 1.0, 0.0, Double.MIN_VALUE}; 308 gbl_tPanel.rowWeights = new double[] {1.0, Double.MIN_VALUE}; 309 tPanel.setLayout(gbl_tPanel); 310 311 lblTValue = new JLabel("0"); 312 lblTValue.setMaximumSize(new Dimension(1000, 14)); 313 lblTValue.setPreferredSize(new Dimension(20, 14)); 314 lblTValue.setMinimumSize(new Dimension(20, 14)); 315 GridBagConstraints gbc_lblTValue = new GridBagConstraints(); 316 gbc_lblTValue.fill = GridBagConstraints.BOTH; 317 gbc_lblTValue.insets = new Insets(0, 0, 0, 5); 318 gbc_lblTValue.gridx = 0; 319 gbc_lblTValue.gridy = 0; 320 tPanel.add(lblTValue, gbc_lblTValue); 321 lblTValue.setHorizontalAlignment(SwingConstants.CENTER); 322 lblTValue.setFont(new Font("Tahoma", Font.BOLD, 11)); 323 324 tSlider = new JSlider(SwingConstants.HORIZONTAL); 325 GridBagConstraints gbc_tSlider = new GridBagConstraints(); 326 gbc_tSlider.fill = GridBagConstraints.BOTH; 327 gbc_tSlider.insets = new Insets(0, 0, 0, 5); 328 gbc_tSlider.gridx = 1; 329 gbc_tSlider.gridy = 0; 330 tPanel.add(tSlider, gbc_tSlider); 331 // tSlider.setFocusable(false); 332 333 lblT = new JLabel("T"); 334 lblT.setPreferredSize(new Dimension(20, 14)); 335 lblT.setMaximumSize(new Dimension(1000, 14)); 336 lblT.setMinimumSize(new Dimension(20, 14)); 337 GridBagConstraints gbc_lblT = new GridBagConstraints(); 338 gbc_lblT.fill = GridBagConstraints.BOTH; 339 gbc_lblT.gridx = 2; 340 gbc_lblT.gridy = 0; 341 tPanel.add(lblT, gbc_lblT); 342 lblT.setFont(new Font("Tahoma", Font.BOLD, 12)); 343 lblT.setHorizontalAlignment(SwingConstants.CENTER); 344 345 validate(); 346 } 347 348 /** 349 * @return the main panel 350 */ 351 public JPanel getMainPanel() 352 { 353 return mainPanel; 354 } 355 356 /** 357 * @return the zPanel 358 */ 359 public JPanel getZPanel() 360 { 361 return zPanel; 362 } 363 364 /** 365 * @return the tPanel 366 */ 367 public JPanel getTPanel() 368 { 369 return tPanel; 370 } 371 372 public boolean getAutoHideSliders() 373 { 374 return autoHideSliders; 375 } 376 377 public void setAutoHideSliders(boolean value) 378 { 379 if (autoHideSliders != value) 380 { 381 autoHideSliders = value; 382 zPanel.setVisible((zSlider.getMaximum() > 0) && value); 383 tPanel.setVisible((tSlider.getMaximum() > 0) && value); 384 } 385 } 386 387 public void setFitToView(boolean value) 388 { 389 if (fitToView != value) 390 { 391 fitToView = value; 392 imagePanel.imageChanged(); 393 } 394 } 395 396 public void setPositionZ(int z) 397 { 398 zSlider.setValue(z); 399 imageChanged(); 400 } 401 402 public void setPositionT(int t) 403 { 404 tSlider.setValue(t); 405 imageChanged(); 406 } 407 408 private void setMaxZ(int value) 409 { 410 zSlider.setMaximum(Math.max(0, value)); 411 if (autoHideSliders) 412 zPanel.setVisible(value > 0); 413 } 414 415 private void setMaxT(int value) 416 { 417 tSlider.setMaximum(Math.max(0, value)); 418 if (autoHideSliders) 419 tPanel.setVisible(value > 0); 420 } 421 422 /** 423 * @return the image provider 424 */ 425 public SequenceModel getModel() 426 { 427 return model; 428 } 429 430 public void setModel(SequenceModel model) 431 { 432 if (this.model != model) 433 { 434 if (this.model != null) 435 this.model.removeSequenceModelListener(this); 436 437 this.model = model; 438 439 if (model != null) 440 model.addSequenceModelListener(this); 441 442 dimensionChanged(); 443 } 444 } 445 446 public void setTitle(String value) 447 { 448 if (!titleLabel.getText().equals(value)) 449 { 450 titleLabel.setText(value); 451 titleLabel.setVisible(!StringUtil.isEmpty(value)); 452 } 453 } 454 455 @Override 456 public void dimensionChanged() 457 { 458 if (model != null) 459 { 460 setMaxZ(model.getSizeZ() - 1); 461 setMaxT(model.getSizeT() - 1); 462 } 463 else 464 { 465 setMaxZ(0); 466 setMaxT(0); 467 } 468 469 imagePanel.imageChanged(); 470 } 471 472 @Override 473 public void imageChanged() 474 { 475 imagePanel.imageChanged(); 476 } 477 478 BufferedImage getImage() 479 { 480 if (model == null) 481 return null; 482 483 return model.getImage(tSlider.getValue(), zSlider.getValue()); 484 } 485 486 @Override 487 public void stateChanged(ChangeEvent e) 488 { 489 imagePanel.imageChanged(); 490 lblZValue.setText(Integer.toString(zSlider.getValue())); 491 lblTValue.setText(Integer.toString(tSlider.getValue())); 492 } 493}