commit 53f23b64507b4d1e8fc85bde53e6bb8222fbe704
Author: Leszek Koltunski <leszek@koltunski.pl>
Date:   Fri Mar 27 01:08:37 2020 +0000

    Progress with Pretty Patterns - do away with the tabbed dialog!

diff --git a/src/main/java/org/distorted/dialog/RubikDialogNewRecord.java b/src/main/java/org/distorted/dialog/RubikDialogNewRecord.java
index e684e625..05bf6b92 100644
--- a/src/main/java/org/distorted/dialog/RubikDialogNewRecord.java
+++ b/src/main/java/org/distorted/dialog/RubikDialogNewRecord.java
@@ -85,8 +85,9 @@ public class RubikDialogNewRecord extends AppCompatDialogFragment
           RubikStatePlay play = (RubikStatePlay) RubikState.PLAY.getStateClass();
           int object = play.getObject();
           int size   = play.getSize();
+          int sizeIndex = RubikObjectList.getSizeIndex(object,size);
 
-          bundle.putInt("tab", RubikObjectList.pack(object,size) );
+          bundle.putInt("tab", RubikObjectList.pack(object,sizeIndex) );
           bundle.putBoolean("submitting", true);
 
           RubikDialogScores scoresDiag = new RubikDialogScores();
