/* * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code 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 * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores * CA 94065 USA or visit www.oracle.com if you need additional information or * have any questions. */ package com.codename1.designer; import com.codename1.designer.ResourceEditorView; import com.codename1.ui.animations.AnimationAccessor; import java.awt.BorderLayout; import java.awt.Component; import java.awt.event.ActionEvent; import java.awt.event.MouseEvent; import javax.swing.JList; import javax.swing.SpinnerNumberModel; import com.codename1.ui.animations.Timeline; import com.codename1.ui.EncodedImage; import com.codename1.ui.animations.AnimationObject; import com.codename1.tools.resourcebuilder.AnimationImpl; import com.codename1.ui.util.EditableResources; import java.awt.Point; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.image.BufferedImage; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.prefs.Preferences; import javax.imageio.ImageIO; import javax.imageio.ImageReader; import javax.imageio.metadata.IIOMetadata; import javax.swing.DefaultListCellRenderer; import javax.swing.DefaultListModel; import javax.swing.JFrame; import javax.swing.JOptionPane; import javax.swing.JSpinner; import javax.swing.SwingUtilities; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.swing.event.TableModelListener; import javax.swing.filechooser.FileFilter; import javax.swing.table.AbstractTableModel; import javax.swing.table.TableModel; import org.w3c.dom.Node; import org.w3c.dom.NodeList; /** * * @author Shai */ public class TimelineEditor extends BaseForm { private CodenameOneImageRenderer renderer; private EditableResources res; private String name; private javax.swing.Timer refreshTimeline; /** Creates new form TimelineEditor */ public TimelineEditor(EditableResources res, String name, ResourceEditorView view) { if(res.isOverrideMode() && !res.isOverridenResource(name)) { setOverrideMode(true, view.getComponent()); } initComponents(); animationObjectList.setModel(new AnimationObjectTableModel()); this.res = res; this.name = name; animationObjectList.getSelectionModel().addListSelectionListener(new ListSelectionListener() { public void valueChanged(ListSelectionEvent e) { int i = animationObjectList.getSelectedRow(); removeAnimationObject.setEnabled(i > -1); duplicateObject.setEnabled(i > -1); int size = animationObjectList.getModel().getRowCount(); moveUp.setEnabled(i > -1 && i > 0 && size > 1); moveDown.setEnabled(i > -1 && i < size - 1 && size > 1); } }); animationObjectList.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { if(SwingUtilities.isLeftMouseButton(e) && e.getClickCount() == 2 && animationObjectList.getSelectedRow() > -1) { Timeline t = (Timeline)TimelineEditor.this.res.getImage(TimelineEditor.this.name); updatePosition(-1, -1, t.getAnimation(animationObjectList.getSelectedRow()), false); } renderer.repaint(); } }); duration.setModel(new SpinnerNumberModel(20000, 1000, 1000000, 1000)); width.setModel(new SpinnerNumberModel(240, 10, 1000, 10)); height.setModel(new SpinnerNumberModel(320, 10, 1000, 10)); com.codename1.ui.animations.Timeline current = (com.codename1.ui.animations.Timeline)res.getImage(name); if(current == null) { current = Timeline.createTimeline(3000, new AnimationObject[0], new com.codename1.ui.geom.Dimension(100, 100)); } setImage(current); current.setPause(true); } public class AnimationObjectTableModel extends AbstractTableModel { private List<com.codename1.ui.animations.AnimationObject> anims = new ArrayList<com.codename1.ui.animations.AnimationObject>(); private final String[] COLUMNS = {"Start Time", "Duration", "Image", "X", "Y", "Width", "Height", "Orientation", "Opacity"}; public int indexOf(com.codename1.ui.animations.AnimationObject o) { return anims.indexOf(o); } public void setElementAt(com.codename1.ui.animations.AnimationObject o, int index) { anims.set(index, o); fireTableRowsUpdated(index, index); } public void addElement(com.codename1.ui.animations.AnimationObject o) { anims.add(o); fireTableRowsInserted(anims.size() - 1, anims.size() - 1); } public void remove(int i) { anims.remove(i); fireTableRowsDeleted(i, i); } public void updateTimeline(com.codename1.ui.animations.Timeline t) { anims.clear(); for(int iter = 0 ; iter < t.getAnimationCount() ; iter++) { anims.add(t.getAnimation(iter)); } fireTableDataChanged(); } public int getRowCount() { return anims.size(); } public com.codename1.ui.animations.AnimationObject getElementAt(int i) { return anims.get(i); } public int getColumnCount() { return COLUMNS.length; } public String getColumnName(int columnIndex) { return COLUMNS[columnIndex]; } public Class<?> getColumnClass(int columnIndex) { return String.class; } public boolean isCellEditable(int rowIndex, int columnIndex) { return false; } private String motionToString(com.codename1.ui.animations.Motion m) { if(m == null) { return ""; } if(m.getSourceValue() != m.getDestinationValue()) { return "" + m.getSourceValue() + " - " + m.getDestinationValue(); } return "" + m.getSourceValue(); } public Object getValueAt(int rowIndex, int columnIndex) { com.codename1.ui.animations.AnimationObject o = anims.get(rowIndex); switch(columnIndex) { case 0: return "" + o.getStartTime(); case 1: return "" + (o.getEndTime() - o.getStartTime()); case 2: if(AnimationAccessor.getImageName(o) != null) { return AnimationAccessor.getImageName(o); } return res.findId(AnimationAccessor.getImage(o)); case 3: return motionToString(AnimationAccessor.getMotionX(o)); case 4: return motionToString(AnimationAccessor.getMotionY(o)); case 5: return motionToString(AnimationAccessor.getWidth(o)); case 6: return motionToString(AnimationAccessor.getHeight(o)); case 7: return motionToString(AnimationAccessor.getOrientation(o)); case 8: return motionToString(AnimationAccessor.getOpacity(o)); } return null; } } /** * Selects a gif file using a file chooser and converts it to a timeline */ public static void selectFile(ResourceEditorView view, EditableResources res, String timelineName) { File[] files = ResourceEditorView.showOpenFileChooser("Images", ".gif"); if(files != null) { File sel = files[0]; if(timelineName == null) { timelineName = sel.getName(); } Preferences.userNodeForPackage(view.getClass()).put("lastDir", sel.getParentFile().getAbsolutePath()); ImageReader iReader = ImageIO.getImageReadersBySuffix("gif").next(); try { iReader.setInput(ImageIO.createImageInputStream(new FileInputStream(sel))); int frames = iReader.getNumImages(true); AnimationObject[] anims = new AnimationObject[frames]; int currentTime = 0; for(int frameIter = 0 ; frameIter < frames ; frameIter++) { BufferedImage currentImage = iReader.read(frameIter); ByteArrayOutputStream bo = new ByteArrayOutputStream(); ImageIO.write(currentImage, "png", bo); bo.close(); // create a PNG image in the resource file String label = sel.getName() + " frame:" + frameIter; EncodedImage i = EncodedImage.create(bo.toByteArray()); res.setImage(label, i); int duration = Math.max(40, AnimationImpl.getFrameTime(iReader, frameIter)); Point pos = AnimationImpl.getPixelOffsets(iReader, frameIter); anims[frameIter] = AnimationObject.createAnimationImage(i, pos.x, pos.y); anims[frameIter].setStartTime(currentTime); anims[frameIter].setEndTime(100000000); String disposeMethod = getDisposalMethod(iReader, frameIter); if(disposeMethod != null) { if("restoreToBackgroundColor".equals(disposeMethod)) { if(frameIter + 1 < frames) { int t = Math.max(40, AnimationImpl.getFrameTime(iReader, frameIter + 1)); anims[frameIter].setEndTime(currentTime + t); } else { anims[frameIter].setEndTime(currentTime + duration); } //for(int iter = frameIter ; iter >= 0 ; iter--) { // anims[iter].setEndTime(currentTime); //} } // "none" | // "doNotDispose" | "restoreToBackgroundColor" | // "restoreToPrevious" } currentTime += duration; } Timeline t = Timeline.createTimeline(currentTime, anims, new com.codename1.ui.geom.Dimension(iReader.getWidth(0), iReader.getHeight(0))); res.setImage(timelineName, t); view.setSelectedResource(timelineName); } catch(IOException err) { err.printStackTrace(); JOptionPane.showMessageDialog(JFrame.getFrames()[0], "Error reading file " + err, "IO Error", JOptionPane.ERROR_MESSAGE); } } } static String getDisposalMethod(ImageReader reader, int num) throws IOException { IIOMetadata meta = reader.getImageMetadata(num); Node parent = meta.getAsTree("javax_imageio_gif_image_1.0"); //printNodeTree(parent); NodeList root = parent.getChildNodes(); for(int iter = 0 ; iter < root.getLength() ; iter++) { Node n = root.item(iter); if(n.getNodeName().equals("GraphicControlExtension")) { return n.getAttributes().getNamedItem("disposalMethod").getNodeValue(); } } return null; } public void updatePosition(int x, int y, AnimationObject o, boolean startingPoint) { AnimationObjectTableModel dl = (AnimationObjectTableModel)animationObjectList.getModel(); int index = -1; for(int iter = 0 ; iter < animationObjectList.getModel().getRowCount() ; iter++) { if(dl.getElementAt(iter) == o) { index = iter; break; } } Timeline t = (Timeline)TimelineEditor.this.res.getImage(TimelineEditor.this.name); AnimationObjectEditor editor = new AnimationObjectEditor(TimelineEditor.this.res, o, t.getDuration()); if(x > -1) { editor.updatePosition(x, y, startingPoint); } int ok = JOptionPane.showConfirmDialog(TimelineEditor.this, editor, "Edit", JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE); if(ok == JOptionPane.OK_OPTION) { if(index < 0) { return; } dl.setElementAt(editor.getAnimationObject(), index); AnimationObject[] animations = new AnimationObject[t.getAnimationCount()]; for(int iter = 0 ; iter < animations.length ; iter++) { animations[iter] = t.getAnimation(iter); } animations[index] = editor.getAnimationObject(); boolean paused = t.isPause(); int oldTime = t.getTime(); t = Timeline.createTimeline(getValue(duration), animations, new com.codename1.ui.geom.Dimension(getValue(width), getValue(height))); t.setPause(paused); t.setTime(oldTime); setImage(t); } } public void setImage(com.codename1.ui.animations.Timeline image) { animationPanel.removeAll(); AnimationObjectTableModel model = (AnimationObjectTableModel)animationObjectList.getModel(); model.updateTimeline(image); /*for(int iter = 0 ; iter < image.getAnimationCount() ; iter++) { model.addElement(image.getAnimation(iter)); }*/ renderer = new CodenameOneImageRenderer(image); renderer.setAnimationObjectList(animationObjectList, this); animationPanel.add(BorderLayout.CENTER, renderer); animationPanel.revalidate(); if(image != res.getImage(name)) { res.setImage(name, image); } timeline.setMaximum(image.getDuration()); duration.setValue(image.getDuration()); endTime.setText("" + image.getDuration()); width.setValue(image.getWidth()); height.setValue(image.getHeight()); } /** This method is called from within the constructor to * initialize the form. * WARNING: Do NOT modify this code. The content of this method is * always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() { jSplitPane1 = new javax.swing.JSplitPane(); animationPanel = new javax.swing.JPanel(); jPanel3 = new javax.swing.JPanel(); propertiesTab = new javax.swing.JTabbedPane(); jPanel1 = new javax.swing.JPanel(); jLabel1 = new javax.swing.JLabel(); jLabel2 = new javax.swing.JLabel(); duration = new javax.swing.JSpinner(); width = new javax.swing.JSpinner(); jLabel4 = new javax.swing.JLabel(); height = new javax.swing.JSpinner(); jPanel2 = new javax.swing.JPanel(); jScrollPane2 = new javax.swing.JScrollPane(); animationObjectList = new javax.swing.JTable(); addAnimationObject = new javax.swing.JButton(); removeAnimationObject = new javax.swing.JButton(); duplicateObject = new javax.swing.JButton(); moveUp = new javax.swing.JButton(); moveDown = new javax.swing.JButton(); jScrollPane1 = new javax.swing.JScrollPane(); help = new javax.swing.JTextPane(); play = new javax.swing.JButton(); pause = new javax.swing.JButton(); timeline = new javax.swing.JSlider(); currentTime = new javax.swing.JLabel(); endTime = new javax.swing.JLabel(); FormListener formListener = new FormListener(); setName("Form"); // NOI18N setOpaque(false); jSplitPane1.setName("jSplitPane1"); // NOI18N animationPanel.setName("animationPanel"); // NOI18N animationPanel.setLayout(new java.awt.BorderLayout()); jSplitPane1.setLeftComponent(animationPanel); jPanel3.setName("jPanel3"); // NOI18N propertiesTab.setName("propertiesTab"); // NOI18N jPanel1.setName("jPanel1"); // NOI18N jPanel1.setOpaque(false); jLabel1.setText("Duration"); jLabel1.setName("jLabel1"); // NOI18N jLabel2.setText("Width"); jLabel2.setName("jLabel2"); // NOI18N duration.setName("duration"); // NOI18N duration.addChangeListener(formListener); width.setName("width"); // NOI18N width.addChangeListener(formListener); jLabel4.setText("Height"); jLabel4.setName("jLabel4"); // NOI18N height.setName("height"); // NOI18N height.addChangeListener(formListener); org.jdesktop.layout.GroupLayout jPanel1Layout = new org.jdesktop.layout.GroupLayout(jPanel1); jPanel1.setLayout(jPanel1Layout); jPanel1Layout.setHorizontalGroup( jPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) .add(jPanel1Layout.createSequentialGroup() .addContainerGap() .add(jPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) .add(jLabel1) .add(jLabel2) .add(jLabel4)) .add(33, 33, 33) .add(jPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) .add(width, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 453, Short.MAX_VALUE) .add(duration, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 453, Short.MAX_VALUE) .add(height, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 453, Short.MAX_VALUE)) .addContainerGap()) ); jPanel1Layout.setVerticalGroup( jPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) .add(jPanel1Layout.createSequentialGroup() .addContainerGap() .add(jPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) .add(jLabel1) .add(duration, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .add(jPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) .add(jLabel2) .add(width, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .add(jPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) .add(jLabel4) .add(height, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) .addContainerGap(175, Short.MAX_VALUE)) ); propertiesTab.addTab("Timeline", jPanel1); jPanel2.setName("jPanel2"); // NOI18N jPanel2.setOpaque(false); jScrollPane2.setName("jScrollPane2"); // NOI18N animationObjectList.setName("animationObjectList"); // NOI18N jScrollPane2.setViewportView(animationObjectList); addAnimationObject.setText("Add"); addAnimationObject.setName("addAnimationObject"); // NOI18N addAnimationObject.addActionListener(formListener); removeAnimationObject.setText("Remove"); removeAnimationObject.setEnabled(false); removeAnimationObject.setName("removeAnimationObject"); // NOI18N removeAnimationObject.addActionListener(formListener); duplicateObject.setText("Duplicate"); duplicateObject.setEnabled(false); duplicateObject.setName("duplicateObject"); // NOI18N duplicateObject.addActionListener(formListener); moveUp.setText("Move Up"); moveUp.setEnabled(false); moveUp.setName("moveUp"); // NOI18N moveUp.addActionListener(formListener); moveDown.setText("Move Down"); moveDown.setEnabled(false); moveDown.setName("moveDown"); // NOI18N moveDown.addActionListener(formListener); org.jdesktop.layout.GroupLayout jPanel2Layout = new org.jdesktop.layout.GroupLayout(jPanel2); jPanel2.setLayout(jPanel2Layout); jPanel2Layout.setHorizontalGroup( jPanel2Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) .add(jPanel2Layout.createSequentialGroup() .addContainerGap() .add(addAnimationObject) .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .add(removeAnimationObject) .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .add(duplicateObject) .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .add(moveUp) .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .add(moveDown) .addContainerGap(68, Short.MAX_VALUE)) .add(jPanel2Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) .add(org.jdesktop.layout.GroupLayout.TRAILING, jScrollPane2, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 547, Short.MAX_VALUE)) ); jPanel2Layout.linkSize(new java.awt.Component[] {addAnimationObject, duplicateObject, moveDown, moveUp, removeAnimationObject}, org.jdesktop.layout.GroupLayout.HORIZONTAL); jPanel2Layout.setVerticalGroup( jPanel2Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) .add(org.jdesktop.layout.GroupLayout.TRAILING, jPanel2Layout.createSequentialGroup() .addContainerGap(224, Short.MAX_VALUE) .add(jPanel2Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) .add(addAnimationObject) .add(removeAnimationObject) .add(duplicateObject) .add(moveUp) .add(moveDown)) .addContainerGap()) .add(jPanel2Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) .add(jPanel2Layout.createSequentialGroup() .add(jScrollPane2, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 214, Short.MAX_VALUE) .add(44, 44, 44))) ); propertiesTab.addTab("Objects", jPanel2); jScrollPane1.setName("jScrollPane1"); // NOI18N help.setContentType("text/html"); help.setEditable(false); help.setText("<html>\r\n <head>\r\n\r\n </head>\r\n <body>\r\n <p style=\"margin-top: 0\">\r\n \rA timeline is a simple repeating animation that allows us to create portable visual effects based \non moving/manipulating images (referenced as objects in timeline terminology). A timeline isn't designed for creation of elaborate effects and is mostly designed for simple splash screen/progress indication animations.\n </p>\n <p>\nA timeline has a size and duration, while the duration is fixed the size is used to calculate the ratio \nto image sizes. When a timeline is scaled it will sclae the images within it as well and position them in\na scaled location (e.g. an image positioned in 50,50 for a 100,100 timeline will be in 160x160 when the timeline is scaled to 320x320 resolution).\n </p>\r\n <p>\nA timeline is manipuated by adding objects and defining their internal positions/behaviors during a portion of the timeline. \n </p>\n </body>\r\n</html>\r\n"); // NOI18N help.setName("help"); // NOI18N jScrollPane1.setViewportView(help); propertiesTab.addTab("Help", jScrollPane1); play.setText("Play"); play.setName("play"); // NOI18N play.addActionListener(formListener); pause.setText("Pause"); pause.setEnabled(false); pause.setName("pause"); // NOI18N pause.addActionListener(formListener); org.jdesktop.layout.GroupLayout jPanel3Layout = new org.jdesktop.layout.GroupLayout(jPanel3); jPanel3.setLayout(jPanel3Layout); jPanel3Layout.setHorizontalGroup( jPanel3Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) .add(jPanel3Layout.createSequentialGroup() .addContainerGap() .add(play) .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .add(pause) .addContainerGap(422, Short.MAX_VALUE)) .add(jPanel3Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) .add(propertiesTab, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 552, Short.MAX_VALUE)) ); jPanel3Layout.setVerticalGroup( jPanel3Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) .add(org.jdesktop.layout.GroupLayout.TRAILING, jPanel3Layout.createSequentialGroup() .addContainerGap(297, Short.MAX_VALUE) .add(jPanel3Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) .add(play) .add(pause)) .addContainerGap()) .add(jPanel3Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) .add(jPanel3Layout.createSequentialGroup() .add(propertiesTab, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 286, Short.MAX_VALUE) .add(45, 45, 45))) ); jSplitPane1.setRightComponent(jPanel3); timeline.setMaximum(20000); timeline.setValue(0); timeline.setName("timeline"); // NOI18N timeline.addChangeListener(formListener); currentTime.setText("0"); currentTime.setName("currentTime"); // NOI18N endTime.setText("20000"); endTime.setName("endTime"); // NOI18N org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) .add(org.jdesktop.layout.GroupLayout.TRAILING, layout.createSequentialGroup() .addContainerGap() .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING) .add(org.jdesktop.layout.GroupLayout.LEADING, jSplitPane1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 559, Short.MAX_VALUE) .add(layout.createSequentialGroup() .add(currentTime) .add(18, 18, 18) .add(timeline, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 487, Short.MAX_VALUE) .add(18, 18, 18) .add(endTime))) .addContainerGap()) ); layout.setVerticalGroup( layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) .add(org.jdesktop.layout.GroupLayout.TRAILING, layout.createSequentialGroup() .addContainerGap() .add(jSplitPane1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 333, Short.MAX_VALUE) .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING) .add(currentTime) .add(endTime) .add(timeline, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) .addContainerGap()) ); } // Code for dispatching events from components to event handlers. private class FormListener implements java.awt.event.ActionListener, javax.swing.event.ChangeListener { FormListener() {} public void actionPerformed(java.awt.event.ActionEvent evt) { if (evt.getSource() == addAnimationObject) { TimelineEditor.this.addAnimationObjectActionPerformed(evt); } else if (evt.getSource() == removeAnimationObject) { TimelineEditor.this.removeAnimationObjectActionPerformed(evt); } else if (evt.getSource() == duplicateObject) { TimelineEditor.this.duplicateObjectActionPerformed(evt); } else if (evt.getSource() == moveUp) { TimelineEditor.this.moveUpActionPerformed(evt); } else if (evt.getSource() == moveDown) { TimelineEditor.this.moveDownActionPerformed(evt); } else if (evt.getSource() == play) { TimelineEditor.this.playActionPerformed(evt); } else if (evt.getSource() == pause) { TimelineEditor.this.pauseActionPerformed(evt); } } public void stateChanged(javax.swing.event.ChangeEvent evt) { if (evt.getSource() == duration) { TimelineEditor.this.durationStateChanged(evt); } else if (evt.getSource() == width) { TimelineEditor.this.widthStateChanged(evt); } else if (evt.getSource() == height) { TimelineEditor.this.heightStateChanged(evt); } else if (evt.getSource() == timeline) { TimelineEditor.this.timelineStateChanged(evt); } } }// </editor-fold>//GEN-END:initComponents private Timeline cloneCurrentTimeline() { Timeline t = (Timeline)res.getImage(name); AnimationObject[] arr = new AnimationObject[t.getAnimationCount()]; for(int iter = 0 ; iter < arr.length ; iter++) { arr[iter] = t.getAnimation(iter); } Timeline nt = Timeline.createTimeline(getValue(duration), arr, new com.codename1.ui.geom.Dimension(getValue(width), getValue(height))); nt.setPause(t.isPause()); nt.setTime(t.getTime()); return nt; } private void durationStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_durationStateChanged int d = getValue(duration); if(d != ((Timeline)renderer.getImage()).getDuration()) { com.codename1.ui.animations.Timeline t = cloneCurrentTimeline(); endTime.setText("" + d); timeline.setMaximum(d); res.setImage(name, t); setImage(t); } }//GEN-LAST:event_durationStateChanged private void widthStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_widthStateChanged int w = getValue(width); if(w != renderer.getImage().getWidth()) { com.codename1.ui.animations.Timeline t = cloneCurrentTimeline(); renderer.getImage().scaled(w, renderer.getImage().getHeight()); res.setImage(name, t); setImage(t); renderer.revalidate(); renderer.repaint(); } }//GEN-LAST:event_widthStateChanged private void heightStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_heightStateChanged int h = getValue(height); if(h != renderer.getImage().getHeight()) { com.codename1.ui.animations.Timeline t = cloneCurrentTimeline(); renderer.getImage().scaled(renderer.getImage().getWidth(), h); res.setImage(name, t); setImage(t); renderer.revalidate(); renderer.repaint(); } }//GEN-LAST:event_heightStateChanged private void timelineStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_timelineStateChanged currentTime.setText("" + timeline.getValue()); if(!refreshingTimelineLock) { Timeline t = (Timeline)renderer.getImage(); t.setPause(false); t.setTime(timeline.getValue()); renderer.updateAnimation(); t.setPause(true); } }//GEN-LAST:event_timelineStateChanged private boolean refreshingTimelineLock; private void playActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_playActionPerformed final Timeline t = (Timeline)renderer.getImage(); t.setPause(false); play.setEnabled(false); pause.setEnabled(true); refreshTimeline = new javax.swing.Timer(500, new ActionListener() { public void actionPerformed(ActionEvent e) { if(t.isPause()) { pause.setEnabled(false); play.setEnabled(true); refreshTimeline.stop(); refreshTimeline = null; return; } refreshingTimelineLock = true; timeline.setValue(t.getTime()); refreshingTimelineLock = false; } }); refreshTimeline.setRepeats(true); refreshTimeline.start(); }//GEN-LAST:event_playActionPerformed private void pauseActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_pauseActionPerformed Timeline t = (Timeline)renderer.getImage(); t.setPause(true); play.setEnabled(true); pause.setEnabled(false); if(refreshTimeline != null) { refreshTimeline.stop(); refreshTimeline = null; } }//GEN-LAST:event_pauseActionPerformed private int getValue(JSpinner s) { return ((Number)s.getValue()).intValue(); } private void addAnimationObjectActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_addAnimationObjectActionPerformed AnimationObjectEditor editor = new AnimationObjectEditor(res, null, getValue(duration)); editor.setStartTime(timeline.getValue()); int ok = JOptionPane.showConfirmDialog(this, editor, "Add", JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE); if(ok == JOptionPane.OK_OPTION) { ((AnimationObjectTableModel)animationObjectList.getModel()).addElement(editor.getAnimationObject()); Timeline t = (Timeline)res.getImage(name); AnimationObject[] animations = new AnimationObject[t.getAnimationCount() + 1]; for(int iter = 0 ; iter < animations.length - 1 ; iter++) { animations[iter] = t.getAnimation(iter); } animations[animations.length - 1] = editor.getAnimationObject(); Timeline nt = Timeline.createTimeline(getValue(duration), animations, new com.codename1.ui.geom.Dimension(getValue(width), getValue(height))); nt.setPause(t.isPause()); nt.setTime(t.getTime()); setImage(nt); } }//GEN-LAST:event_addAnimationObjectActionPerformed private void removeAnimationObjectActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_removeAnimationObjectActionPerformed Timeline t = (Timeline)res.getImage(name); AnimationObject[] animations = new AnimationObject[t.getAnimationCount() - 1]; int offset = 0; for(int iter = 0 ; iter < t.getAnimationCount() ; iter++) { if(iter != animationObjectList.getSelectedRow()) { animations[offset] = t.getAnimation(iter); offset++; } } ((AnimationObjectTableModel)animationObjectList.getModel()).remove(animationObjectList.getSelectedRow()); Timeline nt = Timeline.createTimeline(getValue(duration), animations, new com.codename1.ui.geom.Dimension(getValue(width), getValue(height))); nt.setPause(t.isPause()); setImage(nt); animationObjectList.clearSelection(); duplicateObject.setEnabled(false); moveDown.setEnabled(false); moveUp.setEnabled(false); removeAnimationObject.setEnabled(false); }//GEN-LAST:event_removeAnimationObjectActionPerformed private void duplicateObjectActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_duplicateObjectActionPerformed Timeline t = cloneCurrentTimeline(); AnimationObject o = AnimationAccessor.clone((AnimationObject)((AnimationObjectTableModel)animationObjectList.getModel()).getElementAt(animationObjectList.getSelectedRow())); ((AnimationObjectTableModel)animationObjectList.getModel()).addElement(o); AnimationObject[] animations = new AnimationObject[t.getAnimationCount() + 1]; for(int iter = 0 ; iter < animations.length - 1 ; iter++) { animations[iter] = t.getAnimation(iter); } animations[animations.length - 1] = o; Timeline nt = Timeline.createTimeline(getValue(duration), animations, new com.codename1.ui.geom.Dimension(getValue(width), getValue(height))); nt.setPause(t.isPause()); setImage(nt); animationObjectList.clearSelection(); duplicateObject.setEnabled(false); moveDown.setEnabled(false); moveUp.setEnabled(false); removeAnimationObject.setEnabled(false); }//GEN-LAST:event_duplicateObjectActionPerformed private void moveUpActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_moveUpActionPerformed int i = animationObjectList.getSelectedRow(); Timeline t = cloneCurrentTimeline(); AnimationObject[] animations = new AnimationObject[t.getAnimationCount()]; for(int iter = 0 ; iter < animations.length ; iter++) { animations[iter] = t.getAnimation(iter); } AnimationObject o = animations[i - 1]; animations[i - 1] = animations[i]; animations[i] = o; Timeline nt = Timeline.createTimeline(getValue(duration), animations, new com.codename1.ui.geom.Dimension(getValue(width), getValue(height))); nt.setPause(t.isPause()); setImage(nt); moveUp.setEnabled(i > 1); moveDown.setEnabled(true); animationObjectList.getSelectionModel().setSelectionInterval(i - 1, i -1); }//GEN-LAST:event_moveUpActionPerformed private void moveDownActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_moveDownActionPerformed int i = animationObjectList.getSelectedRow(); Timeline t = cloneCurrentTimeline(); AnimationObject[] animations = new AnimationObject[t.getAnimationCount()]; for(int iter = 0 ; iter < animations.length ; iter++) { animations[iter] = t.getAnimation(iter); } AnimationObject o = animations[i + 1]; animations[i + 1] = animations[i]; animations[i] = o; Timeline nt = Timeline.createTimeline(getValue(duration), animations, new com.codename1.ui.geom.Dimension(getValue(width), getValue(height))); nt.setPause(t.isPause()); setImage(nt); moveDown.setEnabled(i < animations.length - 1); moveUp.setEnabled(true); animationObjectList.getSelectionModel().setSelectionInterval(i + 1, i + 1); }//GEN-LAST:event_moveDownActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton addAnimationObject; private javax.swing.JTable animationObjectList; private javax.swing.JPanel animationPanel; private javax.swing.JLabel currentTime; private javax.swing.JButton duplicateObject; private javax.swing.JSpinner duration; private javax.swing.JLabel endTime; private javax.swing.JSpinner height; private javax.swing.JTextPane help; private javax.swing.JLabel jLabel1; private javax.swing.JLabel jLabel2; private javax.swing.JLabel jLabel4; private javax.swing.JPanel jPanel1; private javax.swing.JPanel jPanel2; private javax.swing.JPanel jPanel3; private javax.swing.JScrollPane jScrollPane1; private javax.swing.JScrollPane jScrollPane2; private javax.swing.JSplitPane jSplitPane1; private javax.swing.JButton moveDown; private javax.swing.JButton moveUp; private javax.swing.JButton pause; private javax.swing.JButton play; private javax.swing.JTabbedPane propertiesTab; private javax.swing.JButton removeAnimationObject; private javax.swing.JSlider timeline; private javax.swing.JSpinner width; // End of variables declaration//GEN-END:variables }