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.viewer; 020 021import java.awt.BorderLayout; 022import java.awt.Dimension; 023import java.awt.event.ActionEvent; 024import java.awt.event.ActionListener; 025import java.awt.event.ComponentAdapter; 026import java.awt.event.ComponentEvent; 027 028import javax.swing.BorderFactory; 029import javax.swing.Box; 030import javax.swing.BoxLayout; 031import javax.swing.JLabel; 032import javax.swing.JPanel; 033import javax.swing.JSlider; 034import javax.swing.JSpinner; 035import javax.swing.JTextField; 036import javax.swing.SpinnerNumberModel; 037import javax.swing.SwingConstants; 038import javax.swing.Timer; 039import javax.swing.event.ChangeEvent; 040import javax.swing.event.ChangeListener; 041 042import icy.gui.component.IcySlider; 043import icy.gui.component.button.IcyToggleButton; 044import icy.gui.util.ComponentUtil; 045import icy.gui.util.GuiUtil; 046import icy.resource.ResourceUtil; 047import icy.resource.icon.IcyIcon; 048import icy.system.thread.ThreadUtil; 049 050/** 051 * @author Stephane 052 */ 053public class TNavigationPanel extends JPanel 054{ 055 /** 056 * 057 */ 058 private static final long serialVersionUID = 9123780562399386045L; 059 060 private static final int DEFAULT_FRAME_RATE = 15; 061 062 final JSlider slider; 063 final JLabel leftLabel; 064 final JLabel rightLabel; 065 066 final IcyToggleButton play; 067 final IcyToggleButton loop; 068 final JSpinner frameRate; 069 070 final Timer timer; 071 072 public TNavigationPanel() 073 { 074 super(true); 075 076 slider = new IcySlider(SwingConstants.HORIZONTAL); 077 slider.setFocusable(false); 078 slider.setMaximum(0); 079 slider.setMinimum(0); 080 slider.setToolTipText("Move cursor to navigate in T dimension"); 081 slider.addChangeListener(new ChangeListener() 082 { 083 @Override 084 public void stateChanged(ChangeEvent e) 085 { 086 rightLabel.setText(Integer.toString(slider.getMaximum())); 087 leftLabel.setText(Integer.toString(slider.getValue())); 088 validate(); 089 } 090 }); 091 092 ComponentUtil.setFixedHeight(slider, 22); 093 094 timer = new Timer(1000 / DEFAULT_FRAME_RATE, new ActionListener() 095 { 096 @Override 097 public void actionPerformed(ActionEvent e) 098 { 099 // only if slider is not adjusting T position 100 if (!slider.getValueIsAdjusting()) 101 { 102 final int oldT = getTPosition(); 103 104 incTPosition(); 105 106 // end reached ? 107 if (oldT == getTPosition()) 108 { 109 // loop mode --> reset 110 if (isRepeat()) 111 setTPosition(0); 112 else 113 { 114 // end play 115 stopPlay(); 116 // and reset position 117 setTPosition(0); 118 } 119 } 120 } 121 } 122 }); 123 124 play = new IcyToggleButton(new IcyIcon(ResourceUtil.ICON_PLAY)); 125 play.setFlat(true); 126 play.setToolTipText("play"); 127 play.addActionListener(new ActionListener() 128 { 129 @Override 130 public void actionPerformed(ActionEvent e) 131 { 132 if (isPlaying()) 133 stopPlay(); 134 else 135 startPlay(); 136 } 137 }); 138 139 loop = new IcyToggleButton(new IcyIcon(ResourceUtil.ICON_ARROW_RIGHT, 16)); 140 loop.setFlat(true); 141 loop.setToolTipText("Enable loop playback"); 142 loop.addActionListener(new ActionListener() 143 { 144 @Override 145 public void actionPerformed(ActionEvent e) 146 { 147 setRepeat(!isRepeat()); 148 } 149 }); 150 // default 151 setRepeat(true); 152 153 frameRate = new JSpinner(new SpinnerNumberModel(DEFAULT_FRAME_RATE, 1, 60, 1)); 154 frameRate.setFocusable(false); 155 // no manual edition and edition focus 156 final JTextField tf = ((JSpinner.DefaultEditor) frameRate.getEditor()).getTextField(); 157 tf.setEditable(false); 158 tf.setFocusable(false); 159 frameRate.setToolTipText("Change playback frame rate"); 160 frameRate.addChangeListener(new ChangeListener() 161 { 162 @Override 163 public void stateChanged(ChangeEvent e) 164 { 165 final int f = ((Integer) frameRate.getValue()).intValue(); 166 // adjust timer delay 167 setTimerDelay(1000 / f); 168 } 169 }); 170 ComponentUtil.setFixedSize(frameRate, new Dimension(50, 22)); 171 172 leftLabel = new JLabel("0"); 173 leftLabel.setToolTipText("T position"); 174 rightLabel = new JLabel("0"); 175 rightLabel.setToolTipText("T sequence size"); 176 177 final JPanel leftPanel = GuiUtil.createLineBoxPanel(Box.createHorizontalStrut(8), GuiUtil.createBoldLabel("T"), 178 Box.createHorizontalStrut(10), leftLabel); 179 180 rightLabel.addComponentListener(new ComponentAdapter() 181 { 182 @Override 183 public void componentResized(ComponentEvent e) 184 { 185 // so left label is adjusted to right label size 186 ComponentUtil.setFixedWidth(leftLabel, rightLabel.getWidth()); 187 leftPanel.revalidate(); 188 } 189 }); 190 191 final JPanel rightPanel = new JPanel(); 192 rightPanel.setLayout(new BoxLayout(rightPanel, BoxLayout.LINE_AXIS)); 193 194 final JLabel frameRateLabel = new JLabel("FPS"); 195 frameRateLabel.setToolTipText("Frames Per Second"); 196 197 rightPanel.add(rightLabel); 198 rightPanel.add(Box.createHorizontalStrut(12)); 199 rightPanel.add(play); 200 rightPanel.add(loop); 201 rightPanel.add(Box.createHorizontalStrut(8)); 202 rightPanel.add(frameRate); 203 rightPanel.add(Box.createHorizontalStrut(4)); 204 rightPanel.add(frameRateLabel); 205 rightPanel.add(Box.createHorizontalStrut(4)); 206 207 // setBorder(BorderFactory.createLineBorder(BorderFactory.createTitledBorder("").getTitleColor())); 208 setBorder(BorderFactory.createTitledBorder("").getBorder()); 209 setLayout(new BorderLayout()); 210 211 add(leftPanel, BorderLayout.WEST); 212 add(slider, BorderLayout.CENTER); 213 add(rightPanel, BorderLayout.EAST); 214 215 validate(); 216 } 217 218 protected void incTPosition() 219 { 220 setTPosition(getTPosition() + 1); 221 } 222 223 protected void decTPosition() 224 { 225 setTPosition(Math.max(0, getTPosition() - 1)); 226 } 227 228 protected void setTimerDelay(int delay) 229 { 230 timer.setDelay(delay); 231 } 232 233 protected int getTPosition() 234 { 235 return slider.getValue(); 236 } 237 238 protected void setTPosition(final int t) 239 { 240 // we want to be sure the T position is changed in EDT 241 ThreadUtil.invokeNow(new Runnable() 242 { 243 @Override 244 public void run() 245 { 246 slider.setValue(t); 247 } 248 }); 249 } 250 251 /** 252 * Returns the frame rate (given in frame per second) for play command. 253 */ 254 public int getFrameRate() 255 { 256 return ((Integer) frameRate.getValue()).intValue(); 257 } 258 259 /** 260 * Sets the frame rate (given in frame per second) for play command. 261 */ 262 public void setFrameRate(int fps) 263 { 264 frameRate.setValue(Integer.valueOf(fps)); 265 } 266 267 /** 268 * Returns true if <code>repeat</code> is enabled for play command. 269 */ 270 public boolean isRepeat() 271 { 272 return loop.getToolTipText().startsWith("Disable"); 273 } 274 275 /** 276 * Set <code>repeat</code> mode for play command. 277 */ 278 public void setRepeat(boolean value) 279 { 280 if (value) 281 { 282 loop.setIcon(new IcyIcon(ResourceUtil.ICON_RELOAD, 16)); 283 loop.setSelected(true); 284 loop.setToolTipText("Disable loop playback"); 285 } 286 else 287 { 288 loop.setIcon(new IcyIcon(ResourceUtil.ICON_ARROW_RIGHT, 16)); 289 loop.setSelected(false); 290 loop.setToolTipText("Enable loop playback"); 291 } 292 } 293 294 /** 295 * Returns true if currently playing. 296 */ 297 public boolean isPlaying() 298 { 299 return timer.isRunning(); 300 } 301 302 /** 303 * Start sequence play. 304 * 305 * @see #stopPlay() 306 * @see #setRepeat(boolean) 307 */ 308 public void startPlay() 309 { 310 timer.start(); 311 play.setIcon(new IcyIcon(ResourceUtil.ICON_PAUSE)); 312 play.setSelected(true); 313 play.setToolTipText("pause"); 314 } 315 316 /** 317 * Stop sequence play. 318 * 319 * @see #startPlay() 320 */ 321 public void stopPlay() 322 { 323 timer.stop(); 324 play.setIcon(new IcyIcon(ResourceUtil.ICON_PLAY)); 325 play.setSelected(false); 326 play.setToolTipText("play"); 327 } 328 329 /** 330 * @see icy.gui.component.IcySlider#setPaintLabels(boolean) 331 */ 332 public void setPaintLabels(boolean b) 333 { 334 slider.setPaintLabels(b); 335 } 336 337 /** 338 * @see icy.gui.component.IcySlider#setPaintTicks(boolean) 339 */ 340 public void setPaintTicks(boolean b) 341 { 342 slider.setPaintTicks(b); 343 } 344 345 /** 346 * @see javax.swing.JSlider#addChangeListener(javax.swing.event.ChangeListener) 347 */ 348 public void addChangeListener(ChangeListener l) 349 { 350 slider.addChangeListener(l); 351 } 352 353 /** 354 * @see javax.swing.JSlider#removeChangeListener(javax.swing.event.ChangeListener) 355 */ 356 public void removeChangeListener(ChangeListener l) 357 { 358 slider.removeChangeListener(l); 359 } 360 361 /** 362 * Remove all change listener 363 */ 364 public void removeAllChangeListener() 365 { 366 for (ChangeListener l : slider.getListeners(ChangeListener.class)) 367 slider.removeChangeListener(l); 368 } 369 370 /** 371 * @see javax.swing.JSlider#getValue() 372 */ 373 public int getValue() 374 { 375 return slider.getValue(); 376 } 377 378 /** 379 * @param n 380 * @see javax.swing.JSlider#setValue(int) 381 */ 382 public void setValue(int n) 383 { 384 slider.setValue(n); 385 } 386 387 /** 388 * @see javax.swing.JSlider#getMinimum() 389 */ 390 public int getMinimum() 391 { 392 return slider.getMinimum(); 393 } 394 395 /** 396 * @see javax.swing.JSlider#setMinimum(int) 397 */ 398 public void setMinimum(int minimum) 399 { 400 slider.setMinimum(minimum); 401 } 402 403 /** 404 * @see javax.swing.JSlider#getMaximum() 405 */ 406 public int getMaximum() 407 { 408 return slider.getMaximum(); 409 } 410 411 /** 412 * @see javax.swing.JSlider#setMaximum(int) 413 */ 414 public void setMaximum(int maximum) 415 { 416 slider.setMaximum(maximum); 417 } 418 419 /** 420 * @see javax.swing.JSlider#getPaintTicks() 421 */ 422 public boolean getPaintTicks() 423 { 424 return slider.getPaintTicks(); 425 } 426 427 /** 428 * @see javax.swing.JSlider#getPaintTrack() 429 */ 430 public boolean getPaintTrack() 431 { 432 return slider.getPaintTrack(); 433 } 434 435 /** 436 * @see javax.swing.JSlider#setPaintTrack(boolean) 437 */ 438 public void setPaintTrack(boolean b) 439 { 440 slider.setPaintTrack(b); 441 } 442 443 /** 444 * @see javax.swing.JSlider#getPaintLabels() 445 */ 446 public boolean getPaintLabels() 447 { 448 return slider.getPaintLabels(); 449 } 450}