Browse Source

Issue #534 fix wobbling GUI when number of decimals change on sliders

rickard 1 year ago
parent
commit
4f261b2ad6

+ 44 - 8
jme3-scenecomposer/src/com/jme3/gde/scenecomposer/CameraPositionTrackerAppState.java

@@ -1,8 +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.scenecomposer;
 
 import com.jme3.app.Application;
 import com.jme3.app.state.BaseAppState;
+import com.jme3.math.Vector3f;
 import com.jme3.renderer.Camera;
+import java.text.DecimalFormat;
 import javax.swing.JLabel;
 import javax.swing.SwingUtilities;
 
@@ -12,8 +45,11 @@ import javax.swing.SwingUtilities;
  * @author MeFisto94
  */
 public class CameraPositionTrackerAppState extends BaseAppState {
-    JLabel lblPos;
-    JLabel lblLookAt;
+    private final JLabel lblPos;
+    private final JLabel lblLookAt;
+    
+    private final Vector3f position = new Vector3f();
+    private final Vector3f direction = new Vector3f();
     
     public CameraPositionTrackerAppState(JLabel lblPos, JLabel lblLookAt) {
         this.lblPos = lblPos;
@@ -37,12 +73,12 @@ public class CameraPositionTrackerAppState extends BaseAppState {
         super.update(tpf);
         
         final Camera cam = getApplication().getCamera();
-        SwingUtilities.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                lblPos.setText(cam.getLocation().toString());
-                lblLookAt.setText(cam.getDirection().toString());
-            }
+        SwingUtilities.invokeLater(() -> {
+            position.set(cam.getLocation());
+            direction.set(cam.getDirection());
+            lblPos.setText(SceneComposerUtil.trimDecimals(position));
+            lblLookAt.setText(SceneComposerUtil.trimDecimals(direction));
         });
     }
+    
 }

+ 40 - 13
jme3-scenecomposer/src/com/jme3/gde/scenecomposer/SceneComposerTopComponent.form

@@ -28,10 +28,10 @@
               <EmptySpace max="-2" attributes="0"/>
               <Component id="sceneInfoPanel" min="-2" max="-2" attributes="0"/>
               <EmptySpace max="-2" attributes="0"/>
-              <Component id="cameraPanel" min="-2" max="-2" attributes="0"/>
-              <EmptySpace max="32767" attributes="0"/>
+              <Component id="cameraPanel" max="32767" attributes="0"/>
+              <EmptySpace max="-2" attributes="0"/>
           </Group>
-          <Component id="jToolBar1" alignment="0" max="32767" attributes="0"/>
+          <Component id="jToolBar1" alignment="0" pref="1231" max="32767" attributes="0"/>
       </Group>
     </DimensionLayout>
     <DimensionLayout dim="1">
@@ -74,13 +74,13 @@
                       <Component id="jLabel10" alignment="0" min="-2" max="-2" attributes="0"/>
                       <Component id="cursorPositionHeader" alignment="0" min="-2" max="-2" attributes="0"/>
                   </Group>
-                  <EmptySpace min="-2" pref="34" max="-2" attributes="0"/>
+                  <EmptySpace type="separate" min="-2" max="-2" attributes="0"/>
                   <Group type="103" groupAlignment="0" attributes="0">
                       <Component id="cursorPositionLabel" min="-2" max="-2" attributes="0"/>
-                      <Component id="jLabel12" alignment="0" min="-2" max="-2" attributes="0"/>
-                      <Component id="jLabel11" alignment="0" min="-2" max="-2" attributes="0"/>
+                      <Component id="cameraDirectionLabel" alignment="0" min="-2" max="-2" attributes="0"/>
+                      <Component id="cameraPositionLabel" alignment="0" min="-2" max="-2" attributes="0"/>
                   </Group>
-                  <EmptySpace pref="134" max="32767" attributes="0"/>
+                  <EmptySpace max="32767" attributes="0"/>
               </Group>
               <Group type="102" alignment="0" attributes="0">
                   <Group type="103" groupAlignment="0" attributes="0">
@@ -139,12 +139,12 @@
                   <EmptySpace max="-2" attributes="0"/>
                   <Group type="103" groupAlignment="3" attributes="0">
                       <Component id="jLabel9" alignment="3" min="-2" max="-2" attributes="0"/>
