diff --git a/jme3-assetbrowser/build.xml b/jme3-assetbrowser/build.xml new file mode 100644 index 000000000..97de6a221 --- /dev/null +++ b/jme3-assetbrowser/build.xml @@ -0,0 +1,8 @@ + + + + + + Builds, tests, and runs the project com.jme3.assetbrowser. + + diff --git a/jme3-assetbrowser/manifest.mf b/jme3-assetbrowser/manifest.mf new file mode 100644 index 000000000..87b1d0b18 --- /dev/null +++ b/jme3-assetbrowser/manifest.mf @@ -0,0 +1,7 @@ +Manifest-Version: 1.0 +AutoUpdate-Show-In-Client: true +OpenIDE-Module: com.jme3.gde.assetbrowser +OpenIDE-Module-Localizing-Bundle: com/jme3/gde/assetbrowser/Bundle.properties +OpenIDE-Module-Requires: org.openide.windows.WindowManager +OpenIDE-Module-Specification-Version: 1.0 + diff --git a/jme3-assetbrowser/nbproject/build-impl.xml b/jme3-assetbrowser/nbproject/build-impl.xml new file mode 100644 index 000000000..081c3f289 --- /dev/null +++ b/jme3-assetbrowser/nbproject/build-impl.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + You must set 'suite.dir' to point to your containing module suite + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/jme3-assetbrowser/nbproject/genfiles.properties b/jme3-assetbrowser/nbproject/genfiles.properties new file mode 100644 index 000000000..7690ae5fb --- /dev/null +++ b/jme3-assetbrowser/nbproject/genfiles.properties @@ -0,0 +1,8 @@ +build.xml.data.CRC32=9efa5489 +build.xml.script.CRC32=f284e28d +build.xml.stylesheet.CRC32=15ca8a54@2.91 +# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml. +# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you. +nbproject/build-impl.xml.data.CRC32=37385f23 +nbproject/build-impl.xml.script.CRC32=a691b4aa +nbproject/build-impl.xml.stylesheet.CRC32=49aa68b0@2.91 diff --git a/jme3-assetbrowser/nbproject/project.properties b/jme3-assetbrowser/nbproject/project.properties new file mode 100644 index 000000000..7312cafeb --- /dev/null +++ b/jme3-assetbrowser/nbproject/project.properties @@ -0,0 +1,7 @@ +#Thu, 25 Aug 2011 20:26:49 +0200 +javac.source=17 +javac.compilerargs=-Xlint -Xlint:-serial +license.file=../license-jme.txt +nbm.homepage=https://www.jmonkeyengine.org +nbm.module.author=Normen Hansen +nbm.needs.restart=true diff --git a/jme3-assetbrowser/nbproject/project.xml b/jme3-assetbrowser/nbproject/project.xml new file mode 100644 index 000000000..4db2ce9be --- /dev/null +++ b/jme3-assetbrowser/nbproject/project.xml @@ -0,0 +1,260 @@ + + + org.netbeans.modules.apisupport.project + + + com.jme3.gde.assetbrowser + + + + com.jme3.gde.core + + + + 1 + 3.6.0 + + + + com.jme3.gde.materials + + + + 1 + 3.6.0 + + + + com.jme3.gde.scenecomposer + + + + 1 + 3.6.0 + + + + com.jme3.gde.textureeditor + + + + 1 + 3.6.0 + + + + com.jme3.gde.core.baselibs + + + + 1 + 3.6.0 + + + + com.jme3.gde.core.libraries + + + + 1 + 3.6.0 + + + + org.netbeans.api.templates + + + + 1.6.1 + + + + org.netbeans.api.visual + + + + 2.43.1 + + + + org.netbeans.core.multiview + + + + 1 + 1.40.1 + + + + org.netbeans.modules.editor.document + + + + 1.5.1.1 + + + + org.netbeans.modules.editor.lib + + + + 3 + 3.49.2.22.43 + + + + org.netbeans.modules.projectapi + + + + 1 + 1.60.2 + + + + org.netbeans.modules.projectuiapi + + + + 1 + 1.78.1.8 + + + + org.netbeans.modules.settings + + + + 1 + 1.45.1 + + + + org.netbeans.modules.websvc.jaxws21api + + + + 1 + 1.34.1 + + + + org.netbeans.spi.navigator + + + + 1 + 1.33.1 + + + + org.openide.actions + + + + 6.38.1 + + + + org.openide.awt + + + + 7.62.1 + + + + org.openide.dialogs + + + + 7.38.1 + + + + org.openide.explorer + + + + 6.57.1 + + + + org.openide.filesystems + + + + 9.7.1 + + + + org.openide.filesystems.nb + + + + 9.7.1 + + + + org.openide.loaders + + + + 7.57.2 + + + + org.openide.nodes + + + + 7.39.1 + + + + org.openide.text + + + + 6.62.2 + + + + org.openide.util + + + + 8.39.1 + + + + org.openide.util.lookup + + + + 8.25.1 + + + + org.openide.util.ui + + + + 9.4.1 + + + + org.openide.windows + + + + 6.71.1 + + + + + com.jme3.gde.assetBrowser + + + + diff --git a/jme3-assetbrowser/nbproject/suite.properties b/jme3-assetbrowser/nbproject/suite.properties new file mode 100644 index 000000000..29d7cc9bd --- /dev/null +++ b/jme3-assetbrowser/nbproject/suite.properties @@ -0,0 +1 @@ +suite.dir=${basedir}/.. diff --git a/jme3-assetbrowser/src/com/jme3/gde/assetbrowser/AssetBrowser.form b/jme3-assetbrowser/src/com/jme3/gde/assetbrowser/AssetBrowser.form new file mode 100644 index 000000000..2e1db28ea --- /dev/null +++ b/jme3-assetbrowser/src/com/jme3/gde/assetbrowser/AssetBrowser.form @@ -0,0 +1,155 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/jme3-assetbrowser/src/com/jme3/gde/assetbrowser/AssetBrowser.java b/jme3-assetbrowser/src/com/jme3/gde/assetbrowser/AssetBrowser.java new file mode 100644 index 000000000..7f4f06757 --- /dev/null +++ b/jme3-assetbrowser/src/com/jme3/gde/assetbrowser/AssetBrowser.java @@ -0,0 +1,548 @@ +/* + * Copyright (c) 2009-2023 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.gde.assetbrowser; + +import com.jme3.gde.assetbrowser.icons.Icons; +import com.jme3.gde.assetbrowser.widgets.AssetPreviewWidget; +import com.jme3.gde.assetbrowser.widgets.MatDefPreview; +import com.jme3.gde.assetbrowser.widgets.MaterialPreview; +import com.jme3.gde.assetbrowser.widgets.ModelPreview; +import com.jme3.gde.assetbrowser.widgets.PreviewInteractionListener; +import com.jme3.gde.assetbrowser.widgets.SoundPreview; +import com.jme3.gde.assetbrowser.widgets.TexturePreview; +import com.jme3.gde.core.assets.BinaryModelDataObject; +import com.jme3.gde.core.assets.ProjectAssetManager; +import com.jme3.gde.core.util.ProjectSelection; +import com.jme3.gde.materials.JMEMaterialDataObject; +import com.jme3.gde.materials.multiview.MaterialOpenSupport; +import com.jme3.gde.scenecomposer.OpenSceneComposer; +import com.jme3.gde.scenecomposer.SceneComposerTopComponent; +import com.jme3.gde.textureeditor.JmeTextureDataObject; +import com.jme3.gde.textureeditor.OpenTexture; +import com.jme3.scene.Spatial; +import java.awt.Dimension; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.event.ComponentEvent; +import java.awt.event.ComponentListener; +import java.awt.event.KeyEvent; +import java.io.File; +import java.io.IOException; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; +import javax.swing.JOptionPane; +import org.netbeans.api.project.Project; +import org.openide.DialogDisplayer; +import org.openide.NotifyDescriptor; +import org.openide.filesystems.FileAttributeEvent; +import org.openide.filesystems.FileChangeListener; +import org.openide.filesystems.FileEvent; +import org.openide.filesystems.FileObject; +import org.openide.filesystems.FileRenameEvent; +import org.openide.loaders.DataObject; +import org.openide.loaders.DataObjectNotFoundException; +import org.openide.util.Exceptions; + +/** + * Top component for AssetBrowser + * + * @author rickard + */ +public class AssetBrowser extends javax.swing.JPanel implements PreviewInteractionListener { + + private static final String MATERIALS = "Materials"; + private static final String MAT_DEFS = "MatDefs"; + private static final String MODELS = "Models"; + private static final String TEXTURES = "Textures"; + private static final String SOUNDS = "Sounds"; + private ProjectAssetManager assetManager; + private PreviewHelper previewUtil; + private String projectName; + + private int lastGridColumns = 0; + private int lastGridRows = 0; + private String lastFilter; + + private int sizeX = Constants.sizeX; + private int sizeY = Constants.sizeY; + private int imageSize = Constants.imageSize; + private int oldSliderValue = 2; + + private boolean componentListenerAdded = false; + private ComponentListener resizeListener = new ComponentListener() { + @Override + public void componentResized(ComponentEvent e) { + setSize(getParent().getSize()); + setPreferredSize(getParent().getSize()); + getLayout().layoutContainer(AssetBrowser.this); + java.awt.EventQueue.invokeLater(() -> { + + loadAssets(lastFilter); + + }); + } + + @Override + public void componentMoved(ComponentEvent e) { +// setSize(new Dimension(0,0)); + } + + @Override + public void componentShown(ComponentEvent e) { + } + + @Override + public void componentHidden(ComponentEvent e) { + } + }; + + /** + * Creates new form AssetBrowser + */ + public AssetBrowser() { + + initComponents(); + + addComponentListener(resizeListener); + } + + /** + * Will recalculate grid, and remove all previews and regenerate if rows or + * columns or filter has changed + * + * @param filter only show previews containing filter + */ + private void loadAssets(String filter) { + if (assetManager == null) { + return; + } + + // this is required to make the panel resize + if (!componentListenerAdded && getParent() != null) { + getParent().addComponentListener(resizeListener); + componentListenerAdded = true; + removeComponentListener(resizeListener); + } + Dimension size = previewsPanel.getSize(); + + int rows = Math.min(size.height, getHeight() - 30) / sizeY; + + final var textures = Arrays.stream(assetManager.getTextures()).filter(s -> filter.isEmpty() || s.toLowerCase().contains(filter)).collect(Collectors.toList()); + final var materials = Arrays.stream(assetManager.getMaterials()).filter(s -> filter.isEmpty() || s.toLowerCase().contains(filter)).collect(Collectors.toList()); + final var models = Arrays.stream(assetManager.getModels()).filter(s -> filter.isEmpty() || s.toLowerCase().contains(filter)).collect(Collectors.toList()); + final var sounds = Arrays.stream(assetManager.getSounds()).filter(s -> filter.isEmpty() || s.toLowerCase().contains(filter)).collect(Collectors.toList()); + final var matdefs = Arrays.stream(assetManager.getMatDefs()).filter(s -> filter.isEmpty() || s.toLowerCase().contains(filter)).collect(Collectors.toList()); + int numAssets = textures.size() + materials.size() + models.size() + sounds.size() + matdefs.size(); + int columns = Math.max(numAssets / rows, 1); + + Dimension newSize = new Dimension(columns * sizeX, rows * sizeY); + if (columns != lastGridColumns || rows != lastGridRows || !lastFilter.equals(filter)) { + GridBagConstraints constraints = new GridBagConstraints(); + previewsPanel.setLayout(new GridBagLayout()); + constraints.fill = GridBagConstraints.BOTH; + constraints.gridx = sizeX; + constraints.gridy = sizeY; + previewsPanel.removeAll(); + previewsPanel.setSize(newSize); + previewsPanel.setPreferredSize(newSize); + + previewsPanel.setLayout(new GridBagLayout()); + + int index = addAssets(textures, TEXTURES, constraints, columns, rows, 0); + index = addAssets(materials, MATERIALS, constraints, columns, rows, index); + index = addAssets(models, MODELS, constraints, columns, rows, index); + index = addAssets(sounds, SOUNDS, constraints, columns, rows, index); + index = addAssets(matdefs, MAT_DEFS, constraints, columns, rows, index); + lastGridColumns = columns; + lastGridRows = rows; + lastFilter = filter; + } + } + + /** + * Add assets of a specific type to the grid + * + * @param items the assets to preview + * @param type type of asset + * @param constraints + * @param columns columns in the grid + * @param rows rows in the grid + * @param startIndex last used index when adding previews + * @return + */ + private int addAssets(List items, String type, GridBagConstraints constraints, int columns, int rows, int startIndex) { + Collections.sort(items); + int index = startIndex; + for (String item : items) { + AssetPreviewWidget preview = null; + + constraints.gridx = index % columns; + constraints.gridy = (int) (((float) index-1) / (columns)); + if (type.startsWith(TEXTURES)) { + preview = new TexturePreview(this, previewUtil.getOrCreateTexturePreview(item, imageSize)); + } else if (type.startsWith(MATERIALS)) { + preview = new MaterialPreview(this); + preview.setPreviewImage(previewUtil.getOrCreateMaterialPreview(item, preview, imageSize)); + } else if (type.startsWith(MODELS)) { + preview = new ModelPreview(this); + preview.setPreviewImage(previewUtil.getOrCreateModelPreview(item, preview, imageSize)); + } else if (type.startsWith(SOUNDS)) { + preview = new SoundPreview(this, previewUtil.getSoundPreview(item, imageSize)); + } else if (type.startsWith(MAT_DEFS)) { + preview = new MatDefPreview(this, previewUtil.getDefaultIcon(item, imageSize)); + } + if (preview == null) { + continue; + } + preview.setMinimumSize(new Dimension(sizeX, sizeY)); + preview.setPreferredSize(new Dimension(sizeX, sizeY)); + if (assetManager.getAbsoluteAssetPath(item) != null) { + preview.setEditable(true); + } + preview.setPreviewName(item); + previewsPanel.add(preview, constraints); + index++; + } + return index; + } + + /** + * Creates the base folder for previews in the project directory + * + * @param assetManager + */ + private void createAssetBrowserFolder(ProjectAssetManager assetManager) { + final FileObject fileObject = assetManager.getProject().getProjectDirectory(); + + final String path = assetManager.isGradleProject() ? + fileObject.getParent().getPath() : fileObject.getPath(); + + final File file = new File(path, ".assetBrowser/"); + if (!file.exists()) { + file.mkdirs(); + } + } + + + /** + * 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") + // //GEN-BEGIN:initComponents + private void initComponents() { + + projectLabel = new javax.swing.JLabel(); + jScrollPane1 = new javax.swing.JScrollPane(); + previewsPanel = new javax.swing.JPanel(); + jPanel2 = new javax.swing.JPanel(); + filterField = new javax.swing.JTextField(); + clearFilterButton = new javax.swing.JButton(); + filler1 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 0), new java.awt.Dimension(32767, 0)); + sizeSlider = new javax.swing.JSlider(); + + setAlignmentX(0.0F); + setAlignmentY(0.0F); + setPreferredSize(new java.awt.Dimension(2000, 2000)); + setLayout(new javax.swing.BoxLayout(this, javax.swing.BoxLayout.PAGE_AXIS)); + + projectLabel.setHorizontalAlignment(javax.swing.SwingConstants.LEFT); + org.openide.awt.Mnemonics.setLocalizedText(projectLabel, org.openide.util.NbBundle.getMessage(AssetBrowser.class, "AssetBrowser.projectLabel.text")); // NOI18N + projectLabel.setVerticalAlignment(javax.swing.SwingConstants.TOP); + projectLabel.setAlignmentX(0.5F); + projectLabel.setAlignmentY(0.0F); + projectLabel.setHorizontalTextPosition(javax.swing.SwingConstants.LEADING); + projectLabel.setMaximumSize(new java.awt.Dimension(32000, 32000)); + projectLabel.addMouseListener(new java.awt.event.MouseAdapter() { + public void mouseClicked(java.awt.event.MouseEvent evt) { + projectLabelMouseClicked(evt); + } + }); + add(projectLabel); + + jScrollPane1.setMinimumSize(new java.awt.Dimension(150, 150)); + jScrollPane1.setPreferredSize(new java.awt.Dimension(2000, 3000)); + + previewsPanel.setPreferredSize(new java.awt.Dimension(200, 300)); + previewsPanel.setLayout(new java.awt.GridBagLayout()); + jScrollPane1.setViewportView(previewsPanel); + + add(jScrollPane1); + + jPanel2.setMaximumSize(new java.awt.Dimension(2147483647, 23)); + jPanel2.setMinimumSize(new java.awt.Dimension(104, 33)); + jPanel2.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.LEADING)); + + filterField.setText(org.openide.util.NbBundle.getMessage(AssetBrowser.class, "AssetBrowser.filterField.text")); // NOI18N + filterField.setToolTipText(org.openide.util.NbBundle.getMessage(AssetBrowser.class, "AssetBrowser.filterField.toolTipText")); // NOI18N + filterField.setMinimumSize(new java.awt.Dimension(40, 23)); + filterField.setPreferredSize(new java.awt.Dimension(250, 23)); + filterField.addFocusListener(new java.awt.event.FocusAdapter() { + public void focusLost(java.awt.event.FocusEvent evt) { + filterFieldFocusLost(evt); + } + }); + filterField.addMouseListener(new java.awt.event.MouseAdapter() { + public void mouseClicked(java.awt.event.MouseEvent evt) { + filterFieldMouseClicked(evt); + } + }); + filterField.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + filterFieldActionPerformed(evt); + } + }); + filterField.addKeyListener(new java.awt.event.KeyAdapter() { + public void keyPressed(java.awt.event.KeyEvent evt) { + filterFieldKeyPressed(evt); + } + }); + jPanel2.add(filterField); + + clearFilterButton.setIcon(Icons.clearFilter); + org.openide.awt.Mnemonics.setLocalizedText(clearFilterButton, org.openide.util.NbBundle.getMessage(AssetBrowser.class, "AssetBrowser.clearFilterButton.text")); // NOI18N + clearFilterButton.setMaximumSize(new java.awt.Dimension(23, 23)); + clearFilterButton.setMinimumSize(new java.awt.Dimension(23, 23)); + clearFilterButton.setPreferredSize(new java.awt.Dimension(23, 23)); + clearFilterButton.addMouseListener(new java.awt.event.MouseAdapter() { + public void mouseClicked(java.awt.event.MouseEvent evt) { + clearFilterButtonMouseClicked(evt); + } + }); + jPanel2.add(clearFilterButton); + jPanel2.add(filler1); + + sizeSlider.setMaximum(2); + sizeSlider.setToolTipText(org.openide.util.NbBundle.getMessage(AssetBrowser.class, "AssetBrowser.sizeSlider.toolTipText")); // NOI18N + sizeSlider.setName("sizeSlider"); // NOI18N + sizeSlider.setPreferredSize(new java.awt.Dimension(100, 20)); + sizeSlider.addChangeListener(new javax.swing.event.ChangeListener() { + public void stateChanged(javax.swing.event.ChangeEvent evt) { + sizeSliderStateChanged(evt); + } + }); + jPanel2.add(sizeSlider); + + add(jPanel2); + }// //GEN-END:initComponents + + /** + * Select project to view + * + * @param evt + */ + private void projectLabelMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_projectLabelMouseClicked + assetManager = ProjectSelection.getProjectAssetManager("Select project"); + projectName = assetManager.getProject().getProjectDirectory().getName(); + projectLabel.setText(projectName); + previewUtil = new PreviewHelper(assetManager); + createAssetBrowserFolder(assetManager); + // Check which assets was added/deleted/renamed/changed? Nah, just load + // everything! + assetManager.getAssetFolder().addRecursiveListener(new FileChangeListener() { + @Override + public void fileFolderCreated(FileEvent fe) { + loadAssets(lastFilter); + } + + @Override + public void fileDataCreated(FileEvent fe) { + loadAssets(lastFilter); + } + + @Override + public void fileChanged(FileEvent fe) { + loadAssets(lastFilter); + } + + @Override + public void fileDeleted(FileEvent fe) { + loadAssets(lastFilter); + } + + @Override + public void fileRenamed(FileRenameEvent fre) { + loadAssets(lastFilter); + } + + @Override + public void fileAttributeChanged(FileAttributeEvent fae) { + loadAssets(lastFilter); + } + }); + loadAssets(""); + }//GEN-LAST:event_projectLabelMouseClicked + + private void filterFieldFocusLost(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_filterFieldFocusLost + + }//GEN-LAST:event_filterFieldFocusLost + + private void filterFieldKeyPressed(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_filterFieldKeyPressed + if (evt.getKeyCode() == KeyEvent.VK_TAB || evt.getKeyCode() == KeyEvent.VK_ENTER) { + previewsPanel.requestFocusInWindow(); + loadAssets(filterField.getText().toLowerCase()); + } + }//GEN-LAST:event_filterFieldKeyPressed + + private void filterFieldMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_filterFieldMouseClicked + //filterField.setSelectionStart(0); + //filterField.setSelectionEnd(filterField.getSelectedText().length()); + }//GEN-LAST:event_filterFieldMouseClicked + + private void filterFieldActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_filterFieldActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_filterFieldActionPerformed + + /** + * Change size of previews + * + * @param evt + */ + private void sizeSliderStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_sizeSliderStateChanged + final var value = sizeSlider.getValue(); + switch (value) { + case 0: + sizeX = (int) (Constants.sizeX * 0.5f); + sizeY = (int) (Constants.sizeY * 0.5f); + imageSize = (int) (Constants.imageSize * 0.5f); + break; + case 1: + sizeX = (int) (Constants.sizeY * 0.75f); + sizeY = (int) (Constants.sizeX * 0.75f); + imageSize = (int) (Constants.imageSize * 0.75f); + break; + case 2: + sizeX = Constants.sizeY; + sizeY = Constants.sizeX; + imageSize = Constants.imageSize; + break; + } + if (value != oldSliderValue) { + loadAssets(lastFilter); + oldSliderValue = value; + } + }//GEN-LAST:event_sizeSliderStateChanged + + private void clearFilterButtonMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_clearFilterButtonMouseClicked + filterField.setText(""); + lastFilter = ""; + loadAssets(""); + }//GEN-LAST:event_clearFilterButtonMouseClicked + + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton clearFilterButton; + private javax.swing.Box.Filler filler1; + private javax.swing.JTextField filterField; + private javax.swing.JPanel jPanel2; + private javax.swing.JScrollPane jScrollPane1; + private javax.swing.JPanel previewsPanel; + private javax.swing.JLabel projectLabel; + private javax.swing.JSlider sizeSlider; + // End of variables declaration//GEN-END:variables + + /** + * Double click an asset to open it (if supported) + */ + @Override + public void openAsset(AssetPreviewWidget widget) { + FileObject pf = assetManager.getAssetFileObject(widget.getPreviewName()); + if (widget instanceof MaterialPreview) { + try { + JMEMaterialDataObject matObject = (JMEMaterialDataObject) DataObject.find(pf); + new MaterialOpenSupport(matObject.getPrimaryEntry()).open(); + } catch (IOException ex) { + Exceptions.printStackTrace(ex); + } + } else if (widget instanceof TexturePreview) { + try { + JmeTextureDataObject textureObject = (JmeTextureDataObject) DataObject.find(pf); + OpenTexture openTexture = new OpenTexture(textureObject); + openTexture.actionPerformed(null); + } catch (DataObjectNotFoundException ex) { + Exceptions.printStackTrace(ex); + } + + } else if (widget instanceof ModelPreview) { + try { + BinaryModelDataObject model = (BinaryModelDataObject) DataObject.find(pf); + Runnable call = () -> { + assetManager.clearCache(); + final Spatial asset = model.loadAsset(); + if (asset != null) { + java.awt.EventQueue.invokeLater(() -> { + SceneComposerTopComponent composer = SceneComposerTopComponent.findInstance(); + composer.openScene(asset, model, assetManager); + }); + } else { + NotifyDescriptor.Confirmation msg = new NotifyDescriptor.Confirmation( + "Error opening " + model.getPrimaryFile().getNameExt(), + NotifyDescriptor.OK_CANCEL_OPTION, + NotifyDescriptor.ERROR_MESSAGE); + DialogDisplayer.getDefault().notify(msg); + } + + }; + new Thread(call).start(); + } catch (DataObjectNotFoundException ex) { + Exceptions.printStackTrace(ex); + } + } else { + JOptionPane.showMessageDialog(null, "Not yet supported"); + } + } + + @Override + public void refreshPreview(AssetPreviewWidget widget) { + // not yet implemented + } + + /** + * Delete the asset + */ + @Override + public void deleteAsset(AssetPreviewWidget widget) { + int result = JOptionPane.showConfirmDialog(null, "Delete asset? " + widget.getAssetName()); + if (result == JOptionPane.OK_OPTION) { + FileObject pf = assetManager.getAssetFileObject(widget.getPreviewName()); + try { + pf.delete(); + } catch (IOException ex) { + Exceptions.printStackTrace(ex); + } + } + } + +} diff --git a/jme3-assetbrowser/src/com/jme3/gde/assetbrowser/AssetBrowserTopComponent.form b/jme3-assetbrowser/src/com/jme3/gde/assetbrowser/AssetBrowserTopComponent.form new file mode 100644 index 000000000..77d24fcba --- /dev/null +++ b/jme3-assetbrowser/src/com/jme3/gde/assetbrowser/AssetBrowserTopComponent.form @@ -0,0 +1,48 @@ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/jme3-assetbrowser/src/com/jme3/gde/assetbrowser/AssetBrowserTopComponent.java b/jme3-assetbrowser/src/com/jme3/gde/assetbrowser/AssetBrowserTopComponent.java new file mode 100644 index 000000000..670cf039c --- /dev/null +++ b/jme3-assetbrowser/src/com/jme3/gde/assetbrowser/AssetBrowserTopComponent.java @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2003-2023 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.gde.assetbrowser; + +import org.netbeans.api.settings.ConvertAsProperties; +import org.openide.awt.ActionID; +import org.openide.awt.ActionReference; +import org.openide.util.NbBundle; +import org.openide.windows.TopComponent; +import org.openide.util.NbBundle.Messages; + +/** + * Top component which displays something. + */ +@ConvertAsProperties( + dtd = "-//com.jme3.gde.assetbrowser//AssetBrowser//EN", + autostore = false +) +@TopComponent.Description( + preferredID = "AssetBrowserTopComponent", + //iconBase="SET/PATH/TO/ICON/HERE", + persistenceType = TopComponent.PERSISTENCE_ALWAYS +) +@TopComponent.Registration(mode = "navigator", openAtStartup = true) +@ActionID(category = "Window", id = "com.jme3.gde.assetbrowser.AssetBrowserTopComponent") +@ActionReference(path = "Menu/Window" /*, position = 333 */) +@TopComponent.OpenActionRegistration( + displayName = "#CTL_AssetBrowserAction", + preferredID = "AssetBrowserTopComponent" +) +//@Messages({ +// "CTL_AssetBrowserAction=AssetBrowser", +// "CTL_AssetBrowserTopComponent=AssetBrowser Window", +// "HINT_AssetBrowserTopComponent=This is a AssetBrowser window" +//}) +public final class AssetBrowserTopComponent extends TopComponent { + + public AssetBrowserTopComponent() { + initComponents(); + setName(NbBundle.getMessage(AssetBrowserTopComponent.class, "CTL_AssetBrowserTopComponent")); +// setName(Bundle.CTL_AssetBrowserTopComponent()); + setToolTipText(NbBundle.getMessage(AssetBrowserTopComponent.class, "HINT_AssetBrowserTopComponent")); + } + + /** + * 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. + */ + // //GEN-BEGIN:initComponents + private void initComponents() { + + assetBrowser1 = new com.jme3.gde.assetbrowser.AssetBrowser(); + + setLayout(new java.awt.BorderLayout()); + add(assetBrowser1, java.awt.BorderLayout.SOUTH); + }// //GEN-END:initComponents + + // Variables declaration - do not modify//GEN-BEGIN:variables + private com.jme3.gde.assetbrowser.AssetBrowser assetBrowser1; + // End of variables declaration//GEN-END:variables + @Override + public void componentOpened() { + // TODO add custom code on component opening + } + + @Override + public void componentClosed() { + // TODO add custom code on component closing + } + + void writeProperties(java.util.Properties p) { + // better to version settings since initial version as advocated at + // http://wiki.apidesign.org/wiki/PropertyFiles + p.setProperty("version", "1.0"); + // TODO store your settings + } + + void readProperties(java.util.Properties p) { + String version = p.getProperty("version"); + // TODO read your settings according to their version + } +} diff --git a/jme3-assetbrowser/src/com/jme3/gde/assetbrowser/Bundle.properties b/jme3-assetbrowser/src/com/jme3/gde/assetbrowser/Bundle.properties new file mode 100644 index 000000000..49e153588 --- /dev/null +++ b/jme3-assetbrowser/src/com/jme3/gde/assetbrowser/Bundle.properties @@ -0,0 +1,10 @@ +OpenIDE-Module-Display-Category=jMonkeyEngine +OpenIDE-Module-Name=AssetBrowser +CTL_AssetBrowserAction=AssetBrowser +CTL_AssetBrowserTopComponent=AssetBrowser +HINT_AssetBrowserTopComponent=AssetBrowser +AssetBrowser.projectLabel.text=No project selected +AssetBrowser.filterField.text= +AssetBrowser.sizeSlider.toolTipText=Size of previews +AssetBrowser.clearFilterButton.text= +AssetBrowser.filterField.toolTipText=Enter text to filter diff --git a/jme3-assetbrowser/src/com/jme3/gde/assetbrowser/Constants.java b/jme3-assetbrowser/src/com/jme3/gde/assetbrowser/Constants.java new file mode 100644 index 000000000..5460f2ef6 --- /dev/null +++ b/jme3-assetbrowser/src/com/jme3/gde/assetbrowser/Constants.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2009-2023 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.gde.assetbrowser; + +/** + * + * @author rickard + */ +public class Constants { + + static final int sizeX = 170; + static final int sizeY = 180; + static final int imageSize = 150; +} diff --git a/jme3-assetbrowser/src/com/jme3/gde/assetbrowser/PreviewHelper.java b/jme3-assetbrowser/src/com/jme3/gde/assetbrowser/PreviewHelper.java new file mode 100644 index 000000000..90dd453e1 --- /dev/null +++ b/jme3-assetbrowser/src/com/jme3/gde/assetbrowser/PreviewHelper.java @@ -0,0 +1,310 @@ +/* + * Copyright (c) 2009-2023 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.gde.assetbrowser; + +import com.jme3.gde.assetbrowser.icons.Icons; +import com.jme3.gde.assetbrowser.widgets.AssetPreviewWidget; +import com.jme3.gde.core.assets.ProjectAssetManager; +import com.jme3.gde.core.icons.IconList; +import com.jme3.gde.core.scene.PreviewRequest; +import com.jme3.gde.core.scene.SceneApplication; +import com.jme3.gde.core.scene.SceneListener; +import com.jme3.gde.core.scene.SceneRequest; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import com.jme3.scene.shape.Box; +import com.jme3.texture.Image; +import com.jme3.texture.Texture; +import com.jme3.util.mikktspace.MikktspaceTangentGenerator; +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.RenderingHints; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.attribute.BasicFileAttributes; +import java.nio.file.attribute.FileTime; +import javax.imageio.ImageIO; +import javax.swing.Icon; +import javax.swing.ImageIcon; +import jme3tools.converters.ImageToAwt; +import org.openide.filesystems.FileObject; +import org.openide.util.Exceptions; + +/** + * Helper class for generating preview images + * + * @author rickard + */ +public class PreviewHelper { + + private static final int PREVIEW_SIZE = 150; + private final ProjectAssetManager assetManager; + + private static final Vector3f previewLocation = new Vector3f(4, 4, 7); + private static final Vector3f previewLookAt = new Vector3f(0, 0, 0); + + public PreviewHelper(ProjectAssetManager assetManager) { + this.assetManager = assetManager; + } + + public Icon getOrCreateTexturePreview(String asset, int size) { + final var icon = tryGetPreview(asset, size); + if (icon != null) { + return icon; + } + System.out.println("creating preview "); + Texture texture = assetManager.loadTexture(asset); + Image image = texture.getImage(); + + BufferedImage buff = ImageToAwt.convert(image, false, false, 0); + + BufferedImage scaled = scaleDown(buff, 150, 150); + BufferedImage noAlpha = convertImage(scaled); + savePreview(assetManager, asset.split("\\.")[0], noAlpha); + return new ImageIcon(noAlpha); + } + + public Icon getSoundPreview(String asset, int size) { + return Icons.soundIcon; + } + + public Icon getDefaultIcon(String asset, int size) { + return Icons.assetIcon; + } + + public Icon getOrCreateMaterialPreview(String asset, AssetPreviewWidget widget, int size) { + final var icon = tryGetPreview(asset, size); + if (icon != null) { + return icon; + } + + Material mat = assetManager.loadMaterial(asset); + + Box boxMesh = new Box(1.75f, 1.75f, 1.75f); + Geometry box = new Geometry("previewBox", boxMesh); + box.setMaterial(mat); + PreviewListener listener = new PreviewListener(assetManager, mat.getAssetName().split("\\.")[0], widget); + SceneApplication.getApplication().addSceneListener(listener); + SceneApplication.getApplication().enqueue(() -> { + SceneApplication.getApplication().getRenderManager().preloadScene(box); + java.awt.EventQueue.invokeLater(() -> { + MikktspaceTangentGenerator.generate(box); + PreviewRequest request = new PreviewRequest(listener, box, PREVIEW_SIZE, PREVIEW_SIZE); + request.getCameraRequest().setLocation(previewLocation); + request.getCameraRequest().setLookAt(previewLookAt, Vector3f.UNIT_Y); + SceneApplication.getApplication().createPreview(request); + }); + }); + return IconList.asset; + } + + private Icon tryGetPreview(String asset, int size) { + final var assetPath = assetManager.getAbsoluteAssetPath(asset); + + final FileTime assetModificationTime = getAssetModificationTime(assetPath); + + final File previewFile = loadPreviewFile(assetManager, asset.split("\\.")[0]); + + if (previewFile != null && assetModificationTime != null) { + final Path previewPath = previewFile.toPath(); + if(previewPath == null) { + return null; + } + try { + final BasicFileAttributes previewAttributes = Files.readAttributes( + previewPath, BasicFileAttributes.class); + final FileTime previewCreationTime = previewAttributes.creationTime(); + + if (previewCreationTime.compareTo(assetModificationTime) > 0) { + System.out.println("existing preview OK " + previewFile); + BufferedImage image = ImageIO.read(previewFile); + if (image != null) { + return new ImageIcon(size != PREVIEW_SIZE ? image.getScaledInstance(size, size, 0) : image); + } + } + + } catch (IOException ex) { + Exceptions.printStackTrace(ex); + } + } + return null; + } + + public Icon getOrCreateModelPreview(String asset, AssetPreviewWidget widget, int size) { + final var icon = tryGetPreview(asset, size); + if (icon != null) { + return icon; + } + + Material unshaded = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + unshaded.setColor("Color", ColorRGBA.Red); + + Spatial spatial = assetManager.loadModel(asset); + + recurseApplyDefaultMaterial(spatial, unshaded); + + PreviewListener listener = new PreviewListener(assetManager, asset.split("\\.")[0], widget); + SceneApplication.getApplication().addSceneListener(listener); + SceneApplication.getApplication().enqueue(() -> { + SceneApplication.getApplication().getRenderManager().preloadScene(spatial); + java.awt.EventQueue.invokeLater(() -> { + PreviewRequest request = new PreviewRequest(listener, spatial, PREVIEW_SIZE, PREVIEW_SIZE); + request.getCameraRequest().setLocation(previewLocation); + request.getCameraRequest().setLookAt(previewLookAt, Vector3f.UNIT_Y); + SceneApplication.getApplication().createPreview(request); + }); + }); + return IconList.asset; + } + + /** + * Applies unshaded MatDef if spatial has no material already + * + * @param spatial + * @param material + */ + private void recurseApplyDefaultMaterial(Spatial spatial, Material material) { + if (spatial instanceof Node) { + ((Node) spatial).getChildren().forEach(child -> recurseApplyDefaultMaterial(child, material)); + } else if (spatial instanceof Geometry) { + if (((Geometry) spatial).getMaterial() == null) { + spatial.setMaterial(material); + } + } + } + + private FileTime getAssetModificationTime(String assetPath) { + if (assetPath == null) { + return null; + } + Path path = new File(assetPath).toPath(); + + try { + // creating BasicFileAttributes class object using + // readAttributes method + BasicFileAttributes file_att = Files.readAttributes( + path, BasicFileAttributes.class); + return file_att.lastModifiedTime(); + } catch (IOException ex) { + Exceptions.printStackTrace(ex); + } + return null; + } + + private File loadPreviewFile(ProjectAssetManager assetManager, String id) { + FileObject fileObject = assetManager.getProject().getProjectDirectory(); + return new File(fileObject.getPath() + "/.assetBrowser/", id + ".jpg"); + } + + private void savePreview(ProjectAssetManager assetManager, String id, BufferedImage preview) { + FileObject fileObject = assetManager.getProject().getProjectDirectory(); + String[] fileSections = id.split("/"); + String fileName = fileSections[fileSections.length - 1]; + File path = new File(fileObject.getPath() + "/.assetBrowser/" + id.substring(0, id.length() - fileName.length())); + File file = new File(path, fileName + ".jpg"); + try { + path.mkdirs(); + file.createNewFile(); + ImageIO.write(preview, "jpg", file); + } catch (IOException ex) { + Exceptions.printStackTrace(ex); + } + } + + private BufferedImage scaleDown(BufferedImage sourceImage, int targetWidth, int targetHeight) { + int sourceWidth = sourceImage.getWidth(); + int sourceHeight = sourceImage.getHeight(); + + BufferedImage targetImage = new BufferedImage(targetWidth, targetHeight, sourceImage.getType()); + + Graphics2D g = targetImage.createGraphics(); + g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); + g.drawImage(sourceImage, 0, 0, targetWidth, targetHeight, 0, 0, sourceWidth, sourceHeight, null); + g.dispose(); + + return targetImage; + } + + private class PreviewListener implements SceneListener { + + final AssetPreviewWidget widget; + final ProjectAssetManager assetManager; + private final String assetName; + + public PreviewListener(ProjectAssetManager assetManager, String assetName, AssetPreviewWidget widget) { + this.widget = widget; + this.assetManager = assetManager; + this.assetName = assetName; + } + + @Override + public void sceneOpened(SceneRequest request) { + } + + @Override + public void sceneClosed(SceneRequest request) { + } + + @Override + public void previewCreated(PreviewRequest request) { + if (request.getRequester() == this) { + final var image = convertImage(request.getImage()); + java.awt.EventQueue.invokeLater(() -> { + widget.setPreviewImage(new ImageIcon(image)); + savePreview(assetManager, assetName, image); + widget.revalidate(); + }); + } + } + }; + + private static BufferedImage convertImage(BufferedImage preview) { + final int width = preview.getWidth(); + final int height = preview.getHeight(); + BufferedImage converted = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); + Graphics2D g = converted.createGraphics(); + g.setColor(Color.WHITE); + g.fillRect(0, 0, width, height); + int w = preview.getWidth(); + int h = preview.getHeight(); + g.drawImage(preview, 0, 0, w, h, 0, h, w, 0, null); + g.dispose(); + return converted; + } +} diff --git a/jme3-assetbrowser/src/com/jme3/gde/assetbrowser/dnd/AssetPreviewPopupMenu.java b/jme3-assetbrowser/src/com/jme3/gde/assetbrowser/dnd/AssetPreviewPopupMenu.java new file mode 100644 index 000000000..41939f75d --- /dev/null +++ b/jme3-assetbrowser/src/com/jme3/gde/assetbrowser/dnd/AssetPreviewPopupMenu.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2009-2023 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.gde.assetbrowser.dnd; + +import java.awt.event.ActionListener; +import javax.swing.JPopupMenu; + +/** + * Pop up menu for actions on asset previews + * + * @author rickard + */ +public class AssetPreviewPopupMenu extends JPopupMenu { + + public AssetPreviewPopupMenu(ActionListener listener) { + add("Refresh").addActionListener(listener); + add("Delete").addActionListener(listener); + } +} diff --git a/jme3-assetbrowser/src/com/jme3/gde/assetbrowser/dnd/AssetPreviewWidgetMouseListener.java b/jme3-assetbrowser/src/com/jme3/gde/assetbrowser/dnd/AssetPreviewWidgetMouseListener.java new file mode 100644 index 000000000..4fd9c959c --- /dev/null +++ b/jme3-assetbrowser/src/com/jme3/gde/assetbrowser/dnd/AssetPreviewWidgetMouseListener.java @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2009-2023 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.gde.assetbrowser.dnd; + +import com.jme3.gde.assetbrowser.widgets.AssetPreviewWidget; +import com.jme3.gde.assetbrowser.widgets.PreviewInteractionListener; +import java.awt.event.MouseAdapter; +import javax.swing.JOptionPane; +import javax.swing.TransferHandler; + +/** + * For handling drag and drop of assets. + * + * @author rickard + */ +public final class AssetPreviewWidgetMouseListener extends MouseAdapter { + + private final AssetPreviewWidget previewWidget; + private final PreviewInteractionListener listener; + private boolean pressed, moved; + + public AssetPreviewWidgetMouseListener(AssetPreviewWidget previewWidget, PreviewInteractionListener listener) { + this.previewWidget = previewWidget; + this.listener = listener; + } + + @Override + public void mouseClicked(final java.awt.event.MouseEvent evt) { + if (evt.getClickCount() == 2) { + evt.consume(); + if (previewWidget.isEditable()) { + listener.openAsset(previewWidget); + } else { + JOptionPane.showMessageDialog(null, "Project dependencies can't be edited"); + } + } + } + + @Override + public void mousePressed(final java.awt.event.MouseEvent evt) { + pressed = true; + + } + + @Override + public void mouseReleased(final java.awt.event.MouseEvent evt) { + pressed = false; + moved = false; + } + + @Override + public void mouseMoved(final java.awt.event.MouseEvent evt) { + } + + @Override + public void mouseDragged(final java.awt.event.MouseEvent evt) { + if (pressed) { + moved = true; + TransferHandler handler = previewWidget.getTransferHandler(); + if (handler != null) { + handler.exportAsDrag(previewWidget, evt, TransferHandler.COPY); + } + } + } +} diff --git a/jme3-assetbrowser/src/com/jme3/gde/assetbrowser/icons/Icons.java b/jme3-assetbrowser/src/com/jme3/gde/assetbrowser/icons/Icons.java new file mode 100644 index 000000000..9f0eb7951 --- /dev/null +++ b/jme3-assetbrowser/src/com/jme3/gde/assetbrowser/icons/Icons.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2009-2023 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.gde.assetbrowser.icons; + +import javax.swing.ImageIcon; +import org.openide.util.ImageUtilities; + +/** + * Lists all icons used by the AssetBrowser + * @author rickard + */ +public class Icons { + + public static final String ICONS_PATH = "com/jme3/gde/assetbrowser/icons/"; + public static final String TEXTURE_REMOVE = ICONS_PATH + "remove_texture.svg"; + // use png for asset preview + public static final String SOUND_WAVES = ICONS_PATH + "sound_waves.png"; + public static final String ASSET = ICONS_PATH + "asset.png"; + + public static final ImageIcon clearFilter = + ImageUtilities.loadImageIcon(TEXTURE_REMOVE, false); + public static final ImageIcon soundIcon = + ImageUtilities.loadImageIcon(SOUND_WAVES, false); + public static final ImageIcon assetIcon = + ImageUtilities.loadImageIcon(ASSET, false); +} \ No newline at end of file diff --git a/jme3-assetbrowser/src/com/jme3/gde/assetbrowser/icons/asset.png b/jme3-assetbrowser/src/com/jme3/gde/assetbrowser/icons/asset.png new file mode 100644 index 000000000..f94a32406 Binary files /dev/null and b/jme3-assetbrowser/src/com/jme3/gde/assetbrowser/icons/asset.png differ diff --git a/jme3-assetbrowser/src/com/jme3/gde/assetbrowser/icons/remove_texture.svg b/jme3-assetbrowser/src/com/jme3/gde/assetbrowser/icons/remove_texture.svg new file mode 100644 index 000000000..969e234ef --- /dev/null +++ b/jme3-assetbrowser/src/com/jme3/gde/assetbrowser/icons/remove_texture.svg @@ -0,0 +1 @@ + diff --git a/jme3-assetbrowser/src/com/jme3/gde/assetbrowser/icons/sound-waves.png b/jme3-assetbrowser/src/com/jme3/gde/assetbrowser/icons/sound-waves.png new file mode 100644 index 000000000..58c6322fc Binary files /dev/null and b/jme3-assetbrowser/src/com/jme3/gde/assetbrowser/icons/sound-waves.png differ diff --git a/jme3-assetbrowser/src/com/jme3/gde/assetbrowser/icons/sound-waves.svg b/jme3-assetbrowser/src/com/jme3/gde/assetbrowser/icons/sound-waves.svg new file mode 100644 index 000000000..66dfed4f5 --- /dev/null +++ b/jme3-assetbrowser/src/com/jme3/gde/assetbrowser/icons/sound-waves.svg @@ -0,0 +1,61 @@ + + + + + + image/svg+xml + + + + + + + + + + diff --git a/jme3-assetbrowser/src/com/jme3/gde/assetbrowser/widgets/AssetPreviewWidget.form b/jme3-assetbrowser/src/com/jme3/gde/assetbrowser/widgets/AssetPreviewWidget.form new file mode 100644 index 000000000..e6b7a0420 --- /dev/null +++ b/jme3-assetbrowser/src/com/jme3/gde/assetbrowser/widgets/AssetPreviewWidget.form @@ -0,0 +1,68 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/jme3-assetbrowser/src/com/jme3/gde/assetbrowser/widgets/AssetPreviewWidget.java b/jme3-assetbrowser/src/com/jme3/gde/assetbrowser/widgets/AssetPreviewWidget.java new file mode 100644 index 000000000..12a3d2150 --- /dev/null +++ b/jme3-assetbrowser/src/com/jme3/gde/assetbrowser/widgets/AssetPreviewWidget.java @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2009-2023 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.gde.assetbrowser.widgets; + +import com.jme3.gde.assetbrowser.dnd.AssetPreviewPopupMenu; +import com.jme3.gde.assetbrowser.dnd.AssetPreviewWidgetMouseListener; +import com.jme3.gde.core.icons.IconList; +import com.jme3.gde.core.scene.PreviewRequest; +import com.jme3.gde.core.scene.SceneListener; +import com.jme3.gde.core.scene.SceneRequest; +import com.jme3.gde.core.dnd.AssetNameHolder; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import javax.swing.Icon; + +/** + * Displays an asset as an image in the AssetBrowser and handles open action and + * dragging (if supported) + * + * @author rickard + */ +public class AssetPreviewWidget extends javax.swing.JPanel implements SceneListener, AssetNameHolder, ActionListener { + + private boolean editable; + private PreviewInteractionListener listener; + + /** + * Creates new form AssetPreviewWidget + */ + public AssetPreviewWidget() { + initComponents(); + } + + public AssetPreviewWidget(final PreviewInteractionListener listener, Icon icon) { + this(listener); + assetPreviewLabel.setIcon(icon); + } + + public AssetPreviewWidget(final PreviewInteractionListener listener) { + this(); + this.listener = listener; + final var mouseListener = new AssetPreviewWidgetMouseListener(this, listener); + addMouseListener(mouseListener); + addMouseMotionListener(mouseListener); + setComponentPopupMenu(new AssetPreviewPopupMenu(this)); + } + + public void setPreviewImage(Icon icon) { + assetPreviewLabel.setIcon(icon); + } + + public void setPreviewName(String name) { + assetNameLabel.setText(name); + setToolTipText(name); + } + + public String getPreviewName() { + return assetNameLabel.getText(); + } + + /** + * 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") + // //GEN-BEGIN:initComponents + private void initComponents() { + + assetNameLabel = new javax.swing.JLabel(); + assetPreviewLabel = new javax.swing.JLabel(); + + setMinimumSize(new java.awt.Dimension(170, 180)); + setPreferredSize(new java.awt.Dimension(170, 180)); + addMouseListener(new java.awt.event.MouseAdapter() { + public void mousePressed(java.awt.event.MouseEvent evt) { + formMousePressed(evt); + } + }); + setLayout(new java.awt.BorderLayout()); + + org.openide.awt.Mnemonics.setLocalizedText(assetNameLabel, org.openide.util.NbBundle.getMessage(AssetPreviewWidget.class, "AssetPreviewWidget.assetNameLabel.text")); // NOI18N + add(assetNameLabel, java.awt.BorderLayout.SOUTH); + assetNameLabel.getAccessibleContext().setAccessibleName(org.openide.util.NbBundle.getMessage(AssetPreviewWidget.class, "AssetPreviewWidget.assetNameLabel.AccessibleContext.accessibleName")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(assetPreviewLabel, org.openide.util.NbBundle.getMessage(AssetPreviewWidget.class, "AssetPreviewWidget.assetPreviewLabel.text")); // NOI18N + assetPreviewLabel.setVerticalAlignment(javax.swing.SwingConstants.TOP); + assetPreviewLabel.setPreferredSize(new java.awt.Dimension(150, 150)); + add(assetPreviewLabel, java.awt.BorderLayout.CENTER); + assetPreviewLabel.getAccessibleContext().setAccessibleName(org.openide.util.NbBundle.getMessage(AssetPreviewWidget.class, "AssetPreviewWidget.assetPreviewLabel.AccessibleContext.accessibleName")); // NOI18N + }// //GEN-END:initComponents + + private void formMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_formMousePressed + + }//GEN-LAST:event_formMousePressed + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JLabel assetNameLabel; + private javax.swing.JLabel assetPreviewLabel; + // End of variables declaration//GEN-END:variables + + @Override + public void sceneOpened(SceneRequest request) { + } + + @Override + public void sceneClosed(SceneRequest request) { + } + + @Override + public void previewCreated(PreviewRequest request) { + if (request.getRequester() == this) { + java.awt.EventQueue.invokeLater(() -> { + assetPreviewLabel.setIcon(IconList.asset); +// invalidate(); + revalidate(); + repaint(); +// updateUI(); + }); + } + } + + @Override + public String getAssetName() { + return assetNameLabel.getText(); + } + + @Override + public void setAssetName(String name) { + assetNameLabel.setText(name); + } + + public void setEditable(boolean editable) { + this.editable = editable; + } + + public boolean isEditable() { + return editable; + } + + @Override + public void actionPerformed(ActionEvent e) { + switch (e.getActionCommand()) { + case "Refresh": + listener.refreshPreview(this); + break; + case "Delete": + listener.deleteAsset(this); + break; + } + } + +} diff --git a/jme3-assetbrowser/src/com/jme3/gde/assetbrowser/widgets/Bundle.properties b/jme3-assetbrowser/src/com/jme3/gde/assetbrowser/widgets/Bundle.properties new file mode 100644 index 000000000..7be2afddf --- /dev/null +++ b/jme3-assetbrowser/src/com/jme3/gde/assetbrowser/widgets/Bundle.properties @@ -0,0 +1,4 @@ +AssetPreviewWidget.assetNameLabel.text=assetName +AssetPreviewWidget.assetNameLabel.AccessibleContext.accessibleName=assetNameLabel +AssetPreviewWidget.assetPreviewLabel.AccessibleContext.accessibleName=assetPreviewLabel +AssetPreviewWidget.assetPreviewLabel.text= diff --git a/jme3-assetbrowser/src/com/jme3/gde/assetbrowser/widgets/MatDefPreview.java b/jme3-assetbrowser/src/com/jme3/gde/assetbrowser/widgets/MatDefPreview.java new file mode 100644 index 000000000..5faad99a9 --- /dev/null +++ b/jme3-assetbrowser/src/com/jme3/gde/assetbrowser/widgets/MatDefPreview.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2009-2023 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.gde.assetbrowser.widgets; + +import javax.swing.Icon; + +/** + * A preview of a MatDef in the AssetBrowser + * + * @author rickard + */ +public class MatDefPreview extends AssetPreviewWidget { + + public MatDefPreview(PreviewInteractionListener listener, Icon icon) { + super(listener, icon); + } + +} diff --git a/jme3-assetbrowser/src/com/jme3/gde/assetbrowser/widgets/MaterialPreview.java b/jme3-assetbrowser/src/com/jme3/gde/assetbrowser/widgets/MaterialPreview.java new file mode 100644 index 000000000..2d51fb22e --- /dev/null +++ b/jme3-assetbrowser/src/com/jme3/gde/assetbrowser/widgets/MaterialPreview.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2009-2023 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.gde.assetbrowser.widgets; + +import com.jme3.gde.core.dnd.MaterialDataFlavor; +import com.jme3.gde.core.dnd.AssetGrabHandler; + +/** + * + * @author rickard + */ +public class MaterialPreview extends AssetPreviewWidget { + + public MaterialPreview(PreviewInteractionListener listener) { + super(listener); + setTransferHandler(new AssetGrabHandler(this, new MaterialDataFlavor())); + } + +} diff --git a/jme3-assetbrowser/src/com/jme3/gde/assetbrowser/widgets/ModelPreview.java b/jme3-assetbrowser/src/com/jme3/gde/assetbrowser/widgets/ModelPreview.java new file mode 100644 index 000000000..363fe71a6 --- /dev/null +++ b/jme3-assetbrowser/src/com/jme3/gde/assetbrowser/widgets/ModelPreview.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2009-2023 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.gde.assetbrowser.widgets; + +import com.jme3.gde.core.dnd.AssetGrabHandler; +import com.jme3.gde.core.dnd.SpatialDataFlavor; + +/** + * + * @author rickard + */ +public class ModelPreview extends AssetPreviewWidget { + + public ModelPreview(PreviewInteractionListener listener) { + super(listener); + setTransferHandler(new AssetGrabHandler(this, new SpatialDataFlavor())); + } + +} diff --git a/jme3-assetbrowser/src/com/jme3/gde/assetbrowser/widgets/PreviewInteractionListener.java b/jme3-assetbrowser/src/com/jme3/gde/assetbrowser/widgets/PreviewInteractionListener.java new file mode 100644 index 000000000..af69d3c03 --- /dev/null +++ b/jme3-assetbrowser/src/com/jme3/gde/assetbrowser/widgets/PreviewInteractionListener.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2009-2023 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.gde.assetbrowser.widgets; + +/** + * + * @author rickard + */ +public interface PreviewInteractionListener { + + void openAsset(AssetPreviewWidget widget); + + void refreshPreview(AssetPreviewWidget widget); + + void deleteAsset(AssetPreviewWidget widget); +} diff --git a/jme3-assetbrowser/src/com/jme3/gde/assetbrowser/widgets/SoundPreview.java b/jme3-assetbrowser/src/com/jme3/gde/assetbrowser/widgets/SoundPreview.java new file mode 100644 index 000000000..148703750 --- /dev/null +++ b/jme3-assetbrowser/src/com/jme3/gde/assetbrowser/widgets/SoundPreview.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2009-2023 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.gde.assetbrowser.widgets; + +import javax.swing.Icon; + +/** + * Displaying a preview of a sound in the AssetBrowser + * + * @author rickard + */ +public class SoundPreview extends AssetPreviewWidget { + + public SoundPreview(PreviewInteractionListener listener, Icon icon) { + super(listener, icon); + } +} diff --git a/jme3-assetbrowser/src/com/jme3/gde/assetbrowser/widgets/TexturePreview.java b/jme3-assetbrowser/src/com/jme3/gde/assetbrowser/widgets/TexturePreview.java new file mode 100644 index 000000000..1fa401a28 --- /dev/null +++ b/jme3-assetbrowser/src/com/jme3/gde/assetbrowser/widgets/TexturePreview.java @@ -0,0 +1,22 @@ +/* + * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license + * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template + */ +package com.jme3.gde.assetbrowser.widgets; + +import com.jme3.gde.core.dnd.AssetGrabHandler; +import com.jme3.gde.core.dnd.TextureDataFlavor; +import javax.swing.Icon; + +/** + * + * @author rickard + */ +public class TexturePreview extends AssetPreviewWidget { + + public TexturePreview(PreviewInteractionListener listener, Icon icon) { + super(listener, icon); + setTransferHandler(new AssetGrabHandler(this, new TextureDataFlavor())); + } + +} diff --git a/jme3-behaviortrees/nbproject/genfiles.properties b/jme3-behaviortrees/nbproject/genfiles.properties index 6ac5d8385..5e64f64fd 100644 --- a/jme3-behaviortrees/nbproject/genfiles.properties +++ b/jme3-behaviortrees/nbproject/genfiles.properties @@ -5,4 +5,4 @@ build.xml.stylesheet.CRC32=a56c6a5b@2.72.1 # Do not edit this file. You may delete it but then the IDE will never regenerate such files for you. nbproject/build-impl.xml.data.CRC32=8aca329b nbproject/build-impl.xml.script.CRC32=35831a68 -nbproject/build-impl.xml.stylesheet.CRC32=238281d1@2.72.1 +nbproject/build-impl.xml.stylesheet.CRC32=49aa68b0@2.91 diff --git a/jme3-core/nbproject/project.xml b/jme3-core/nbproject/project.xml index 5415578cd..505f969fe 100644 --- a/jme3-core/nbproject/project.xml +++ b/jme3-core/nbproject/project.xml @@ -12,7 +12,7 @@ 1 - 3.3.0 + 3.6.0 @@ -21,20 +21,20 @@ 1 - 3.3.0 + 3.6.0 com.jme3.gde.core.updatecenters - 3.3.0 + 3.6.0 com.jme3.gde.project.testdata 1 - 3.3.0 + 3.6.0 @@ -434,6 +434,7 @@ com.jme3.gde.core.assets.nodes com.jme3.gde.core.codeless com.jme3.gde.core.completion + com.jme3.gde.core.dnd com.jme3.gde.core.editor.icons com.jme3.gde.core.editor.nodes com.jme3.gde.core.errorreport diff --git a/jme3-core/src/com/jme3/gde/core/assets/ProjectAssetManager.java b/jme3-core/src/com/jme3/gde/core/assets/ProjectAssetManager.java index 260d39c33..ee6ec150e 100644 --- a/jme3-core/src/com/jme3/gde/core/assets/ProjectAssetManager.java +++ b/jme3-core/src/com/jme3/gde/core/assets/ProjectAssetManager.java @@ -455,64 +455,85 @@ private String stripFirstSlash(String input) { return input; } - @Deprecated - public AssetManager getManager() { - return this; - } - public String[] getModels() { - return filesWithSuffix("j3o"); + return getModels(true); } + public String[] getModels(boolean includeDependencies) { + return filesWithSuffix("j3o", includeDependencies); + } + public String[] getMaterials() { - return filesWithSuffix("j3m"); + return getMaterials(true); } + public String[] getMaterials(boolean includeDependencies) { + return filesWithSuffix("j3m", includeDependencies); + } + public String[] getSounds() { - ArrayList list = new ArrayList(); - list.addAll(collectFilesWithSuffix("wav")); - list.addAll(collectFilesWithSuffix("ogg")); - return list.toArray(new String[list.size()]); + return getSounds(true); } + public String[] getSounds(boolean includeDependencies) { + ArrayList list = new ArrayList<>(); + list.addAll(collectFilesWithSuffix("wav", includeDependencies)); + list.addAll(collectFilesWithSuffix("ogg", includeDependencies)); + return list.toArray(String[]::new); + } + public String[] getTextures() { - ArrayList list = new ArrayList(); - list.addAll(collectFilesWithSuffix("jpg")); - list.addAll(collectFilesWithSuffix("jpeg")); - list.addAll(collectFilesWithSuffix("gif")); - list.addAll(collectFilesWithSuffix("png")); - list.addAll(collectFilesWithSuffix("dds")); - list.addAll(collectFilesWithSuffix("pfm")); - list.addAll(collectFilesWithSuffix("hdr")); - list.addAll(collectFilesWithSuffix("tga")); - return list.toArray(new String[list.size()]); + return getTextures(true); + } + + public String[] getTextures(boolean includeDependencies) { + ArrayList list = new ArrayList<>(); + list.addAll(collectFilesWithSuffix("jpg", includeDependencies)); + list.addAll(collectFilesWithSuffix("jpeg", includeDependencies)); + list.addAll(collectFilesWithSuffix("gif", includeDependencies)); + list.addAll(collectFilesWithSuffix("png", includeDependencies)); + list.addAll(collectFilesWithSuffix("dds", includeDependencies)); + list.addAll(collectFilesWithSuffix("pfm", includeDependencies)); + list.addAll(collectFilesWithSuffix("hdr", includeDependencies)); + list.addAll(collectFilesWithSuffix("tga", includeDependencies)); + return list.toArray(String[]::new); + } + + public String[] getMatDefs() { + return getMatDefs(true); } - public String[] getMatDefs() { - return filesWithSuffix("j3md"); + public String[] getMatDefs(boolean includeDependencies) { + return filesWithSuffix("j3md", includeDependencies); } public List getProjectShaderNodeDefs() { - return collectProjectFilesWithSuffix("j3sn", new LinkedList()); + return collectProjectFilesWithSuffix("j3sn", new LinkedList<>()); } public List getDependenciesShaderNodeDefs() { - return collectDependenciesFilesWithSuffix("j3sn", new LinkedList()); + return collectDependenciesFilesWithSuffix("j3sn", new LinkedList<>()); } - + public String[] getAssetsWithSuffix(String string) { - return filesWithSuffix(string); + return getAssetsWithSuffix(string, true); + } + + public String[] getAssetsWithSuffix(String string, boolean includeDependencies) { + return filesWithSuffix(string, includeDependencies); } - private String[] filesWithSuffix(String string) { - List list = collectFilesWithSuffix(string); - return list.toArray(new String[list.size()]); + private String[] filesWithSuffix(String string, boolean includeDependencies) { + List list = collectFilesWithSuffix(string, includeDependencies); + return list.toArray(String[]::new); } - private List collectFilesWithSuffix(String suffix) { - List list = new LinkedList(); + private List collectFilesWithSuffix(String suffix, boolean includeDependencies) { + List list = new LinkedList<>(); collectProjectFilesWithSuffix(suffix, list); - collectDependenciesFilesWithSuffix(suffix, list); + if(includeDependencies) { + collectDependenciesFilesWithSuffix(suffix, list); + } return list; } @@ -682,6 +703,10 @@ public void run() { } }); } + + public boolean isGradleProject() { + return GradleBaseProject.get(project) != null; + } public Mutex mutex() { return mutex; diff --git a/jme3-core/src/com/jme3/gde/core/dnd/AssetGrabHandler.java b/jme3-core/src/com/jme3/gde/core/dnd/AssetGrabHandler.java new file mode 100644 index 000000000..ff20fac84 --- /dev/null +++ b/jme3-core/src/com/jme3/gde/core/dnd/AssetGrabHandler.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2009-2023 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.gde.core.dnd; + +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.Transferable; +import java.awt.datatransfer.UnsupportedFlavorException; +import java.io.IOException; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.swing.JComponent; +import javax.swing.TransferHandler; +import javax.swing.TransferHandler.TransferSupport; + +/** + * Based on: + * https://stackoverflow.com/questions/23225958/dragging-between-two-components-in-swing + * + * @author rickard + * @param + */ +public class AssetGrabHandler extends TransferHandler { + + private static final long serialVersionUID = 1L; + private final DataFlavor flavor; + private final AssetNameHolder origin; + + public AssetGrabHandler(AssetNameHolder origin, T flavor) { + this.origin = origin; + this.flavor = flavor; + } + + @Override + public boolean canImport(TransferSupport info) { + return info.isDataFlavorSupported(flavor); + } + + @Override + public boolean importData(TransferSupport transferSupport) { + final Transferable t = transferSupport.getTransferable(); + try { + return t.getTransferData(flavor) != null; + } catch (UnsupportedFlavorException | IOException e) { + Logger.getLogger(AssetGrabHandler.class.getName()).log(Level.WARNING, "Non-supported flavor {0}", t); + } + return false; + } + + @Override + public int getSourceActions(JComponent c) { + return TransferHandler.COPY; + } + + @Override + public Transferable createTransferable(JComponent source) { + // We need the values from the list as an object array, otherwise the data flavor won't match in importData + return new AssetTransferable(origin, flavor); + } + +} diff --git a/jme3-core/src/com/jme3/gde/core/dnd/AssetNameHolder.java b/jme3-core/src/com/jme3/gde/core/dnd/AssetNameHolder.java new file mode 100644 index 000000000..57efb7345 --- /dev/null +++ b/jme3-core/src/com/jme3/gde/core/dnd/AssetNameHolder.java @@ -0,0 +1,16 @@ +/* + * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license + * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template + */ +package com.jme3.gde.core.dnd; + +/** + * + * @author rickard + */ +public interface AssetNameHolder { + + String getAssetName(); + + void setAssetName(String name); +} diff --git a/jme3-core/src/com/jme3/gde/core/dnd/AssetTransferable.java b/jme3-core/src/com/jme3/gde/core/dnd/AssetTransferable.java new file mode 100644 index 000000000..ff025514a --- /dev/null +++ b/jme3-core/src/com/jme3/gde/core/dnd/AssetTransferable.java @@ -0,0 +1,60 @@ +/* + * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license + * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template + */ +package com.jme3.gde.core.dnd; + +import com.jme3.gde.core.dnd.AssetNameHolder; +import com.jme3.gde.core.dnd.StringDataFlavor; +import com.jme3.gde.core.dnd.TextureDataFlavor; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.Transferable; +import java.awt.datatransfer.UnsupportedFlavorException; +import java.io.IOException; +import javax.swing.JPanel; + +/** + * + * @author rickard + * @param + */ +public class AssetTransferable implements Transferable { + + private DataFlavor[] flavors; + private AssetNameHolder string; + + public AssetTransferable(AssetNameHolder name, T flavor) { + this.string = name; + flavors = new DataFlavor[]{flavor}; + } + + @Override + public DataFlavor[] getTransferDataFlavors() { + return flavors; + } + + @Override + public boolean isDataFlavorSupported(DataFlavor flavor) { + for (DataFlavor mine : getTransferDataFlavors()) { + if (mine.equals(flavor)) { + return true; + } + } + return false; + } + + public AssetNameHolder getString() { + return string; + } + + @Override + public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException { + if (isDataFlavorSupported(flavor)) { + return getString(); + } else { + throw new UnsupportedFlavorException(flavor); + } + + } + +} diff --git a/jme3-core/src/com/jme3/gde/core/dnd/MaterialDataFlavor.java b/jme3-core/src/com/jme3/gde/core/dnd/MaterialDataFlavor.java new file mode 100644 index 000000000..271945499 --- /dev/null +++ b/jme3-core/src/com/jme3/gde/core/dnd/MaterialDataFlavor.java @@ -0,0 +1,10 @@ +package com.jme3.gde.core.dnd; + +/** + * + * @author rickard + */ +public class MaterialDataFlavor extends StringDataFlavor { + + public final static MaterialDataFlavor instance = new MaterialDataFlavor(); +} diff --git a/jme3-core/src/com/jme3/gde/core/dnd/MaterialDropTargetListener.java b/jme3-core/src/com/jme3/gde/core/dnd/MaterialDropTargetListener.java new file mode 100644 index 000000000..58f72c4bc --- /dev/null +++ b/jme3-core/src/com/jme3/gde/core/dnd/MaterialDropTargetListener.java @@ -0,0 +1,80 @@ +/* + * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license + * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template + */ +package com.jme3.gde.core.dnd; + +import com.jme3.gde.core.sceneviewer.SceneViewerTopComponent; +import com.jme3.math.Vector2f; +import java.awt.Cursor; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.Transferable; +import java.awt.dnd.DropTargetContext; +import java.awt.dnd.DropTargetDragEvent; +import java.awt.dnd.DropTargetDropEvent; +import java.awt.dnd.DropTargetEvent; +import java.awt.dnd.DropTargetListener; + +/** + * + * @author rickard + */ +public class MaterialDropTargetListener implements DropTargetListener { + + private static final Cursor droppableCursor = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR); + private static final Cursor notDroppableCursor = Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR); + + private final SceneViewerTopComponent rootPanel; + + public MaterialDropTargetListener(SceneViewerTopComponent rootPanel) { + this.rootPanel = rootPanel; + } + + @Override + public void dragEnter(DropTargetDragEvent dtde) { + } + + @Override + public void dragOver(DropTargetDragEvent dtde) { + if (!this.rootPanel.getCursor().equals(droppableCursor)) { + this.rootPanel.setCursor(droppableCursor); + } + } + + @Override + public void dropActionChanged(DropTargetDragEvent dtde) { + } + + @Override + public void dragExit(DropTargetEvent dte) { + this.rootPanel.setCursor(notDroppableCursor); + } + + @Override + public void drop(DropTargetDropEvent dtde) { + this.rootPanel.setCursor(Cursor.getDefaultCursor()); + + Object transferableObj = null; + try { + final DataFlavor dragAndDropPanelFlavor = new MaterialDataFlavor(); + + final Transferable transferable = dtde.getTransferable(); + + if (transferable.isDataFlavorSupported(dragAndDropPanelFlavor)) { + transferableObj = dtde.getTransferable().getTransferData(dragAndDropPanelFlavor); + } + + } catch (Exception ex) { + ex.printStackTrace(); + } + + if (transferableObj == null) { + return; + } + final int dropYLoc = dtde.getLocation().y; + final int dropXLoc = dtde.getLocation().x; + + rootPanel.applyMaterial(((AssetNameHolder) transferableObj).getAssetName(), new Vector2f(dropXLoc, dropYLoc)); + } + +} diff --git a/jme3-core/src/com/jme3/gde/core/dnd/SceneViewerDropTargetListener.java b/jme3-core/src/com/jme3/gde/core/dnd/SceneViewerDropTargetListener.java new file mode 100644 index 000000000..81dedec2d --- /dev/null +++ b/jme3-core/src/com/jme3/gde/core/dnd/SceneViewerDropTargetListener.java @@ -0,0 +1,94 @@ +/* + * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license + * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template + */ +package com.jme3.gde.core.dnd; + +import com.jme3.gde.core.sceneviewer.SceneViewerTopComponent; +import com.jme3.math.Vector2f; +import java.awt.Cursor; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.Transferable; +import java.awt.datatransfer.UnsupportedFlavorException; +import java.awt.dnd.DropTargetDragEvent; +import java.awt.dnd.DropTargetDropEvent; +import java.awt.dnd.DropTargetEvent; +import java.awt.dnd.DropTargetListener; +import java.io.IOException; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Handles dropping Materials or Spatial from the AssetBrowser to the + * SceneViewer + * @author rickard + */ +public class SceneViewerDropTargetListener implements DropTargetListener { + + private static final Cursor droppableCursor = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR); + private static final Cursor notDroppableCursor = Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR); + + private final SceneViewerTopComponent rootPanel; + + public SceneViewerDropTargetListener(final SceneViewerTopComponent rootPanel) { + this.rootPanel = rootPanel; + } + + @Override + public void dragEnter(final DropTargetDragEvent dtde) { + } + + @Override + public void dragOver(final DropTargetDragEvent dtde) { + if (!this.rootPanel.getCursor().equals(droppableCursor)) { + this.rootPanel.setCursor(droppableCursor); + } + } + + @Override + public void dropActionChanged(DropTargetDragEvent dtde) { + } + + @Override + public void dragExit(final DropTargetEvent dte) { + this.rootPanel.setCursor(notDroppableCursor); + } + + @Override + public void drop(final DropTargetDropEvent dtde) { + this.rootPanel.setCursor(Cursor.getDefaultCursor()); + + AssetNameHolder transferableObj = null; + Transferable transferable = null; + DataFlavor flavor = null; + + try { + transferable = dtde.getTransferable(); + final DataFlavor[] flavors = transferable.getTransferDataFlavors(); + + flavor = flavors[0]; + // What does the Transferable support + if (transferable.isDataFlavorSupported(flavor)) { + transferableObj = (AssetNameHolder) dtde.getTransferable().getTransferData(flavor); + } + + } catch (UnsupportedFlavorException | IOException ex) { + Logger.getLogger(SceneViewerDropTargetListener.class.getName()).log(Level.WARNING, "Non-supported flavor {0}", transferable); + } + + if (transferable == null || transferableObj == null) { + return; + } + + final int dropYLoc = dtde.getLocation().y; + final int dropXLoc = dtde.getLocation().x; + + if (flavor instanceof SpatialDataFlavor) { + rootPanel.addModel(transferableObj.getAssetName(), new Vector2f(dropXLoc, dropYLoc)); + } else if (flavor instanceof MaterialDataFlavor) { + rootPanel.applyMaterial(transferableObj.getAssetName(), new Vector2f(dropXLoc, dropYLoc)); + } + + } + +} diff --git a/jme3-core/src/com/jme3/gde/core/dnd/SpatialDataFlavor.java b/jme3-core/src/com/jme3/gde/core/dnd/SpatialDataFlavor.java new file mode 100644 index 000000000..1bb8bf122 --- /dev/null +++ b/jme3-core/src/com/jme3/gde/core/dnd/SpatialDataFlavor.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2009-2023 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */package com.jme3.gde.core.dnd; + +/** + * + * @author rickard + */ +public class SpatialDataFlavor extends StringDataFlavor { + + public final static SpatialDataFlavor instance = new SpatialDataFlavor(); + +} diff --git a/jme3-core/src/com/jme3/gde/core/dnd/StringDataFlavor.java b/jme3-core/src/com/jme3/gde/core/dnd/StringDataFlavor.java new file mode 100644 index 000000000..bd7e79301 --- /dev/null +++ b/jme3-core/src/com/jme3/gde/core/dnd/StringDataFlavor.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2009-2023 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.gde.core.dnd; + +import java.awt.datatransfer.DataFlavor; + +/** + * Based on: + * https://stackoverflow.com/questions/23225958/dragging-between-two-components-in-swing + * + * @author rickard + */ +public class StringDataFlavor extends DataFlavor { + + public StringDataFlavor() { + + super("text/plain", null); + + } + +} diff --git a/jme3-core/src/com/jme3/gde/core/dnd/TextureDataFlavor.java b/jme3-core/src/com/jme3/gde/core/dnd/TextureDataFlavor.java new file mode 100644 index 000000000..576db866f --- /dev/null +++ b/jme3-core/src/com/jme3/gde/core/dnd/TextureDataFlavor.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2009-2023 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */package com.jme3.gde.core.dnd; + +/** + * + * @author rickard + */ +public class TextureDataFlavor extends StringDataFlavor { + + public final static TextureDataFlavor instance = new TextureDataFlavor(); + +} diff --git a/jme3-core/src/com/jme3/gde/core/scene/PreviewRequest.java b/jme3-core/src/com/jme3/gde/core/scene/PreviewRequest.java index 425820361..c5f734a38 100644 --- a/jme3-core/src/com/jme3/gde/core/scene/PreviewRequest.java +++ b/jme3-core/src/com/jme3/gde/core/scene/PreviewRequest.java @@ -37,7 +37,9 @@ import java.awt.image.BufferedImage; /** - * + * Used to render an image of a scene using SceneApplication. Used by + * Material Editor and Shader Editor, for example. + * * @author normenhansen */ public class PreviewRequest { diff --git a/jme3-core/src/com/jme3/gde/core/sceneviewer/SceneViewerTopComponent.java b/jme3-core/src/com/jme3/gde/core/sceneviewer/SceneViewerTopComponent.java index c5a8111d6..c91d3314a 100644 --- a/jme3-core/src/com/jme3/gde/core/sceneviewer/SceneViewerTopComponent.java +++ b/jme3-core/src/com/jme3/gde/core/sceneviewer/SceneViewerTopComponent.java @@ -24,13 +24,26 @@ */ package com.jme3.gde.core.sceneviewer; +import com.jme3.asset.AssetManager; +import com.jme3.asset.MaterialKey; +import com.jme3.collision.CollisionResult; +import com.jme3.collision.CollisionResults; +import com.jme3.gde.core.dnd.SceneViewerDropTargetListener; import com.jme3.gde.core.filters.FilterExplorerTopComponent; import com.jme3.gde.core.icons.IconList; import com.jme3.gde.core.scene.SceneApplication; import com.jme3.gde.core.scene.SceneRequest; import com.jme3.input.awt.AwtKeyInput; import com.jme3.input.event.KeyInputEvent; +import com.jme3.material.Material; +import com.jme3.math.Ray; +import com.jme3.math.Vector2f; +import com.jme3.math.Vector3f; +import com.jme3.renderer.Camera; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; import java.awt.Component; +import java.awt.dnd.DropTarget; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.awt.event.MouseWheelEvent; @@ -51,7 +64,7 @@ * It also contains the top bar. */ @ConvertAsProperties(dtd = "-//com.jme3.gde.core.sceneviewer//SceneViewer//EN", -autostore = false) + autostore = false) public final class SceneViewerTopComponent extends TopComponent { private static SceneViewerTopComponent instance; @@ -101,10 +114,9 @@ public Void call() throws Exception { String action; if (e.getWheelRotation() < 0) { action = "MouseWheel"; - }else if (e.getWheelRotation() > 0) { + } else if (e.getWheelRotation() > 0) { action = "MouseWheel-"; - } - else { + } else { return null; } if (app.getActiveCameraController() != null) { @@ -154,6 +166,7 @@ public Void call() throws Exception { }); //} + oGLPanel.setDropTarget(new DropTarget(this, new SceneViewerDropTargetListener(this))); } /** @@ -352,7 +365,8 @@ private void enableNormalViewActionPerformed(java.awt.event.ActionEvent evt) {// * only, i.e. deserialization routines; otherwise you could get a * non-deserialized instance. To obtain the singleton instance, use * {@link #findInstance}. - * @return + * + * @return */ public static synchronized SceneViewerTopComponent getDefault() { if (instance == null) { @@ -364,7 +378,8 @@ public static synchronized SceneViewerTopComponent getDefault() { /** * Obtain the SceneViewerTopComponent instance. Never call * {@link #getDefault} directly! - * @return + * + * @return */ public static synchronized SceneViewerTopComponent findInstance() { TopComponent win = WindowManager.getDefault().findTopComponent(PREFERRED_ID); @@ -454,4 +469,45 @@ protected String preferredID() { public UndoRedo getUndoRedo() { return Lookup.getDefault().lookup(UndoRedo.class); } + + public void applyMaterial(String assetName, Vector2f cursorPosition) { + AssetManager assetManager = app.getAssetManager(); + Spatial spatial = pickWorldSpatial(app.getCamera(), new Vector2f(cursorPosition.x, app.getCamera().getHeight() - cursorPosition.y), app.getRootNode()); + System.out.println("position " + new Vector2f(cursorPosition.x, app.getCamera().getHeight() - cursorPosition.y)); + if (spatial != null) { + Material material = assetManager.loadAsset(new MaterialKey(assetName)); + spatial.setMaterial(material); + } + } + + public void addModel(String assetName, Vector2f cursorPosition) { + AssetManager assetManager = app.getAssetManager(); + Spatial spatial = assetManager.loadModel(assetName); + CollisionResult cr = pick(app.getCamera(), cursorPosition, app.getRootNode()); + spatial.setLocalTranslation(cr != null ? + cr.getContactPoint() : app.getCamera().getWorldCoordinates(cursorPosition, 100f)); + app.getRootNode().attachChild(spatial); + } + + public static Spatial pickWorldSpatial(Camera cam, Vector2f mouseLoc, Node jmeRootNode) { + CollisionResult cr = pick(cam, mouseLoc, jmeRootNode); + if (cr != null) { + return cr.getGeometry(); + } else { + return null; + } + } + + private static CollisionResult pick(Camera cam, Vector2f mouseLoc, Node node) { + CollisionResults results = new CollisionResults(); + Ray ray = new Ray(); + Vector3f pos = cam.getWorldCoordinates(mouseLoc, 0).clone(); + Vector3f dir = cam.getWorldCoordinates(mouseLoc, 0.125f).clone(); + dir.subtractLocal(pos).normalizeLocal(); + ray.setOrigin(pos); + ray.setDirection(dir); + node.collideWith(ray, results); + CollisionResult result = results.getClosestCollision(); + return result; + } } diff --git a/jme3-materialeditor/src/com/jme3/gde/materials/MaterialPreviewOpenSupport.java b/jme3-materialeditor/src/com/jme3/gde/materials/MaterialPreviewOpenSupport.java new file mode 100644 index 000000000..004572f96 --- /dev/null +++ b/jme3-materialeditor/src/com/jme3/gde/materials/MaterialPreviewOpenSupport.java @@ -0,0 +1,30 @@ +/* + * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license + * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template + */ +package com.jme3.gde.materials; + +import com.jme3.gde.materials.JMEMaterialDataObject; +import com.jme3.gde.materials.multiview.MaterialEditorTopComponent; +import org.openide.cookies.CloseCookie; +import org.openide.cookies.OpenCookie; +import org.openide.loaders.OpenSupport; +import org.openide.windows.CloneableTopComponent; + +/** + * + * @author rickard + */ +public class MaterialPreviewOpenSupport extends OpenSupport implements OpenCookie, CloseCookie { + + public MaterialPreviewOpenSupport(JMEMaterialDataObject.Entry entry) { + super(entry); + } + + @Override + protected CloneableTopComponent createCloneableTopComponent() { + JMEMaterialDataObject dobj = (JMEMaterialDataObject) entry.getDataObject(); + MaterialEditorTopComponent tc = new MaterialEditorTopComponent(dobj); + return tc; + } +} diff --git a/jme3-materialeditor/src/com/jme3/gde/materials/dnd/TextureDropTargetListener.java b/jme3-materialeditor/src/com/jme3/gde/materials/dnd/TextureDropTargetListener.java new file mode 100644 index 000000000..fa6a4ae29 --- /dev/null +++ b/jme3-materialeditor/src/com/jme3/gde/materials/dnd/TextureDropTargetListener.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2009-2023 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.gde.materials.dnd; + +import com.jme3.gde.core.dnd.AssetNameHolder; +import com.jme3.gde.core.dnd.TextureDataFlavor; +import java.awt.Cursor; +import java.awt.datatransfer.Transferable; +import java.awt.dnd.DropTargetContext; +import java.awt.dnd.DropTargetDragEvent; +import java.awt.dnd.DropTargetDropEvent; +import java.awt.dnd.DropTargetEvent; +import java.awt.dnd.DropTargetListener; + +/** + * + * @author rickard + */ +public class TextureDropTargetListener implements DropTargetListener { + + private static final Cursor droppableCursor = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR); + private static final Cursor notDroppableCursor = Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR); + + private final TextureDropTarget rootPanel; + + public TextureDropTargetListener(TextureDropTarget rootPanel) { + this.rootPanel = rootPanel; + } + + @Override + public void dragEnter(DropTargetDragEvent dtde) { + } + + @Override + public void dragOver(DropTargetDragEvent dtde) { + if (!this.rootPanel.getCursor().equals(droppableCursor)) { + this.rootPanel.setCursor(droppableCursor); + } + } + + @Override + public void dropActionChanged(DropTargetDragEvent dtde) { + } + + @Override + public void dragExit(DropTargetEvent dte) { + this.rootPanel.setCursor(notDroppableCursor); + } + + @Override + public void drop(DropTargetDropEvent dtde) { + this.rootPanel.setCursor(Cursor.getDefaultCursor()); + + Object transferableObj = null; + try { + + final Transferable transferable = dtde.getTransferable(); + + if (transferable.isDataFlavorSupported(TextureDataFlavor.instance)) { + transferableObj = dtde.getTransferable().getTransferData(TextureDataFlavor.instance); + } + + } catch (Exception ex) { + ex.printStackTrace(); + } + + if (transferableObj == null) { + return; + } + + rootPanel.setTexture("\"" + ((AssetNameHolder) transferableObj).getAssetName() + "\""); + } + + public interface TextureDropTarget { + + void setTexture(String texture); + + void setCursor(Cursor cursor); + + Cursor getCursor(); + } +} diff --git a/jme3-materialeditor/src/com/jme3/gde/materials/multiview/widgets/TexturePanel.java b/jme3-materialeditor/src/com/jme3/gde/materials/multiview/widgets/TexturePanel.java index 5540833ff..d7ace1e31 100644 --- a/jme3-materialeditor/src/com/jme3/gde/materials/multiview/widgets/TexturePanel.java +++ b/jme3-materialeditor/src/com/jme3/gde/materials/multiview/widgets/TexturePanel.java @@ -15,10 +15,13 @@ import com.jme3.gde.core.properties.TexturePropertyEditor; import com.jme3.gde.core.properties.preview.TexturePreview; import com.jme3.gde.materials.MaterialProperty; +import com.jme3.gde.materials.dnd.TextureDropTargetListener; +import com.jme3.gde.materials.dnd.TextureDropTargetListener.TextureDropTarget; import com.jme3.gde.materials.multiview.MaterialEditorTopComponent; import com.jme3.gde.materials.multiview.widgets.icons.Icons; import java.awt.Component; import java.awt.Graphics2D; +import java.awt.dnd.DropTarget; import java.awt.image.BufferedImage; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.logging.Level; @@ -30,7 +33,7 @@ * * @author normenhansen */ -public class TexturePanel extends MaterialPropertyWidget { +public class TexturePanel extends MaterialPropertyWidget implements TextureDropTarget{ private TexturePropertyEditor editor; private ProjectAssetManager manager; @@ -54,6 +57,8 @@ public TexturePanel(ProjectAssetManager manager) { this.manager = manager; editor = new TexturePropertyEditor(manager); initComponents(); + + setDropTarget(new DropTarget(this, new TextureDropTargetListener(this))); } private void displayPreview() { @@ -333,4 +338,23 @@ public void cleanUp() { private javax.swing.JSeparator jSeparator1; private javax.swing.JLabel texturePreview; // End of variables declaration//GEN-END:variables + + @Override + public void setTexture(String name) { + property.setValue(""); + java.awt.EventQueue.invokeLater(() -> { + if(name.startsWith("\"")){ + textureName = name; + } else { + textureName = "\"" + name + "\""; + } + property.setValue(textureName); + displayPreview(); + updateFlipRepeat(); + java.awt.EventQueue.invokeLater(() -> { + fireChanged(); + }); + }); + + } } diff --git a/jme3-materialeditor/src/com/jme3/gde/materials/multiview/widgets/TexturePanelSquare.java b/jme3-materialeditor/src/com/jme3/gde/materials/multiview/widgets/TexturePanelSquare.java index 947d11238..b250d746a 100644 --- a/jme3-materialeditor/src/com/jme3/gde/materials/multiview/widgets/TexturePanelSquare.java +++ b/jme3-materialeditor/src/com/jme3/gde/materials/multiview/widgets/TexturePanelSquare.java @@ -37,8 +37,12 @@ import com.jme3.gde.core.properties.TexturePropertyEditor; import com.jme3.gde.core.properties.preview.TexturePreview; import com.jme3.gde.materials.MaterialProperty; +import com.jme3.gde.core.dnd.AssetNameHolder; +import com.jme3.gde.materials.dnd.TextureDropTargetListener; +import com.jme3.gde.materials.dnd.TextureDropTargetListener.TextureDropTarget; import com.jme3.gde.materials.multiview.MaterialEditorTopComponent; import java.awt.Component; +import java.awt.dnd.DropTarget; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.util.concurrent.ScheduledThreadPoolExecutor; @@ -49,7 +53,7 @@ * A more compact texture panel designed for the shader node editor. * @author rickard */ -public class TexturePanelSquare extends MaterialPropertyWidget { +public class TexturePanelSquare extends MaterialPropertyWidget implements TextureDropTarget { private final TexturePropertyEditor editor; private final ProjectAssetManager manager; @@ -99,6 +103,7 @@ public void mouseEntered(MouseEvent e) { public void mouseExited(MouseEvent e) { } }); + setDropTarget(new DropTarget(this, new TextureDropTargetListener(this))); } private void displayPreview() { @@ -305,4 +310,23 @@ public void cleanUp() { private javax.swing.JPanel jPanel1; private javax.swing.JLabel texturePreview; // End of variables declaration//GEN-END:variables + + @Override + public void setTexture(String name) { + property.setValue(""); + java.awt.EventQueue.invokeLater(() -> { + if(name.startsWith("\"")){ + textureName = name; + } else { + textureName = "\"" + name + "\""; + } + property.setValue(textureName); + displayPreview(); + updateFlipRepeat(); + java.awt.EventQueue.invokeLater(() -> { + fireChanged(); + }); + }); + + } } diff --git a/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/OpenSceneComposer.java b/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/OpenSceneComposer.java index 4216a91e0..c361869da 100644 --- a/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/OpenSceneComposer.java +++ b/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/OpenSceneComposer.java @@ -27,32 +27,26 @@ public void actionPerformed(ActionEvent ev) { if (manager == null) { return; } - Runnable call = new Runnable() { - - public void run() { - ProgressHandle progressHandle = ProgressHandle.createHandle("Opening in SceneComposer"); - progressHandle.start(); - try { - manager.clearCache(); - final Spatial asset = context.loadAsset(); - if (asset != null) { - java.awt.EventQueue.invokeLater(new Runnable() { - - public void run() { - SceneComposerTopComponent composer = SceneComposerTopComponent.findInstance(); - composer.openScene(asset, context, manager); - } - }); - } else { - Confirmation msg = new NotifyDescriptor.Confirmation( - "Error opening " + context.getPrimaryFile().getNameExt(), - NotifyDescriptor.OK_CANCEL_OPTION, - NotifyDescriptor.ERROR_MESSAGE); - DialogDisplayer.getDefault().notify(msg); - } - } finally { - progressHandle.finish(); + Runnable call = () -> { + ProgressHandle progressHandle = ProgressHandle.createHandle("Opening in SceneComposer"); + progressHandle.start(); + try { + manager.clearCache(); + final Spatial asset = context.loadAsset(); + if (asset != null) { + java.awt.EventQueue.invokeLater(() -> { + SceneComposerTopComponent composer = SceneComposerTopComponent.findInstance(); + composer.openScene(asset, context, manager); + }); + } else { + Confirmation msg = new NotifyDescriptor.Confirmation( + "Error opening " + context.getPrimaryFile().getNameExt(), + NotifyDescriptor.OK_CANCEL_OPTION, + NotifyDescriptor.ERROR_MESSAGE); + DialogDisplayer.getDefault().notify(msg); } + } finally { + progressHandle.finish(); } }; new Thread(call).start(); diff --git a/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/layer.xml b/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/layer.xml index 07bba0f5e..6e623878b 100644 --- a/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/layer.xml +++ b/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/layer.xml @@ -66,6 +66,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +