commit e4b7d0f9a84277f846a10b4e931433e8d32c5b15
Author: leszek <leszek@koltunski.pl>
Date:   Wed Mar 12 00:28:25 2025 +0100

    add an 'undo' button to the Bandaged Creators.

diff --git a/src/main/java/org/distorted/bandaged/BandagedRenderer.java b/src/main/java/org/distorted/bandaged/BandagedRenderer.java
index dae7306e..50886904 100644
--- a/src/main/java/org/distorted/bandaged/BandagedRenderer.java
+++ b/src/main/java/org/distorted/bandaged/BandagedRenderer.java
@@ -17,6 +17,7 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
+import java.util.Stack;
 
 import javax.microedition.khronos.egl.EGLConfig;
 import javax.microedition.khronos.opengles.GL10;
@@ -66,7 +67,8 @@ public class BandagedRenderer implements GLSurfaceView.Renderer, DistortedLibrar
    private boolean mInitialPhase;
    private long mStartTime;
    private float mQuatX, mQuatY, mQuatZ, mQuatW;
-   private boolean mResetQuats, mSetQuatT, mResettingObject, mConnectingCubits, mCreatingCubits, mRescaling;
+   private boolean mResetQuats, mSetQuatT, mResettingObject, mConnectingCubits;
+   private boolean mCreatingCubits, mRescaling, mUndoingObject;
    private int mIndex1, mIndex2;
    private int mSaveIcon;
    private DistortedFramebuffer mFramebuffer;
@@ -75,6 +77,8 @@ public class BandagedRenderer implements GLSurfaceView.Renderer, DistortedLibrar
    private int mWidth, mHeight;
    private float mScaleValue, mObjectScreenRatio;
 
+   private final Stack<Integer> mPairs;  // each Integer holds a packed pair in ints
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
    BandagedRenderer(BandagedView v, int ordinal)
@@ -92,6 +96,7 @@ public class BandagedRenderer implements GLSurfaceView.Renderer, DistortedLibrar
      mCubitsCreated    = false;
      mCreatingCubits   = false;
      mRescaling        = false;
+     mUndoingObject    = false;
 
      mSaveIcon = -1;
 
@@ -105,6 +110,8 @@ public class BandagedRenderer implements GLSurfaceView.Renderer, DistortedLibrar
 
      mInitRatio = mObject.getScreenRatio();
      mObjectScreenRatio= mInitRatio;
+
+     mPairs = new Stack<>();
      }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -147,7 +154,11 @@ public class BandagedRenderer implements GLSurfaceView.Renderer, DistortedLibrar
      if( mResettingObject )
        {
        boolean done = continueResetting(time);
-       if( done ) mResettingObject = false;
+       if( done )
+         {
+         mResettingObject = false;
+         mPairs.clear();
+         }
        }
 
      if( mSaveIcon>=0 )
@@ -163,9 +174,24 @@ public class BandagedRenderer implements GLSurfaceView.Renderer, DistortedLibrar
 
      if( mConnectingCubits )
        {
-       mObject.tryConnectingCubits(mIndex1,mIndex2,mScaleValue);
+       boolean success = mObject.tryConnectingCubits(mIndex1,mIndex2,mScaleValue);
+       if( success ) mPairs.add( packTwoIntsIntoPair(mIndex1,mIndex2) );
        mConnectingCubits = false;
        }
+     if( mUndoingObject )
+       {
+       int num = mPairs.size();
+
+       if( num>0 )
+         {
+         int pair  = mPairs.pop();
+         int first = getFirstFromPair(pair);
+         int second= getSecondFromPair(pair);
+         mObject.disconnectCubits(first, second, mScaleValue);
+         }
+
+       mUndoingObject = false;
+       }
 
      if( mCreatingCubits )
        {
@@ -296,6 +322,27 @@ public class BandagedRenderer implements GLSurfaceView.Renderer, DistortedLibrar
        }
      }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+   private int packTwoIntsIntoPair(int index1, int index2)
+     {
+     return (index1<<16) + index2;
+     }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+   private int getFirstFromPair(int pair)
+     {
+     return pair>>16;
+     }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+   private int getSecondFromPair(int pair)
+     {
+     return pair&0xffff;
+     }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
    private boolean createObjectJson(TwistyObject object, Activity act)
@@ -469,6 +516,13 @@ public class BandagedRenderer implements GLSurfaceView.Renderer, DistortedLibrar
      mStartTime       = System.currentTimeMillis();
      }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+   public void setupUndo()
+     {
+     mUndoingObject = true;
+     }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
    public boolean continueResetting(long time)