-                      <Component id="jLabel11" alignment="3" min="-2" max="-2" attributes="0"/>
+                      <Component id="cameraPositionLabel" alignment="3" min="-2" max="-2" attributes="0"/>
                   </Group>
                   <EmptySpace max="32767" attributes="0"/>
                   <Group type="103" groupAlignment="3" attributes="0">
                       <Component id="jLabel10" alignment="3" min="-2" max="-2" attributes="0"/>
-                      <Component id="jLabel12" alignment="3" min="-2" max="-2" attributes="0"/>
+                      <Component id="cameraDirectionLabel" alignment="3" min="-2" max="-2" attributes="0"/>
                   </Group>
                   <EmptySpace min="-2" pref="8" max="-2" attributes="0"/>
                   <Group type="103" groupAlignment="3" attributes="0">
@@ -227,17 +227,35 @@
             </Property>
           </Properties>
         </Component>
-        <Component class="javax.swing.JLabel" name="jLabel11">
+        <Component class="javax.swing.JLabel" name="cameraPositionLabel">
           <Properties>
             <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
-              <ResourceString bundle="com/jme3/gde/scenecomposer/Bundle.properties" key="SceneComposerTopComponent.jLabel11.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+              <ResourceString bundle="com/jme3/gde/scenecomposer/Bundle.properties" key="SceneComposerTopComponent.cameraPositionLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+            </Property>
+            <Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+              <Dimension value="[170, 17]"/>
+            </Property>
+            <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+              <Dimension value="[170, 17]"/>
+            </Property>
+            <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+              <Dimension value="[170, 17]"/>
             </Property>
           </Properties>
         </Component>
-        <Component class="javax.swing.JLabel" name="jLabel12">
+        <Component class="javax.swing.JLabel" name="cameraDirectionLabel">
           <Properties>
             <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
-              <ResourceString bundle="com/jme3/gde/scenecomposer/Bundle.properties" key="SceneComposerTopComponent.jLabel12.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+              <ResourceString bundle="com/jme3/gde/scenecomposer/Bundle.properties" key="SceneComposerTopComponent.cameraDirectionLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+            </Property>
+            <Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+              <Dimension value="[170, 17]"/>
+            </Property>
+            <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+              <Dimension value="[170, 17]"/>
+            </Property>
+            <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+              <Dimension value="[170, 17]"/>
             </Property>
           </Properties>
         </Component>
@@ -253,6 +271,15 @@
             <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
               <ResourceString bundle="com/jme3/gde/scenecomposer/Bundle.properties" key="SceneComposerTopComponent.cursorPositionLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
             </Property>
+            <Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+              <Dimension value="[170, 17]"/>
+            </Property>
+            <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+              <Dimension value="[170, 17]"/>
+            </Property>
+            <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+              <Dimension value="[170, 17]"/>
+            </Property>
           </Properties>
         </Component>
         <Component class="javax.swing.JLabel" name="jLabel13">

+ 108 - 70
jme3-scenecomposer/src/com/jme3/gde/scenecomposer/SceneComposerTopComponent.java