diff --git a/src/main/java/org/distorted/dialog/RubikDialogPattern.java b/src/main/java/org/distorted/dialog/RubikDialogPattern.java
deleted file mode 100644
index c760296c..00000000
--- a/src/main/java/org/distorted/dialog/RubikDialogPattern.java
+++ /dev/null
@@ -1,112 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// Copyright 2019 Leszek Koltunski                                                               //
-//                                                                                               //
-// This file is part of Magic Cube.                                                              //
-//                                                                                               //
-// Magic Cube is free software: you can redistribute it and/or modify                            //
-// it under the terms of the GNU General Public License as published by                          //
-// the Free Software Foundation, either version 2 of the License, or                             //
-// (at your option) any later version.                                                           //
-//                                                                                               //
-// Magic Cube is distributed in the hope that it will be useful,                                 //
-// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
-// GNU General Public License for more details.                                                  //
-//                                                                                               //
-// You should have received a copy of the GNU General Public License                             //
-// along with Magic Cube.  If not, see <http://www.gnu.org/licenses/>.                           //
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-package org.distorted.dialog;
-
-import android.app.Dialog;
-import android.content.DialogInterface;
-import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.v4.app.FragmentActivity;
-import android.support.v4.view.ViewPager;
-import android.support.v7.app.AlertDialog;
-import android.support.v7.app.AppCompatDialogFragment;
-import android.support.design.widget.TabLayout;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.Window;
-import android.view.WindowManager;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import org.distorted.magic.R;
-import org.distorted.patterns.RubikPattern;
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-public class RubikDialogPattern extends AppCompatDialogFragment
-  {
-  RubikDialogPatternPagerAdapter mPagerAdapter;
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  @Override
-  public void onStart()
-    {
-    super.onStart();
-
-    Window window = getDialog().getWindow();
-    window.setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
-                    WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);
-    window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  @NonNull
-  @Override
-  public Dialog onCreateDialog(Bundle savedInstanceState)
-    {
-    FragmentActivity act = getActivity();
-    AlertDialog.Builder builder = new AlertDialog.Builder(act);
-
-    LayoutInflater layoutInflater = act.getLayoutInflater();
-    TextView tv = (TextView) layoutInflater.inflate(R.layout.dialog_title, null);
-    tv.setText(R.string.patterns);
-    builder.setCustomTitle(tv);
-
-    builder.setCancelable(true);
-    builder.setPositiveButton( R.string.ok, new DialogInterface.OnClickListener()
-      {
-      @Override
-      public void onClick(DialogInterface dialog, int which)
-        {
-
-        }
-      });
-
-    LayoutInflater inflater = act.getLayoutInflater();
-    final View view = inflater.inflate(R.layout.dialog_tabbed, null);
-    builder.setView(view);
-
-    ViewPager viewPager = view.findViewById(R.id.viewpager);
-    TabLayout tabLayout = view.findViewById(R.id.sliding_tabs);
-    mPagerAdapter = new RubikDialogPatternPagerAdapter(act, viewPager, this);
-    tabLayout.setupWithViewPager(viewPager);
-
-    int[] iconID = { R.drawable.cube2, R.drawable.cube3, R.drawable.cube4, R.drawable.cube5 };
-
-    for(int i=0; i< RubikPattern.NUM_CUBES; i++)
-      {
-      ImageView imageView = new ImageView(act);
-      imageView.setImageResource(iconID[i]);
-      TabLayout.Tab tab = tabLayout.getTabAt(i);
-      if(tab!=null) tab.setCustomView(imageView);
-      }
-
-    return builder.create();
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  public static String getDialogTag()
-    {
-    return "DialogPattern";
-    }
-  }
diff --git a/src/main/java/org/distorted/dialog/RubikDialogPatternPagerAdapter.java b/src/main/java/org/distorted/dialog/RubikDialogPatternPagerAdapter.java
deleted file mode 100644
index 91f44ab1..00000000
--- a/src/main/java/org/distorted/dialog/RubikDialogPatternPagerAdapter.java
+++ /dev/null
@@ -1,106 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// Copyright 2020 Leszek Koltunski                                                               //
-//                                                                                               //
-// This file is part of Magic Cube.                                                              //
-//                                                                                               //
-// Magic Cube is free software: you can redistribute it and/or modify                            //
-// it under the terms of the GNU General Public License as published by                          //
-// the Free Software Foundation, either version 2 of the License, or                             //
-// (at your option) any later version.                                                           //
-//                                                                                               //
-// Magic Cube is distributed in the hope that it will be useful,                                 //
-// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
-// GNU General Public License for more details.                                                  //
-//                                                                                               //
-// You should have received a copy of the GNU General Public License                             //
-// along with Magic Cube.  If not, see <http://www.gnu.org/licenses/>.                           //
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-package org.distorted.dialog;
-
-import android.support.annotation.NonNull;
-import android.support.v4.app.FragmentActivity;
-import android.support.v4.view.PagerAdapter;
-import android.support.v4.view.ViewPager;
-import android.view.View;
-import android.view.ViewGroup;
-
-import org.distorted.patterns.RubikPattern;
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-class RubikDialogPatternPagerAdapter extends PagerAdapter
-  {
-  private FragmentActivity mAct;
-  private RubikDialogPatternView[] mViews;
-  private RubikDialogPattern mDialog;
-  private int mNumTabs;
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  private String[] createCategories(int pos)
-    {
-    RubikPattern pattern = RubikPattern.getInstance();
-    int numCat = pattern.getNumCategories(pos);
-
-    String[] ret = new String[numCat];
-
-    for(int i=0; i<numCat; i++)
-      {
-      ret[i] = pattern.getCategoryName(pos,i);
-      }
-
-    return ret;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  RubikDialogPatternPagerAdapter(FragmentActivity act, ViewPager viewPager, RubikDialogPattern dialog)
-    {
-    mAct = act;
-    mDialog = dialog;
-    mNumTabs = RubikPattern.NUM_CUBES;
-    mViews = new RubikDialogPatternView[mNumTabs];
-
-    viewPager.setAdapter(this);
-    viewPager.setOffscreenPageLimit(mNumTabs-1);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  @Override
-  @NonNull
-  public Object instantiateItem(@NonNull ViewGroup collection, final int position)
-    {
-    String[] categories = createCategories(position);
-    mViews[position] = new RubikDialogPatternView(mAct, mDialog, categories);
-    collection.addView(mViews[position]);
-
-    return mViews[position];
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  @Override
-  public void destroyItem(ViewGroup collection, int position, @NonNull Object view)
-    {
-    collection.removeView((View) view);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  @Override
-  public int getCount()
-    {
-    return mNumTabs;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  @Override
-  public boolean isViewFromObject(@NonNull View view, @NonNull Object object)
-    {
-    return view == object;
-    }
-  }
diff --git a/src/main/java/org/distorted/dialog/RubikDialogPatternView.java b/src/main/java/org/distorted/dialog/RubikDialogPatternView.java
deleted file mode 100644
index 46b65c95..00000000
--- a/src/main/java/org/distorted/dialog/RubikDialogPatternView.java
+++ /dev/null
@@ -1,101 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// Copyright 2020 Leszek Koltunski                                                               //
-//                                                                                               //
-// This file is part of Magic Cube.                                                              //
-//                                                                                               //
-// Magic Cube is free software: you can redistribute it and/or modify                            //
-// it under the terms of the GNU General Public License as published by                          //
-// the Free Software Foundation, either version 2 of the License, or                             //
-// (at your option) any later version.                                                           //
-//                                                                                               //
-// Magic Cube is distributed in the hope that it will be useful,                                 //
-// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
-// GNU General Public License for more details.                                                  //
-//                                                                                               //
-// You should have received a copy of the GNU General Public License                             //
-// along with Magic Cube.  If not, see <http://www.gnu.org/licenses/>.                           //
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-package org.distorted.dialog;
-
-import android.content.Context;
-import android.support.v4.app.FragmentActivity;
-import android.util.AttributeSet;
-import android.util.DisplayMetrics;
-import android.view.View;
-import android.widget.Button;
-import android.widget.FrameLayout;
-import android.widget.LinearLayout;
-
-import org.distorted.magic.R;
-import org.distorted.magic.RubikActivity;
-import org.distorted.uistate.RubikState;
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-public class RubikDialogPatternView extends FrameLayout
-  {
-  private LinearLayout mLayout;
-  private RubikDialogPattern mDialog;
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  public RubikDialogPatternView(Context context, AttributeSet attrs, int defStyle)
-    {
-    super(context, attrs, defStyle);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  public RubikDialogPatternView(Context context, AttributeSet attrs)
-    {
-    super(context, attrs);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  public RubikDialogPatternView(FragmentActivity act, RubikDialogPattern dialog, String[] categories)
-    {
-    super(act);
-
-    mDialog = dialog;
-    View tab = inflate( act, R.layout.dialog_tab, null);
-    mLayout = tab.findViewById(R.id.tabLayout);
-    createSection(act,categories);
-
-    addView(tab);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  private void createSection(final FragmentActivity act, final String[] categories)
-    {
-    DisplayMetrics metrics = act.getResources().getDisplayMetrics();
-    final float scale = metrics.density;
-    int margin = (int)(3*scale + 0.5f);
-    LinearLayout.LayoutParams bParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.WRAP_CONTENT);
-    bParams.setMargins(margin, margin, margin, margin);
-
-    final RubikActivity ract = (RubikActivity)getContext();
-
-    for(String category: categories)
-      {
-      Button button = new Button(act);
-      button.setLayoutParams(bParams);
-      button.setText(category);
-
-      button.setOnClickListener( new View.OnClickListener()
-        {
-        @Override
-        public void onClick(View view)
-          {
-          RubikState.switchState(ract,RubikState.PATT);
-          mDialog.dismiss();
-          }
-        });
-
-      mLayout.addView(button);
-      }
-    }
-  }
diff --git a/src/main/java/org/distorted/dialog/RubikDialogSetName.java b/src/main/java/org/distorted/dialog/RubikDialogSetName.java
index 85993786..0e7dbadf 100644
--- a/src/main/java/org/distorted/dialog/RubikDialogSetName.java
+++ b/src/main/java/org/distorted/dialog/RubikDialogSetName.java
@@ -122,9 +122,10 @@ public class RubikDialogSetName extends AppCompatDialogFragment
         RubikStatePlay play = (RubikStatePlay) RubikState.PLAY.getStateClass();
         int object = play.getObject();
         int size   = play.getSize();
+        int sizeIndex = RubikObjectList.getSizeIndex(object,size);
 
         Bundle bundle = new Bundle();
-        bundle.putInt("tab", RubikObjectList.pack(object,size) );
+        bundle.putInt("tab", RubikObjectList.pack(object,sizeIndex) );
         bundle.putBoolean("submitting", true);
 
         RubikDialogScores scores = new RubikDialogScores();
diff --git a/src/main/java/org/distorted/magic/RubikActivity.java b/src/main/java/org/distorted/magic/RubikActivity.java
index 8c5f5029..bea57a18 100644
--- a/src/main/java/org/distorted/magic/RubikActivity.java
+++ b/src/main/java/org/distorted/magic/RubikActivity.java
@@ -26,7 +26,6 @@ import android.support.v7.app.AppCompatActivity;
 import android.view.View;
 
 import org.distorted.dialog.RubikDialogAbout;
-import org.distorted.dialog.RubikDialogPattern;
 import org.distorted.dialog.RubikDialogScores;
 import org.distorted.dialog.RubikDialogEffects;
 import org.distorted.effect.BaseEffect;
@@ -88,6 +87,7 @@ public class RubikActivity extends AppCompatActivity
         scores.setCountry(this);
         }
 
+      boolean success = false;
       RubikStatePlay play = (RubikStatePlay)RubikState.PLAY.getStateClass();
       int object = play.getObject();
       int size   = play.getSize();
@@ -96,11 +96,23 @@ public class RubikActivity extends AppCompatActivity
         {
         RubikObjectList obj = RubikObjectList.getObject(object);
         int[] sizes = obj.getSizes();
+        int sizeIndex = RubikObjectList.getSizeIndex(object,size);
 
-        if( size>=0 && size<sizes.length )
+        if( sizeIndex>=0 && sizeIndex<sizes.length )
           {
-          view.getRenderer().createObject( obj, sizes[size] );
+          success = true;
+          view.getRenderer().createObject( obj, size );
           }
+
+        }
+
+      if( !success )
+        {
+        RubikObjectList obj = RubikObjectList.getObject(RubikStatePlay.DEF_OBJECT);
+        int s = RubikStatePlay.DEF_SIZE;
+
+        play.setObjectAndSize(obj,s);
+        view.getRenderer().createObject(obj,s);
         }
       }
     
@@ -163,27 +175,14 @@ public class RubikActivity extends AppCompatActivity
 // PUBLIC API
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-    public void setCanRotate(boolean can)
+    public void changeObject(RubikObjectList object, int size)
       {
       RubikSurfaceView view = findViewById(R.id.rubikSurfaceView);
       RubikRenderer renderer = view.getRenderer();
 
-      renderer.setCanRotate(can);
-      }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-    public void changeObject(int object, int size)
-      {
-      RubikObjectList obj = RubikObjectList.getObject(object);
-      int objectSize = obj.getSizes()[size];
-
-      RubikSurfaceView view = findViewById(R.id.rubikSurfaceView);
-      RubikRenderer renderer = view.getRenderer();
-
       if( renderer.canDrag() )
         {
-        renderer.createObject(obj,objectSize);
+        renderer.createObject(object,size);
         }
       }
 
@@ -217,9 +216,10 @@ public class RubikActivity extends AppCompatActivity
       RubikStatePlay play = (RubikStatePlay) RubikState.PLAY.getStateClass();
       int object = play.getObject();
       int size   = play.getSize();
+      int sizeIndex = RubikObjectList.getSizeIndex(object,size);
 
       Bundle bundle = new Bundle();
-      bundle.putInt("tab", RubikObjectList.pack(object,size) );
+      bundle.putInt("tab", RubikObjectList.pack(object,sizeIndex) );
       bundle.putBoolean("submitting", false);
 
       RubikDialogScores scores = new RubikDialogScores();
@@ -231,8 +231,7 @@ public class RubikActivity extends AppCompatActivity
 
     public void Patterns(View v)
       {
-      RubikDialogPattern diag = new RubikDialogPattern();
-      diag.show(getSupportFragmentManager(), null);
+      RubikState.switchState(this,RubikState.PATT);
       }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/main/java/org/distorted/magic/RubikRenderer.java b/src/main/java/org/distorted/magic/RubikRenderer.java
index 93236598..aa038263 100644
--- a/src/main/java/org/distorted/magic/RubikRenderer.java
+++ b/src/main/java/org/distorted/magic/RubikRenderer.java
@@ -161,17 +161,14 @@ public class RubikRenderer implements GLSurfaceView.Renderer, EffectListener
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-   boolean createObject(RubikObjectList object, int size)
+   void createObject(RubikObjectList object, int size)
      {
      if( (object!=mNextObject || mNextSize!=size) && size>0 )
        {
        mChangeObject = true;
        mNextObject = object;
        mNextSize   = size;
-       return true;
        }
-
-     return false;
      }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/main/java/org/distorted/magic/RubikSurfaceView.java b/src/main/java/org/distorted/magic/RubikSurfaceView.java
index 16b6c1f7..2bb0286b 100644
--- a/src/main/java/org/distorted/magic/RubikSurfaceView.java
+++ b/src/main/java/org/distorted/magic/RubikSurfaceView.java
@@ -162,10 +162,7 @@ public class RubikSurfaceView extends GLSurfaceView
 
     private void setUpDragOrRotate(float x, float y)
       {
-      boolean rota = mRenderer.canRotate();
-      boolean drag = mRenderer.canDrag();
-
-      if( !rota && drag )
+      if( !RubikState.canRotate() )
         {
         mDragging           = true;
         mBeginningRotation  = false;
@@ -180,12 +177,12 @@ public class RubikSurfaceView extends GLSurfaceView
         if( mMovement!=null && mMovement.faceTouched(rotatedTouchPoint1,rotatedCamera) )
           {
           mDragging           = false;
-          mBeginningRotation  = rota;
+          mBeginningRotation  = mRenderer.canRotate();
           mContinuingRotation = false;
           }
         else
           {
-          mDragging           = drag;
+          mDragging           = mRenderer.canDrag();
           mBeginningRotation  = false;
           mContinuingRotation = false;
           }
diff --git a/src/main/java/org/distorted/object/RubikObjectList.java b/src/main/java/org/distorted/object/RubikObjectList.java
index 452926ed..c731f1d2 100644
--- a/src/main/java/org/distorted/object/RubikObjectList.java
+++ b/src/main/java/org/distorted/object/RubikObjectList.java
@@ -141,8 +141,8 @@ public enum RubikObjectList
         {
         if( objects[i].name().equals(name) )
           {
-          int s = getSize(i,size);
-          return pack(i,s);
+          int sizeIndex = getSizeIndex(i,size);
+          return pack(i,sizeIndex);
           }
         }
       }
@@ -198,7 +198,7 @@ public enum RubikObjectList
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  public static int getSize(int ordinal, int size)
+  public static int getSizeIndex(int ordinal, int size)
     {
     int[] sizes = objects[ordinal].getSizes();
     int len = sizes.length;
diff --git a/src/main/java/org/distorted/patterns/RubikPattern.java b/src/main/java/org/distorted/patterns/RubikPattern.java
index 4a1c40e3..78e94214 100644
--- a/src/main/java/org/distorted/patterns/RubikPattern.java
+++ b/src/main/java/org/distorted/patterns/RubikPattern.java
@@ -26,9 +26,9 @@ import android.graphics.Paint;
 
 public class RubikPattern
 {
-  private static final int MIN_CUBE  = 2;
-  private static final int MAX_CUBE  = 5;
-  public  static final int NUM_CUBES = MAX_CUBE-MIN_CUBE+1;
+  public static final int MIN_CUBE  = 2;
+  public static final int MAX_CUBE  = 5;
+  public static final int NUM_CUBES = MAX_CUBE-MIN_CUBE+1;
 
   private int[] numCategories = new int[NUM_CUBES];
   private static String buffer="";
diff --git a/src/main/java/org/distorted/scores/RubikScores.java b/src/main/java/org/distorted/scores/RubikScores.java
index a4789fe0..6935af8d 100644
--- a/src/main/java/org/distorted/scores/RubikScores.java
+++ b/src/main/java/org/distorted/scores/RubikScores.java
@@ -199,7 +199,7 @@ public class RubikScores
     {
     String recordStr, subStr, nameStr, sizeStr, timeStr, submStr;
     int start, end, equals, underscore, comma;
-    int object, size, subm;
+    int object, sizeIndex, subm;
     long time;
 
     for(int scramble=0; scramble<MAX_SCRAMBLE; scramble++)
@@ -231,18 +231,18 @@ public class RubikScores
 
           if( object>=0 && object< NUM_OBJECTS )
             {
-            size = RubikObjectList.getSize(object,Integer.parseInt(sizeStr));
+            sizeIndex = RubikObjectList.getSizeIndex(object,Integer.parseInt(sizeStr));
             time = Long.parseLong(timeStr);
             subm = Integer.parseInt(submStr);
 
-            if( size>=0 && size<MAX_SIZE && subm>=0 && subm<=1 )
+            if( sizeIndex>=0 && sizeIndex<MAX_SIZE && subm>=0 && subm<=1 )
               {
-              mRecords  [object][size][scramble] = time;
-              mSubmitted[object][size][scramble] = subm;
+              mRecords  [object][sizeIndex][scramble] = time;
+              mSubmitted[object][sizeIndex][scramble] = subm;
               }
             else
               {
-              android.util.Log.e("solv", "error: size="+size+" subm="+subm);
+              android.util.Log.e("solv", "error: size="+sizeIndex+" subm="+subm);
               }
             }
           else
diff --git a/src/main/java/org/distorted/uistate/RubikState.java b/src/main/java/org/distorted/uistate/RubikState.java
index 5879a3e1..0809cf1e 100644
--- a/src/main/java/org/distorted/uistate/RubikState.java
+++ b/src/main/java/org/distorted/uistate/RubikState.java
@@ -26,14 +26,15 @@ import org.distorted.magic.RubikActivity;
 
 public enum RubikState
   {
-  MAIN ( null , new RubikStateMain()    ),
-  PLAY ( MAIN , new RubikStatePlay()    ),
-  SOLV ( PLAY , new RubikStateSolving() ),
-  PATT ( MAIN , new RubikStatePattern() ),
+  MAIN ( null , true , new RubikStateMain()    ),
+  PLAY ( MAIN , true , new RubikStatePlay()    ),
+  SOLV ( PLAY , true , new RubikStateSolving() ),
+  PATT ( MAIN , false, new RubikStatePattern() ),
   ;
 
   public static final int LENGTH = values().length;
   private final RubikState mBack;
+  private boolean mCanRotate;
   private final RubikStateAbstract mClass;
   private static final RubikState[] sizes;
 
@@ -65,6 +66,13 @@ public enum RubikState
     return mCurrState;
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public static boolean canRotate()
+    {
+    return mCurrState.mCanRotate;
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   public static void savePreferences(SharedPreferences.Editor editor)
@@ -112,10 +120,11 @@ public enum RubikState
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  RubikState(RubikState back, RubikStateAbstract clazz)
+  RubikState(RubikState back, boolean canRotate, RubikStateAbstract clazz)
     {
-    mBack = back;
-    mClass = clazz;
+    mBack      = back;
+    mCanRotate = canRotate;
+    mClass     = clazz;
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/main/java/org/distorted/uistate/RubikStatePattern.java b/src/main/java/org/distorted/uistate/RubikStatePattern.java
index f3eafa06..ee0564f0 100644
--- a/src/main/java/org/distorted/uistate/RubikStatePattern.java
+++ b/src/main/java/org/distorted/uistate/RubikStatePattern.java
@@ -19,24 +19,34 @@
 
 package org.distorted.uistate;
 
+import android.content.Context;
 import android.content.SharedPreferences;
-import android.support.v4.app.FragmentManager;
+import android.graphics.drawable.BitmapDrawable;
 import android.util.DisplayMetrics;
+import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.widget.Button;
+import android.widget.ImageButton;
 import android.widget.LinearLayout;
+import android.widget.PopupWindow;
 import android.widget.TextView;
 
-import org.distorted.dialog.RubikDialogPattern;
 import org.distorted.magic.R;
 import org.distorted.magic.RubikActivity;
+import org.distorted.object.RubikObjectList;
+import org.distorted.patterns.RubikPattern;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
 public class RubikStatePattern extends RubikStateAbstract
   {
-  private TextView mText;
+  private ImageButton mObjButton;
+  private Button mBackButton;
+  private PopupWindow mPopup;
+  private int mLayoutWidth, mLayoutHeight;
+  private LinearLayout mLayout;
+  private int mSize;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
@@ -49,62 +59,177 @@ public class RubikStatePattern extends RubikStateAbstract
 
   void leaveState(RubikActivity act)
     {
-    act.setCanRotate(true);
+    RubikStatePlay play = (RubikStatePlay)RubikState.PLAY.getStateClass();
+
+    if( !play.setObjectAndSize(RubikObjectList.CUBE, mSize) )
+      {
+      int object= play.getObject();
+      int size  = play.getSize();
+
+      act.changeObject(RubikObjectList.getObject(object),size);
+      }
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   void enterState(final RubikActivity act)
     {
-    act.setCanRotate(false);
+    RubikStatePlay play = (RubikStatePlay)RubikState.PLAY.getStateClass();
+    int obj  = play.getObject();
+    int size = play.getSize();
+
+    if( size>=RubikPattern.MIN_CUBE && size<=RubikPattern.MAX_CUBE && obj==RubikObjectList.CUBE.ordinal() )
+      {
+      mSize = size;
+      }
+    else
+      {
+      mSize = RubikStatePlay.DEF_SIZE;
+      act.changeObject(RubikObjectList.CUBE,mSize);
+      }
 
     LayoutInflater inflater = act.getLayoutInflater();
 
     // TOP ////////////////////////////
     LinearLayout layoutTop = act.findViewById(R.id.mainTitle);
     layoutTop.removeAllViews();
-    mText = (TextView)inflater.inflate(R.layout.upper_text, null);
-    mText.setText(R.string.patterns);
-    layoutTop.addView(mText);
+    TextView text = (TextView)inflater.inflate(R.layout.upper_text, null);
+    text.setText(R.string.patterns);
+    layoutTop.addView(text);
 
     // BOT ////////////////////////////
+    DisplayMetrics metrics = act.getResources().getDisplayMetrics();
+    final float scale = metrics.density;
+
+    if( mObjButton==null ) setupObjectButton(act,scale);
+
     LinearLayout layoutLeft = act.findViewById(R.id.mainBarLeft);
     layoutLeft.removeAllViews();
+    layoutLeft.addView(mObjButton);
+
+    if( mBackButton==null ) setupBackButton(act,scale);
+
     LinearLayout layoutRight = act.findViewById(R.id.mainBarRight);
     layoutRight.removeAllViews();
+    layoutRight.addView(mBackButton);
 
-    DisplayMetrics metrics = act.getResources().getDisplayMetrics();
-    float scale = metrics.density;
-    int padding = (int)(5*scale + 0.5f);
-    LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.MATCH_PARENT);
+    if( mPopup==null ) setupPopupWindow(act, scale);
+    }
 
-    Button button = new Button(act);
-    button.setLayoutParams(params);
-    button.setId(BUTTON_ID_BACK);
-    button.setPadding(padding,0,padding,0);
-    button.setText(R.string.back);
+///////////////////////////////////////////////////////////////////////////////////////////////////
 
-    button.setOnClickListener( new View.OnClickListener()
+  private void setupObjectButton(final RubikActivity act, final float scale)
+    {
+    int padding = (int)(3*scale + 0.5f);
+    LinearLayout.LayoutParams objectParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,LinearLayout.LayoutParams.MATCH_PARENT);
+    mObjButton = new ImageButton(act);
+    mObjButton.setLayoutParams(objectParams);
+    mObjButton.setPadding(padding,0,padding,0);
+    mObjButton.setImageResource(R.drawable.cube_menu);
+
+    mObjButton.setOnClickListener( new View.OnClickListener()
+      {
+      @Override
+      public void onClick(View view)
+        {
+        int total = RubikPattern.NUM_CUBES;
+        boolean vertical = act.isVertical();
+        mLayout.setOrientation(vertical ? LinearLayout.VERTICAL:LinearLayout.HORIZONTAL);
+
+        int height = view.getHeight();
+        int width  = view.getWidth();
+        int laywid = mLayoutWidth * (vertical? 1:total);
+        int layhei = mLayoutHeight* (vertical? total:1);
+
+        mPopup.showAsDropDown(view, (width-laywid)/2, -height-layhei, Gravity.LEFT);
+        }
+      });
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private void setupBackButton(final RubikActivity act, final float scale)
+    {
+    int padding = (int)(3*scale + 0.5f);
+    LinearLayout.LayoutParams backParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.MATCH_PARENT);
+    mBackButton = new Button(act);
+    mBackButton.setLayoutParams(backParams);
+    mBackButton.setId(BUTTON_ID_BACK);
+    mBackButton.setPadding(padding,0,padding,0);
+    mBackButton.setText(R.string.back);
+
+    mBackButton.setOnClickListener( new View.OnClickListener()
       {
       @Override
       public void onClick(View v)
         {
         RubikState.goBack(act);
-
-        FragmentManager mana = act.getSupportFragmentManager();
-        RubikDialogPattern diag = new RubikDialogPattern();
-        diag.show( mana, RubikDialogPattern.getDialogTag() );
         }
       });
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private void setupPopupWindow(final RubikActivity act, final float scale)
+    {
+    LayoutInflater layoutInflater = (LayoutInflater)act.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+    final View layout = layoutInflater.inflate(R.layout.popup_objects, null);
+    mLayout = layout.findViewById(R.id.popup);
 
-    layoutRight.addView(button);
+    mPopup = new PopupWindow(act);
+    mPopup.setContentView(layout);
+    mPopup.setFocusable(true);
+    int margin = (int)(5*scale + 0.5f);
+
+    BitmapDrawable bd = (BitmapDrawable) act.getResources().getDrawable(R.drawable.cube2);
+    int cubeWidth  = bd.getIntrinsicWidth();
+    int cubeHeight = bd.getIntrinsicHeight();
+
+    mLayoutWidth = (int)(cubeWidth + 2*margin + 0.5f);
+    mLayoutHeight= (int)(cubeHeight+ 2*margin + 0.5f);
+
+    final int[] icons = {R.drawable.cube2, R.drawable.cube3, R.drawable.cube4, R.drawable.cube5 };
+    final int[] sizes = {2,3,4,5};
+    int len = icons.length;
+
+    for(int i=0; i<len; i++)
+      {
+      final int size = i;
+
+      LinearLayout.LayoutParams p = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,LinearLayout.LayoutParams.WRAP_CONTENT);
+      p.setMargins(margin, margin, margin, margin);
+
+      ImageButton button = new ImageButton(act);
+      button.setLayoutParams(p);
+
+      button.setBackgroundResource(icons[i]);
+      button.setOnClickListener( new View.OnClickListener()
+        {
+        @Override
+        public void onClick(View v)
+          {
+          mSize = sizes[size];
+          act.changeObject(RubikObjectList.CUBE,sizes[size]);
+          mPopup.dismiss();
+          }
+        });
+
+      mLayout.addView(button);
+      }
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   public void savePreferences(SharedPreferences.Editor editor)
     {
+    mObjButton = null;
+    mBackButton= null;
 
+    if( mPopup!=null )
+      {
+      mPopup.dismiss();
+      mPopup = null;
+      }
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/main/java/org/distorted/uistate/RubikStatePlay.java b/src/main/java/org/distorted/uistate/RubikStatePlay.java
index 83edba92..cb921ca3 100644
--- a/src/main/java/org/distorted/uistate/RubikStatePlay.java
+++ b/src/main/java/org/distorted/uistate/RubikStatePlay.java
@@ -43,8 +43,8 @@ public class RubikStatePlay extends RubikStateAbstract
   private static final int MIN_SCRAMBLE =  1;
   private static final int DEF_SCRAMBLE =  1;
   public  static final int MAX_SCRAMBLE = 18;
-  private static final int DEF_OBJECT   = RubikObjectList.CUBE.ordinal();
-  private static final int DEF_SIZE     =  1;  // i.e. the second from the list of CUBE's sizes
+  public  static final int DEF_OBJECT   = RubikObjectList.CUBE.ordinal();
+  public  static final int DEF_SIZE     =  3;
 
   private ImageButton mObjButton;
   private Button mBackButton;
@@ -174,8 +174,8 @@ public class RubikStatePlay extends RubikStateAbstract
 
     for(int object=0; object<RubikObjectList.NUM_OBJECTS; object++)
       {
-      RubikObjectList list = RubikObjectList.getObject(object);
-      int[] sizes = list.getSizes();
+      final RubikObjectList list = RubikObjectList.getObject(object);
+      final int[] sizes = list.getSizes();
       int[] icons = list.getIconIDs();
       int len = sizes.length;
       final int obj = object;
@@ -197,8 +197,8 @@ public class RubikStatePlay extends RubikStateAbstract
           public void onClick(View v)
             {
             mObject = obj;
-            mSize   = size;
-            act.changeObject(obj,size);
+            mSize   = sizes[size];
+            act.changeObject(list,sizes[size]);
             mPopup.dismiss();
             }
           });
@@ -226,7 +226,7 @@ public class RubikStatePlay extends RubikStateAbstract
     if( mPopup!=null )
       {
       mPopup.dismiss();
-      mPopup     = null;
+      mPopup = null;
       }
     }
 
@@ -239,6 +239,28 @@ public class RubikStatePlay extends RubikStateAbstract
     mSize       = preferences.getInt("statePlay_size"    , DEF_SIZE    );
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public boolean setObjectAndSize(RubikObjectList obj, int size)
+    {
+    boolean success = false;
+
+    for( int s: obj.getSizes() )
+      if( s==size )
+        {
+        success = true;
+        break;
+        }
+
+    if( success )
+      {
+      mObject = obj.ordinal();
+      mSize   = size;
+      }
+
+    return success;
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   public int getPicker()
diff --git a/src/main/java/org/distorted/uistate/RubikStateSolving.java b/src/main/java/org/distorted/uistate/RubikStateSolving.java
index 67bb656b..d9f7e57b 100644
--- a/src/main/java/org/distorted/uistate/RubikStateSolving.java
+++ b/src/main/java/org/distorted/uistate/RubikStateSolving.java
@@ -29,6 +29,7 @@ import android.widget.TextView;
 
 import org.distorted.magic.R;
 import org.distorted.magic.RubikActivity;
+import org.distorted.object.RubikObjectList;
 import org.distorted.scores.RubikScores;
 
 import java.util.Timer;
@@ -173,8 +174,9 @@ public class RubikStateSolving extends RubikStateAbstract
       int object  = play.getObject();
       int size    = play.getSize();
       int scramble= play.getPicker();
+      int realSize= RubikObjectList.getSizeIndex(object,size);
 
-      boolean isNew = mScores.setRecord(object, size, scramble, timeTaken);
+      boolean isNew = mScores.setRecord(object, realSize, scramble, timeTaken);
 
       return isNew ? timeTaken : -timeTaken;
       }