diff --git a/src/main/java/org/distorted/bandaged/BandagedScreen.java b/src/main/java/org/distorted/bandaged/BandagedScreen.java
index 7965078d..2f608dcc 100644
--- a/src/main/java/org/distorted/bandaged/BandagedScreen.java
+++ b/src/main/java/org/distorted/bandaged/BandagedScreen.java
@@ -36,7 +36,7 @@ import org.distorted.objectlib.bandaged.LocallyBandagedList;
 public class BandagedScreen implements AdapterView.OnItemSelectedListener
 {
   private WeakReference<BandagedActivity> mAct;
-  private TransparentImageButton mBackButton, mResetButton, mDoneButton;
+  private TransparentImageButton mBackButton, mResetButton, mUndoButton, mDoneButton;
   private LinearLayout mObjectView;
   private int mNumObjects, mX, mY, mZ;
   private final ArrayList<BandagedObjectView> mViews;
@@ -96,6 +96,24 @@ public class BandagedScreen implements AdapterView.OnItemSelectedListener
       });
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private void setupUndoButton(final BandagedActivity act)
+    {
+    LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.MATCH_PARENT);
+    mUndoButton = new TransparentImageButton(act,R.drawable.ui_left,params);
+
+    mUndoButton.setOnClickListener( new View.OnClickListener()
+    {
+      @Override
+      public void onClick(View v)
+        {
+        BandagedRenderer renderer = act.getRenderer();
+        if( !renderer.isBusy() ) renderer.setupUndo();
+        }
+    });
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   private void setupResetButton(final BandagedActivity act)
@@ -152,29 +170,35 @@ public class BandagedScreen implements AdapterView.OnItemSelectedListener
     int height = act.getScreenHeightInPixels();
     int padding= (int)(height*BandagedActivity.PADDING/3);
 
-    LinearLayout.LayoutParams paramsL = new LinearLayout.LayoutParams(width/4, LinearLayout.LayoutParams.MATCH_PARENT);
-    LinearLayout.LayoutParams paramsM = new LinearLayout.LayoutParams(width/2, LinearLayout.LayoutParams.MATCH_PARENT);
-    LinearLayout.LayoutParams paramsR = new LinearLayout.LayoutParams(width/4, LinearLayout.LayoutParams.MATCH_PARENT);
+    LinearLayout.LayoutParams params1 = new LinearLayout.LayoutParams(width/4, LinearLayout.LayoutParams.MATCH_PARENT);
+    LinearLayout.LayoutParams params2 = new LinearLayout.LayoutParams(width/4, LinearLayout.LayoutParams.MATCH_PARENT);
+    LinearLayout.LayoutParams params3 = new LinearLayout.LayoutParams(width/4, LinearLayout.LayoutParams.MATCH_PARENT);
+    LinearLayout.LayoutParams params4 = new LinearLayout.LayoutParams(width/4, LinearLayout.LayoutParams.MATCH_PARENT);
 
-    LinearLayout layoutLeft = new LinearLayout(act);
-    layoutLeft.setLayoutParams(paramsL);
-    LinearLayout layoutMid  = new LinearLayout(act);
-    layoutMid.setLayoutParams(paramsM);
-    LinearLayout layoutRight= new LinearLayout(act);
-    layoutRight.setLayoutParams(paramsR);
+    LinearLayout layout1 = new LinearLayout(act);
+    layout1.setLayoutParams(params1);
+    LinearLayout layout2 = new LinearLayout(act);
+    layout2.setLayoutParams(params2);
+    LinearLayout layout3 = new LinearLayout(act);
+    layout3.setLayoutParams(params3);
+    LinearLayout layout4 = new LinearLayout(act);
+    layout4.setLayoutParams(params4);
 
     setupBackButton(act);
-    layoutRight.addView(mBackButton);
+    layout4.addView(mBackButton);
     setupDoneButton(act);
-    layoutMid.addView(mDoneButton);
+    layout3.addView(mDoneButton);
+    setupUndoButton(act);
+    layout2.addView(mUndoButton);
     setupResetButton(act);
-    layoutLeft.addView(mResetButton);
+    layout1.addView(mResetButton);
 
     LinearLayout layout = act.findViewById(R.id.lowerBar);
     layout.removeAllViews();
-    layout.addView(layoutLeft);
-    layout.addView(layoutMid);
-    layout.addView(layoutRight);
+    layout.addView(layout1);
+    layout.addView(layout2);
+    layout.addView(layout3);
+    layout.addView(layout4);
 
     mSpinnerX = act.findViewById(R.id.bandagedCreatorX);
     mSpinnerY = act.findViewById(R.id.bandagedCreatorY);