@@ -1,6 +1,33 @@
 /*
- * To change this template, choose Tools | Templates
- * and open the template in the editor.
+ *  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.scenecomposer;
 
@@ -112,8 +139,8 @@ public final class SceneComposerTopComponent extends TopComponent implements
         jLabel8 = new javax.swing.JLabel();
         jLabel9 = new javax.swing.JLabel();
         jLabel10 = new javax.swing.JLabel();
-        jLabel11 = new javax.swing.JLabel();
-        jLabel12 = new javax.swing.JLabel();
+        cameraPositionLabel = new javax.swing.JLabel();
+        cameraDirectionLabel = new javax.swing.JLabel();
         cursorPositionHeader = new javax.swing.JLabel();
         cursorPositionLabel = new javax.swing.JLabel();
         jLabel13 = new javax.swing.JLabel();
@@ -211,13 +238,22 @@ public final class SceneComposerTopComponent extends TopComponent implements
 
         org.openide.awt.Mnemonics.setLocalizedText(jLabel10, org.openide.util.NbBundle.getMessage(SceneComposerTopComponent.class, "SceneComposerTopComponent.jLabel10.text")); // NOI18N
 
-        org.openide.awt.Mnemonics.setLocalizedText(jLabel11, org.openide.util.NbBundle.getMessage(SceneComposerTopComponent.class, "SceneComposerTopComponent.jLabel11.text")); // NOI18N
+        org.openide.awt.Mnemonics.setLocalizedText(cameraPositionLabel, org.openide.util.NbBundle.getMessage(SceneComposerTopComponent.class, "SceneComposerTopComponent.cameraPositionLabel.text")); // NOI18N
+        cameraPositionLabel.setMaximumSize(new java.awt.Dimension(170, 17));
+        cameraPositionLabel.setMinimumSize(new java.awt.Dimension(170, 17));
+        cameraPositionLabel.setPreferredSize(new java.awt.Dimension(170, 17));
 
-        org.openide.awt.Mnemonics.setLocalizedText(jLabel12, org.openide.util.NbBundle.getMessage(SceneComposerTopComponent.class, "SceneComposerTopComponent.jLabel12.text")); // NOI18N
+        org.openide.awt.Mnemonics.setLocalizedText(cameraDirectionLabel, org.openide.util.NbBundle.getMessage(SceneComposerTopComponent.class, "SceneComposerTopComponent.cameraDirectionLabel.text")); // NOI18N
+        cameraDirectionLabel.setMaximumSize(new java.awt.Dimension(170, 17));
+        cameraDirectionLabel.setMinimumSize(new java.awt.Dimension(170, 17));
+        cameraDirectionLabel.setPreferredSize(new java.awt.Dimension(170, 17));
 
         org.openide.awt.Mnemonics.setLocalizedText(cursorPositionHeader, org.openide.util.NbBundle.getMessage(SceneComposerTopComponent.class, "SceneComposerTopComponent.cursorPositionHeader.text")); // NOI18N
 
         org.openide.awt.Mnemonics.setLocalizedText(cursorPositionLabel, org.openide.util.NbBundle.getMessage(SceneComposerTopComponent.class, "SceneComposerTopComponent.cursorPositionLabel.text")); // NOI18N
+        cursorPositionLabel.setMaximumSize(new java.awt.Dimension(170, 17));
+        cursorPositionLabel.setMinimumSize(new java.awt.Dimension(170, 17));
+        cursorPositionLabel.setPreferredSize(new java.awt.Dimension(170, 17));
 
         org.openide.awt.Mnemonics.setLocalizedText(jLabel13, org.openide.util.NbBundle.getMessage(SceneComposerTopComponent.class, "SceneComposerTopComponent.jLabel13.text")); // NOI18N
 
@@ -246,12 +282,12 @@ public final class SceneComposerTopComponent extends TopComponent implements
                     .addComponent(jLabel9)
                     .addComponent(jLabel10)
                     .addComponent(cursorPositionHeader))
-                .addGap(34, 34, 34)
+                .addGap(18, 18, 18)
                 .addGroup(cameraPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
-                    .addComponent(cursorPositionLabel)
-                    .addComponent(jLabel12)
-                    .addComponent(jLabel11))
-                .addContainerGap(134, Short.MAX_VALUE))
+                    .addComponent(cursorPositionLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                    .addComponent(cameraDirectionLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                    .addComponent(cameraPositionLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
             .addGroup(cameraPanelLayout.createSequentialGroup()
                 .addGroup(cameraPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                     .addComponent(jLabel7)
@@ -296,15 +332,15 @@ public final class SceneComposerTopComponent extends TopComponent implements
                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                 .addGroup(cameraPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                     .addComponent(jLabel9)
-                    .addComponent(jLabel11))
+                    .addComponent(cameraPositionLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                 .addGroup(cameraPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                     .addComponent(jLabel10)
-                    .addComponent(jLabel12))
+                    .addComponent(cameraDirectionLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                 .addGap(8, 8, 8)
                 .addGroup(cameraPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                     .addComponent(cursorPositionHeader)
-                    .addComponent(cursorPositionLabel)))
+                    .addComponent(cursorPositionLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))
         );
 
         jToolBar1.setRollover(true);
@@ -759,9 +795,9 @@ public final class SceneComposerTopComponent extends TopComponent implements
                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                 .addComponent(sceneInfoPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
-                .addComponent(cameraPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
-                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
-            .addComponent(jToolBar1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                .addComponent(cameraPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                .addContainerGap())
+            .addComponent(jToolBar1, javax.swing.GroupLayout.DEFAULT_SIZE, 1231, Short.MAX_VALUE)
         );
         layout.setVerticalGroup(
             layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
@@ -897,42 +933,30 @@ private void jToggleSelectGeomActionPerformed(java.awt.event.ActionEvent evt) {/
         toolController.setTransformationType(transformationTypeComboBox.getItemAt(transformationTypeComboBox.getSelectedIndex()));
     }//GEN-LAST:event_transformationTypeComboBoxActionPerformed
 
-    private void jSlider1StateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_jSlider1StateChanged
-        // This is called, when the slider of the near plane has been dragged.
-        float near = ((float)jSlider1.getValue() / 1000f);
-        
-        // Prevent an endless loop of state changes
-        if (!FastMath.approximateEquals((Float)(jSpinner1.getValue()), near)) {
-            jSpinner1.setValue(near);
-        }
-    }//GEN-LAST:event_jSlider1StateChanged
-
-    private void jSlider2StateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_jSlider2StateChanged
-        // This is called, when the slider of the far plane has been dragged.
-        float far = jSlider2.getValue();
-        
-        // Prevent an endless loop of state changes
-        if (!FastMath.approximateEquals((Float)(jSpinner2.getValue()), far)) {
-            jSpinner2.setValue(far);
-        }
-    }//GEN-LAST:event_jSlider2StateChanged
-
-    private void jSpinner1StateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_jSpinner1StateChanged
+    private void fovSpinnerStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_fovSpinnerStateChanged
         // This is called, when the spinner of the near plane has been changed.
-        float near = ((float)jSlider1.getValue() / 1000f);
-        float spin = (Float)jSpinner1.getValue();
-        float fov = (int) fovSpinner.getValue();
+        int fov = (int) fovSpinner.getValue();
+
         // Prevent an endless loop of state changes and don't change the slider when the spinner
         // has gone out of range, since this would lead to the slider's StateChanged overwriting the spinner again.
         // but we want the spinner to be a free-form field
-        
-        if (spin <= 2000f && spin >= 100f && !FastMath.approximateEquals((Float)(jSpinner1.getValue()), near)) {
-            jSlider1.setValue((int)((Float)(jSpinner1.getValue()) * 1000f));
+
+        if (fov <= 360 && fov >= 1 && fovSlider.getValue() != fov) {
+            fovSlider.setValue((int) fovSpinner.getValue());
         }
-        
+
         final Camera cam = SceneApplication.getApplication().getCamera();
-        cam.setFrustumPerspective(fov, (float)cam.getWidth() / cam.getHeight(), spin, cam.getFrustumFar());
-    }//GEN-LAST:event_jSpinner1StateChanged
+        cam.setFrustumPerspective(fov, (float)cam.getWidth() / cam.getHeight(), cam.getFrustumNear(), cam.getFrustumFar());
+    }//GEN-LAST:event_fovSpinnerStateChanged
+
+    private void fovSliderStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_fovSliderStateChanged
+        int fov = (int) fovSlider.getValue();
+
+        // Prevent an endless loop of state changes
+        if ((int) fovSpinner.getValue() != fov) {
+            fovSpinner.setValue((int) fov);
+        }
+    }//GEN-LAST:event_fovSliderStateChanged
 
     private void jSpinner2StateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_jSpinner2StateChanged
         // Prevent an endless loop of state changes and don't change the slider when the spinner
@@ -943,39 +967,53 @@ private void jToggleSelectGeomActionPerformed(java.awt.event.ActionEvent evt) {/
         if (spin <= 3000f && spin >= 5f && !FastMath.approximateEquals(spin, (float)jSlider2.getValue())) {
             jSlider2.setValue((int)spin);
         }
-        
+
         final Camera cam = SceneApplication.getApplication().getCamera();
         cam.setFrustumPerspective(fov, (float)cam.getWidth() / cam.getHeight(), cam.getFrustumNear(), spin);
     }//GEN-LAST:event_jSpinner2StateChanged
 
-    private void fovSliderStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_fovSliderStateChanged
-        int fov = (int) fovSlider.getValue();
-        
-        // Prevent an endless loop of state changes
-        if ((int) fovSpinner.getValue() != fov) {
-            fovSpinner.setValue((int) fov);
-        }
-    }//GEN-LAST:event_fovSliderStateChanged
-
-    private void fovSpinnerStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_fovSpinnerStateChanged
+    private void jSpinner1StateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_jSpinner1StateChanged
         // This is called, when the spinner of the near plane has been changed.
-        int fov = (int) fovSpinner.getValue();
-        
+        float near = ((float)jSlider1.getValue() / 1000f);
+        float spin = (Float)jSpinner1.getValue();
+        float fov = (int) fovSpinner.getValue();
         // Prevent an endless loop of state changes and don't change the slider when the spinner
         // has gone out of range, since this would lead to the slider's StateChanged overwriting the spinner again.
         // but we want the spinner to be a free-form field
-        
-        if (fov <= 360 && fov >= 1 && fovSlider.getValue() != fov) {
-            fovSlider.setValue((int) fovSpinner.getValue());
+
+        if (spin <= 2000f && spin >= 100f && !FastMath.approximateEquals((Float)(jSpinner1.getValue()), near)) {
+            jSlider1.setValue((int)((Float)(jSpinner1.getValue()) * 1000f));
         }
-        
+
         final Camera cam = SceneApplication.getApplication().getCamera();
-        cam.setFrustumPerspective(fov, (float)cam.getWidth() / cam.getHeight(), cam.getFrustumNear(), cam.getFrustumFar());
-    }//GEN-LAST:event_fovSpinnerStateChanged
+        cam.setFrustumPerspective(fov, (float)cam.getWidth() / cam.getHeight(), spin, cam.getFrustumFar());
+    }//GEN-LAST:event_jSpinner1StateChanged
+
+    private void jSlider2StateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_jSlider2StateChanged
+        // This is called, when the slider of the far plane has been dragged.
+        float far = jSlider2.getValue();
+
+        // Prevent an endless loop of state changes
+        if (!FastMath.approximateEquals((Float)(jSpinner2.getValue()), far)) {
+            jSpinner2.setValue(far);
+        }
+    }//GEN-LAST:event_jSlider2StateChanged
+
+    private void jSlider1StateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_jSlider1StateChanged
+        // This is called, when the slider of the near plane has been dragged.
+        float near = ((float)jSlider1.getValue() / 1000f);
+
+        // Prevent an endless loop of state changes
+        if (!FastMath.approximateEquals((Float)(jSpinner1.getValue()), near)) {
+            jSpinner1.setValue(near);
+        }
+    }//GEN-LAST:event_jSlider1StateChanged
 
     // Variables declaration - do not modify//GEN-BEGIN:variables
     private javax.swing.JButton camToCursorSelectionButton;
+    private javax.swing.JLabel cameraDirectionLabel;
     private javax.swing.JPanel cameraPanel;
+    private javax.swing.JLabel cameraPositionLabel;
     private javax.swing.JButton createPhysicsMeshButton;
     private javax.swing.JLabel cursorPositionHeader;
     private javax.swing.JLabel cursorPositionLabel;
@@ -991,8 +1029,6 @@ private void jToggleSelectGeomActionPerformed(java.awt.event.ActionEvent evt) {/
     private javax.swing.JCheckBox jCheckBox1;
     private javax.swing.JLabel jLabel1;
     private javax.swing.JLabel jLabel10;
-    private javax.swing.JLabel jLabel11;
-    private javax.swing.JLabel jLabel12;
     private javax.swing.JLabel jLabel13;
     private javax.swing.JLabel jLabel2;
     private javax.swing.JLabel jLabel3;
@@ -1372,7 +1408,7 @@ private void jToggleSelectGeomActionPerformed(java.awt.event.ActionEvent evt) {/
             camController.setMaster(this);
             camController.enable();
             
-            cameraPositionTrackerAppState = new CameraPositionTrackerAppState(jLabel11, jLabel12);
+            cameraPositionTrackerAppState = new CameraPositionTrackerAppState(cameraPositionLabel, cameraDirectionLabel);
             SceneApplication.getApplication().getStateManager().attach(cameraPositionTrackerAppState);
 
             toolController.createOnTopToolNode();
@@ -1474,8 +1510,10 @@ private void jToggleSelectGeomActionPerformed(java.awt.event.ActionEvent evt) {/
 
     @Override
     public void onSetCursorLocation(final Vector3f location) {
+
         SwingUtilities.invokeLater(() -> {
-            cursorPositionLabel.setText(location.toString());
+            cursorPositionLabel.setText(
+                    SceneComposerUtil.trimDecimals(location));
         });
     }
 }

+ 55 - 0
jme3-scenecomposer/src/com/jme3/gde/scenecomposer/SceneComposerUtil.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.scenecomposer;
+
+import com.jme3.math.Vector3f;
+
+/**
+ *
+ * @author rickard
+ */
+
+class SceneComposerUtil {
+
+    /**
+     * Convenience method to trim decimals on a Vector3f to max 4
+     *
+     * @param vector3f
+     * @return trimmed Vector3f in String format
+     */
+    static String trimDecimals(Vector3f vector3f) {
+        return String.format("%s, %s, %s",
+                String.format("%.4f", vector3f.x),
+                String.format("%.4f", vector3f.y),
+                String.format("%.4f", vector3f.z));
+    }
+}