/* * Open Source Physics software is free software as described near the bottom of this code file. * * For additional information and documentation on Open Source Physics please see: * <http://www.opensourcephysics.org/> */ /* * The org.opensourcephysics.media.core package defines the Open Source Physics * media framework for working with video and other media. * * Copyright (c) 2014 Douglas Brown and Wolfgang Christian. * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston MA 02111-1307 USA * or view the license online at http://www.gnu.org/copyleft/gpl.html * * For additional information and documentation on Open Source Physics, * please see <http://www.opensourcephysics.org/>. */ package org.opensourcephysics.media.core; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Font; import java.awt.Frame; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.FocusEvent; import java.awt.event.FocusListener; import javax.swing.BorderFactory; import javax.swing.Box; import javax.swing.JButton; import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.border.Border; /** * This displays and sets VideoClip and ClipControl properties. * * @author Douglas Brown * @version 1.0 */ public class ClipInspector extends JDialog { // instance fields protected VideoClip clip; protected ClipControl clipControl; protected JLabel startLabel, stepSizeLabel, t0Label; protected JLabel endLabel, dtLabel, fpsLabel; protected IntegerField startField, stepSizeField, endField; protected NumberField t0Field, dtField, fpsField; protected JButton okButton, cancelButton; protected int prevFrame, prevStart, prevEnd, prevSize, prevCount; protected double prevDt, prevRate, prevStartTime; protected boolean prevDefault; protected int currentStart, currentCount; protected Box frameBox, timeBox; protected double dtMin = 1.0E-18, fpsMin = 1.0E-18; /** * Constructs a non-modal ClipInspector with access to the clip control. * * @param videoClip the video clip * @param control the clip control * @param frame the owner */ public ClipInspector(VideoClip videoClip, ClipControl control, Frame frame) { super(frame, false); // non-modal dialog setResizable(false); clip = videoClip; clipControl = control; createGUI(); refresh(); initialize(); } /** * Initializes this clip inspector. */ public void initialize() { updateDisplay(); prevStart = clip.getStartFrameNumber(); prevEnd = clip.getEndFrameNumber(); prevSize = clip.getStepSize(); prevCount = clip.getStepCount(); prevStartTime = clip.getStartTime(); prevDefault = clip.isDefaultStartTime; prevDt = clipControl.getMeanFrameDuration(); prevRate = clipControl.getRate(); prevFrame = clipControl.getFrameNumber(); currentStart = clip.getStartFrameNumber(); currentCount = clip.getStepCount(); } /** * Refreshes the GUI. */ public void refresh() { setTitle(MediaRes.getString("ClipInspector.Title")); //$NON-NLS-1$ startLabel.setText(MediaRes.getString("ClipInspector.Label.StartFrame")); //$NON-NLS-1$ stepSizeLabel.setText(MediaRes.getString("ClipInspector.Label.StepSize")); //$NON-NLS-1$ t0Label.setText(MediaRes.getString("ClipInspector.Label.StartTime")); //$NON-NLS-1$ endLabel.setText(MediaRes.getString("ClipInspector.Label.EndFrame")); //$NON-NLS-1$ cancelButton.setText(MediaRes.getString("Dialog.Button.Cancel")); //$NON-NLS-1$ okButton.setText(MediaRes.getString("Dialog.Button.OK")); //$NON-NLS-1$ dtLabel.setText(MediaRes.getString("ClipInspector.Label.FrameDt")); //$NON-NLS-1$ fpsLabel.setText(MediaRes.getString("ClipInspector.Label.FPS")); //$NON-NLS-1$ frameBox.setBorder(BorderFactory.createTitledBorder( MediaRes.getString("ClipInspector.Title.Frames"))); //$NON-NLS-1$ timeBox.setBorder(BorderFactory.createTitledBorder( MediaRes.getString("ClipInspector.Title.FrameTimes"))); //$NON-NLS-1$ pack(); } //_____________________________ private methods ____________________________ /** * Creates the visible components for the clip. */ private void createGUI() { JPanel contentPane = new JPanel(new BorderLayout()); setContentPane(contentPane); Border labelBorder = BorderFactory.createEmptyBorder(3, 2, 3, 2); // create start label and field startLabel = new JLabel(); startLabel.setForeground(new Color(0, 0, 102)); startLabel.setFont(new Font("Dialog", Font.PLAIN, 12)); //$NON-NLS-1$ startLabel.setBorder(labelBorder); startField = new IntegerField(5); startField.setMaximumSize(startField.getPreferredSize()); final ActionListener startListener = new ActionListener() { public void actionPerformed(ActionEvent e) { int prevStart = clip.getStartFrameNumber(); if (!clip.setStartFrameNumber(startField.getIntValue(), clip.getEndFrameNumber())) { updateDisplay(); startField.selectAll(); return; // no change } currentStart = clip.getStartFrameNumber(); // reset start time if needed if (!clip.isDefaultStartTime) { double startTime = clip.getStartTime(); startTime += (currentStart-prevStart)*clipControl.getMeanFrameDuration(); clip.setStartTime(startTime); } clip.trimFrameCount(); currentCount = clip.getStepCount(); updateDisplay(); startField.selectAll(); clipControl.setStepNumber(0); } }; startField.addActionListener(startListener); startField.addFocusListener(new FocusListener() { public void focusGained(FocusEvent e) { startField.selectAll(); } public void focusLost(FocusEvent e) { startListener.actionPerformed(null); } }); // create stepSize label and field stepSizeLabel = new JLabel(); stepSizeLabel.setForeground(new Color(0, 0, 102)); stepSizeLabel.setFont(new Font("Dialog", Font.PLAIN, 12)); //$NON-NLS-1$ stepSizeLabel.setBorder(labelBorder); stepSizeField = new IntegerField(5); stepSizeField.setMaximumSize(stepSizeField.getPreferredSize()); stepSizeField.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { int frameNumber = clipControl.getFrameNumber(); if (!clip.setStepSize(stepSizeField.getIntValue())) { updateDisplay(); stepSizeField.selectAll(); return; } currentCount = clip.getStepCount(); updateDisplay(); stepSizeField.selectAll(); clipControl.setStepNumber(clip.frameToStep(frameNumber)); } }); stepSizeField.addFocusListener(new FocusListener() { public void focusGained(FocusEvent e) { stepSizeField.selectAll(); } public void focusLost(FocusEvent e) { int frameNumber = clipControl.getFrameNumber(); if (!clip.setStepSize(stepSizeField.getIntValue())) { updateDisplay(); stepSizeField.selectAll(); return; } currentCount = clip.getStepCount(); updateDisplay(); clipControl.setStepNumber(clip.frameToStep(frameNumber)); } }); // create end frame label and field endLabel = new JLabel(); endLabel.setForeground(new Color(0, 0, 102)); endLabel.setFont(new Font("Dialog", Font.PLAIN, 12)); //$NON-NLS-1$ endLabel.setBorder(labelBorder); endField = new IntegerField(5); endField.setMaximumSize(endField.getPreferredSize()); endField.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { if (!clip.setEndFrameNumber(endField.getIntValue())) { updateDisplay(); endField.selectAll(); return; } currentCount = clip.getStepCount(); updateDisplay(); endField.selectAll(); Video video = clip.getVideo(); if (video!=null && video.getFrameCount()>1) clipControl.setStepNumber(clip.getStepCount()-1); } }); endField.addFocusListener(new FocusListener() { public void focusGained(FocusEvent e) { endField.selectAll(); } public void focusLost(FocusEvent e) { if (!clip.setEndFrameNumber(endField.getIntValue())) { updateDisplay(); endField.selectAll(); return; } updateDisplay(); Video video = clip.getVideo(); if (video!=null && video.getFrameCount()>1) clipControl.setStepNumber(clip.getStepCount()-1); } }); // create start time label and field t0Label = new JLabel(); t0Label.setForeground(new Color(0, 0, 102)); t0Label.setFont(new Font("Dialog", Font.PLAIN, 12)); //$NON-NLS-1$ t0Label.setBorder(labelBorder); t0Field = new NumberField(5); String exp = "0.00E0"; //$NON-NLS-1$ String fixed = "0.000"; //$NON-NLS-1$ double[] limits = new double[] {.01, .1, 1, 10}; t0Field.setPatterns(new String[] {fixed, fixed, fixed, fixed, exp}, limits); t0Field.setUnits(" s"); //$NON-NLS-1$ t0Field.setMaximumSize(t0Field.getPreferredSize()); t0Field.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { if (t0Field.getText().equals("")) //$NON-NLS-1$ clip.setStartTime(Double.NaN); else clip.setStartTime(t0Field.getValue()*1000); updateDisplay(); t0Field.selectAll(); } }); t0Field.addFocusListener(new FocusListener() { public void focusGained(FocusEvent e) { t0Field.selectAll(); } public void focusLost(FocusEvent e) { if (t0Field.getText().equals("")) //$NON-NLS-1$ clip.setStartTime(Double.NaN); else clip.setStartTime(t0Field.getValue()*1000); updateDisplay(); } }); // create dt label and field dtLabel = new JLabel(); dtLabel.setForeground(new Color(0, 0, 102)); dtLabel.setFont(new Font("Dialog", Font.PLAIN, 12)); //$NON-NLS-1$ dtLabel.setBorder(labelBorder); dtField = new NumberField(5); dtField.setPatterns(new String[] {exp, fixed, fixed, fixed, exp}, limits); dtField.setMaxValue(1/fpsMin); dtField.setMinValue(dtMin); dtField.setUnits(" s"); //$NON-NLS-1$ dtField.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { clipControl.setFrameDuration(dtField.getValue()*1000); updateDisplay(); dtField.selectAll(); } }); dtField.addFocusListener(new FocusListener() { public void focusGained(FocusEvent e) { dtField.selectAll(); } public void focusLost(FocusEvent e) { clipControl.setFrameDuration(dtField.getValue()*1000); updateDisplay(); } }); // create fps label and field fpsLabel = new JLabel(); fpsLabel.setForeground(new Color(0, 0, 102)); fpsLabel.setFont(new Font("Dialog", Font.PLAIN, 12)); //$NON-NLS-1$ fpsLabel.setBorder(labelBorder); fpsField = new NumberField(5); exp = "0.0E0"; //$NON-NLS-1$ fixed = "0.00"; //$NON-NLS-1$ fpsField.setPatterns(new String[] {exp, fixed, fixed, fixed, exp}); fpsField.setMaxValue(1/dtMin); fpsField.setMinValue(fpsMin); fpsField.setUnits(" /s"); //$NON-NLS-1$ fpsField.setMaximumSize(fpsField.getPreferredSize()); fpsField.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { clipControl.setFrameDuration(1000/fpsField.getValue()); updateDisplay(); fpsField.selectAll(); } }); fpsField.addFocusListener(new FocusListener() { public void focusGained(FocusEvent e) { fpsField.selectAll(); } public void focusLost(FocusEvent e) { clipControl.setFrameDuration(1000/fpsField.getValue()); updateDisplay(); } }); // create data panel and add labels and fields Box dataBox = Box.createVerticalBox(); Border lined = BorderFactory.createLineBorder(Color.GRAY); Border empty = BorderFactory.createEmptyBorder(2, 4, 2, 4); dataBox.setBorder(BorderFactory.createCompoundBorder(lined, empty)); contentPane.add(dataBox, BorderLayout.CENTER); frameBox = Box.createVerticalBox(); timeBox = Box.createVerticalBox(); dataBox.add(frameBox); dataBox.add(timeBox); GridBagConstraints c = new GridBagConstraints(); // create startframe pane JPanel startPane = new JPanel(new GridBagLayout()); c.weightx = 0.5; c.anchor = GridBagConstraints.LINE_END; startPane.add(startLabel, c); c.weightx = 0.0; c.anchor = GridBagConstraints.LINE_START; startPane.add(startField, c); frameBox.add(startPane); // create stepsize pane JPanel sizePane = new JPanel(new GridBagLayout()); c.weightx = 0.5; c.anchor = GridBagConstraints.LINE_END; sizePane.add(stepSizeLabel, c); c.weightx = 0.0; c.anchor = GridBagConstraints.LINE_START; sizePane.add(stepSizeField, c); frameBox.add(sizePane); // create endframe pane JPanel endPane = new JPanel(new GridBagLayout()); c.weightx = 0.5; c.anchor = GridBagConstraints.LINE_END; endPane.add(endLabel, c); c.weightx = 0.0; c.anchor = GridBagConstraints.LINE_START; endPane.add(endField, c); frameBox.add(endPane); // create t0 pane JPanel t0Pane = new JPanel(new GridBagLayout()); c.weightx = 0.5; c.anchor = GridBagConstraints.LINE_END; t0Pane.add(t0Label, c); c.weightx = 0.0; c.anchor = GridBagConstraints.LINE_START; t0Pane.add(t0Field, c); timeBox.add(t0Pane); // create fps pane JPanel fpsPane = new JPanel(new GridBagLayout()); c.weightx = 0.5; c.anchor = GridBagConstraints.LINE_END; fpsPane.add(fpsLabel, c); c.weightx = 0.0; c.anchor = GridBagConstraints.LINE_START; fpsPane.add(fpsField, c); timeBox.add(fpsPane); // create dt pane JPanel dtPane = new JPanel(new GridBagLayout()); c.weightx = 0.5; c.anchor = GridBagConstraints.LINE_END; dtPane.add(dtLabel, c); c.weightx = 0.0; c.anchor = GridBagConstraints.LINE_START; dtPane.add(dtField, c); timeBox.add(dtPane); // create cancel button cancelButton = new JButton(); cancelButton.setForeground(new Color(0, 0, 102)); cancelButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { revert(); setVisible(false); } }); // create ok button okButton = new JButton(); okButton.setForeground(new Color(0, 0, 102)); okButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { setVisible(false); } }); // create buttonbar and add buttons JPanel buttonbar = new JPanel(); contentPane.add(buttonbar, BorderLayout.SOUTH); buttonbar.add(okButton); buttonbar.add(cancelButton); } /** * Updates this clip inspector to reflect the current clip settings. */ public void updateDisplay() { startField.setIntValue(clip.getStartFrameNumber()); stepSizeField.setIntValue(clip.getStepSize()); t0Field.setValue(clip.getStartTime()/1000); endField.setIntValue(clip.getEndFrameNumber()); double duration = clipControl.getMeanFrameDuration(); if (duration>0) { dtField.setValue(duration/1000); fpsField.setValue(1000/duration); } else { dtField.setText(null); fpsField.setText(null); } repaint(); } /** * Reverts to the previous clip settings. */ private void revert() { clip.setStartFrameNumber(prevStart); clip.setStepSize(prevSize); clip.setStepCount(prevCount); if (prevDefault) clip.setStartTime(Double.NaN); else clip.setStartTime(prevStartTime); clipControl.setRate(prevRate); clipControl.setFrameDuration(prevDt); clipControl.setStepNumber(clip.frameToStep(prevFrame)); clip.trimFrameCount(); } } /* * Open Source Physics software is free software; you can redistribute * it and/or modify it under the terms of the GNU General Public License (GPL) as * published by the Free Software Foundation; either version 2 of the License, * or(at your option) any later version. * Code that uses any portion of the code in the org.opensourcephysics package * or any subpackage (subdirectory) of this package must must also be be released * under the GNU GPL license. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston MA 02111-1307 USA * or view the license online at http://www.gnu.org/copyleft/gpl.html * * Copyright (c) 2007 The Open Source Physics project * http://www.opensourcephysics.org */