commit e07c48a220f75069ec705c55d8c51309d1688939
Author: Leszek Koltunski <leszek@koltunski.pl>
Date:   Fri Sep 11 01:17:59 2020 +0100

    Make the ObjectPopup a 2D grid.

diff --git a/src/main/java/org/distorted/objects/RubikObjectList.java b/src/main/java/org/distorted/objects/RubikObjectList.java
index 7cf6a568..b55a868b 100644
--- a/src/main/java/org/distorted/objects/RubikObjectList.java
+++ b/src/main/java/org/distorted/objects/RubikObjectList.java
@@ -74,6 +74,7 @@ public enum RubikObjectList
   private final RubikMovement mObjectMovementClass;
   private static final RubikObjectList[] objects;
   private static int mNumAll;
+  private static int[] mIndices;
 
   static
     {
@@ -84,6 +85,8 @@ public enum RubikObjectList
     int maxLevel= Integer.MIN_VALUE;
     int maxSize = Integer.MIN_VALUE;
 
+    mIndices = new int[] {0,1,2};
+
     for(RubikObjectList object: RubikObjectList.values())
       {
       objects[i] = object;
@@ -104,6 +107,27 @@ public enum RubikObjectList
     MAX_OBJECT_SIZE = maxSize;
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// TODO
+  public static int getColumnCount()
+    {
+    return 3;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// TODO
+  public static int getRowCount()
+    {
+    return 4;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// TODO
+  public static int[] getIndices()
+    {
+    return mIndices;
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   public static RubikObjectList getObject(int ordinal)
diff --git a/src/main/java/org/distorted/states/RubikStatePlay.java b/src/main/java/org/distorted/states/RubikStatePlay.java
index b6b4893c..f4d83928 100644
--- a/src/main/java/org/distorted/states/RubikStatePlay.java
+++ b/src/main/java/org/distorted/states/RubikStatePlay.java
@@ -33,6 +33,7 @@ import android.view.ViewGroup;
 import android.widget.AdapterView;
 import android.widget.ArrayAdapter;
 import android.widget.Button;
+import android.widget.GridLayout;
 import android.widget.ImageButton;
 import android.widget.LinearLayout;
 import android.widget.PopupWindow;
@@ -69,13 +70,14 @@ public class RubikStatePlay extends RubikStateAbstract implements AdapterView.On
   private PopupWindow mObjectPopup, mMenuPopup;
   private int mObject = DEF_OBJECT;
   private int mSize   = DEF_SIZE;
-  private int mObjectLayoutWidth, mMenuLayoutWidth, mMenuLayoutHeight;
-  private LinearLayout mObjectLayout, mMenuLayout;
+  private int mObjectSize, mMenuLayoutWidth, mMenuLayoutHeight;
+  private GridLayout mObjectGrid;
   private AppCompatSpinner mLevelSpinner;
   private ArrayAdapter<String> mSpinnerAdapter;
   private int mLevelValue;
   private int mBarHeight;
-  private float mButtonSize, mTitleSize, mMenuItemSize, mMenuTextSize;
+  private float mButtonSize, mMenuItemSize, mMenuTextSize;
+  private int mColCount, mRowCount;
 
   private ArrayList<Move> mMoves;
   private boolean mCanPrevMove;
@@ -106,7 +108,6 @@ public class RubikStatePlay extends RubikStateAbstract implements AdapterView.On
     float width = act.getScreenWidthInPixels();
     mMenuTextSize = width*RubikActivity.MENU_MEDIUM_TEXT_SIZE;
     mButtonSize   = width*RubikActivity.BUTTON_TEXT_SIZE;
-    mTitleSize    = width*RubikActivity.TITLE_TEXT_SIZE;
     mMenuItemSize = width*RubikActivity.MENU_ITEM_SIZE;
 
     mCanPrevMove = true;
@@ -114,6 +115,9 @@ public class RubikStatePlay extends RubikStateAbstract implements AdapterView.On
     if( mMoves==null ) mMoves = new ArrayList<>();
     else               mMoves.clear();
 
+    mRowCount = RubikObjectList.getRowCount();
+    mColCount = RubikObjectList.getColumnCount();
+
     // TOP ////////////////////////////
     LinearLayout layoutTop = act.findViewById(R.id.upperBar);
     layoutTop.removeAllViews();
@@ -147,9 +151,9 @@ public class RubikStatePlay extends RubikStateAbstract implements AdapterView.On
 
   private void setupObjectButton(final RubikActivity act, final float width)
     {
-    int padding = (int)(width*RubikActivity.PADDING);
-    int margin  = (int)(width*RubikActivity.MARGIN);
-    int icon = RubikActivity.getDrawable(R.drawable.ui_small_cube_menu,R.drawable.ui_medium_cube_menu, R.drawable.ui_big_cube_menu, R.drawable.ui_huge_cube_menu);
+    final int padding = (int)(width*RubikActivity.PADDING);
+    final int margin  = (int)(width*RubikActivity.MARGIN);
+    final int icon = RubikActivity.getDrawable(R.drawable.ui_small_cube_menu,R.drawable.ui_medium_cube_menu, R.drawable.ui_big_cube_menu, R.drawable.ui_huge_cube_menu);
 
     LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.MATCH_PARENT, 1.2f);
     params.topMargin    = margin;
@@ -169,18 +173,14 @@ public class RubikStatePlay extends RubikStateAbstract implements AdapterView.On
         {
         if( act.getPreRender().canPlay() )
           {
-          int total = RubikObjectList.getTotal();
           boolean vertical = act.isVertical();
-          mObjectLayout.setOrientation(vertical ? LinearLayout.VERTICAL:LinearLayout.HORIZONTAL);
-
-          int width  = view.getWidth();
-          int layhei = mObjectLayoutWidth * (vertical? total:1);
-          int laywid = mObjectLayoutWidth * (vertical? 1:total);
-
-          mObjectPopup.showAsDropDown(view, (width-laywid)/2, 0, Gravity.LEFT);
+          mObjectGrid.setOrientation(vertical ? GridLayout.VERTICAL:GridLayout.HORIZONTAL);
+          mObjectPopup.showAsDropDown(view, 0, margin, Gravity.LEFT);
 
           if( android.os.Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1 )
             {
+            int layhei = mObjectSize * (vertical? mRowCount:mColCount);
+            int laywid = mObjectSize * (vertical? mColCount:mRowCount);
             mObjectPopup.update(view, laywid, layhei);
             }
           }
@@ -373,20 +373,34 @@ public class RubikStatePlay extends RubikStateAbstract implements AdapterView.On
     {
     LayoutInflater layoutInflater = (LayoutInflater)act.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
     final View layout = layoutInflater.inflate(R.layout.popup_objects, null);
-    mObjectLayout = layout.findViewById(R.id.popup);
+    mObjectGrid = layout.findViewById(R.id.objectGrid);
+
+    int[] indices = RubikObjectList.getIndices();
+
+    GridLayout.Spec[] rowSpecs = new GridLayout.Spec[mRowCount];
+    GridLayout.Spec[] colSpecs = new GridLayout.Spec[mColCount];
+
+    mObjectGrid.setColumnCount(mColCount);
+    mObjectGrid.setRowCount(mRowCount);
+
+    for(int row=0; row<mRowCount; row++)
+      {
+      rowSpecs[row] = GridLayout.spec(row);
+      }
+    for(int col=0; col<mColCount; col++)
+      {
+      colSpecs[col] = GridLayout.spec(col);
+      }
 
     mObjectPopup = new PopupWindow(act);
     mObjectPopup.setContentView(layout);
     mObjectPopup.setFocusable(true);
-    int margin = (int)(width*RubikActivity.LARGE_MARGIN);
     int icon = RubikActivity.getDrawable(R.drawable.ui_small_cube2,R.drawable.ui_medium_cube2, R.drawable.ui_big_cube2, R.drawable.ui_huge_cube2);
 
     BitmapDrawable bd = (BitmapDrawable) act.getResources().getDrawable(icon);
-    int cubeWidth  = bd.getIntrinsicWidth();
-    mObjectLayoutWidth = (int)(cubeWidth + 2*margin + 0.5f);
-
-    LinearLayout.LayoutParams p = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,LinearLayout.LayoutParams.WRAP_CONTENT);
-    p.setMargins(margin, margin, margin, margin);
+    int cubeWidth = bd.getIntrinsicWidth();
+    int margin = (int)(width*RubikActivity.LARGE_MARGIN);
+    mObjectSize = (int)(cubeWidth + 2*margin + 0.5f);
 
     for(int object=0; object<RubikObjectList.NUM_OBJECTS; object++)
       {
@@ -398,11 +412,9 @@ public class RubikStatePlay extends RubikStateAbstract implements AdapterView.On
 
       for(int i=0; i<len; i++)
         {
-        final int size = i;
+        final int index = i;
 
         ImageButton button = new ImageButton(act);
-        button.setLayoutParams(p);
-
         button.setBackgroundResource(icons[i]);
         button.setOnClickListener( new View.OnClickListener()
           {
@@ -412,8 +424,8 @@ public class RubikStatePlay extends RubikStateAbstract implements AdapterView.On
             if( act.getPreRender().canPlay() && RubikState.getCurrentState()==RubikState.PLAY )
               {
               mObject = obj;
-              mSize   = sizes[size];
-              act.changeObject(list,sizes[size], true);
+              mSize   = sizes[index];
+              act.changeObject(list,sizes[index], true);
               adjustSpinner(act);
               mMoves.clear();
               }
@@ -422,7 +434,13 @@ public class RubikStatePlay extends RubikStateAbstract implements AdapterView.On
             }
           });
 
-        mObjectLayout.addView(button);
+        GridLayout.LayoutParams params = new GridLayout.LayoutParams(rowSpecs[index],colSpecs[indices[object]]);
+        params.bottomMargin = margin;
+        params.topMargin    = margin;
+        params.leftMargin   = margin;
+        params.rightMargin  = margin;
+
+        mObjectGrid.addView(button, params);
         }
       }
     }
@@ -432,8 +450,8 @@ public class RubikStatePlay extends RubikStateAbstract implements AdapterView.On
   private void setupMenuWindow(final RubikActivity act, final float width)
     {
     LayoutInflater layoutInflater = (LayoutInflater)act.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-    final View layout = layoutInflater.inflate(R.layout.popup_objects, null);
-    mMenuLayout = layout.findViewById(R.id.popup);
+    final View layout = layoutInflater.inflate(R.layout.popup_menu, null);
+    LinearLayout menuLayout = layout.findViewById(R.id.menuGrid);
 
     mMenuPopup = new PopupWindow(act);
     mMenuPopup.setContentView(layout);
@@ -464,7 +482,7 @@ public class RubikStatePlay extends RubikStateAbstract implements AdapterView.On
           }
         });
 
-      mMenuLayout.addView(button);
+      menuLayout.addView(button);
       }
 
     mMenuLayoutWidth = (int)(width/2);
diff --git a/src/main/res/layout/popup_menu.xml b/src/main/res/layout/popup_menu.xml
new file mode 100644
index 00000000..dc7eb2d1
--- /dev/null
+++ b/src/main/res/layout/popup_menu.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+   android:id="@+id/menuGrid"
+   android:layout_width="wrap_content"
+   android:layout_height="wrap_content"
+   android:orientation="vertical">
+</LinearLayout>
\ No newline at end of file
diff --git a/src/main/res/layout/popup_objects.xml b/src/main/res/layout/popup_objects.xml
index ecf9f121..3762dd64 100644
--- a/src/main/res/layout/popup_objects.xml
+++ b/src/main/res/layout/popup_objects.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
+   android:id="@+id/objectGrid"
    android:layout_width="wrap_content"
-   android:id="@+id/popup"
-   android:layout_height="wrap_content"
-   android:orientation="vertical" >
-</LinearLayout>
\ No newline at end of file
+   android:layout_height="wrap_content">
+</GridLayout>
\ No newline at end of file
