commit 4f470e00efbc4d178426646791a3a5f85891d5ef
Author: Leszek Koltunski <leszek@koltunski.pl>
Date:   Thu Mar 26 17:34:42 2020 +0000

    Progress with Pretty Patterns.

diff --git a/src/main/java/org/distorted/dialog/RubikDialogPattern.java b/src/main/java/org/distorted/dialog/RubikDialogPattern.java
index ab45ee9c..c760296c 100644
--- a/src/main/java/org/distorted/dialog/RubikDialogPattern.java
+++ b/src/main/java/org/distorted/dialog/RubikDialogPattern.java
@@ -87,7 +87,7 @@ public class RubikDialogPattern extends AppCompatDialogFragment
 
     ViewPager viewPager = view.findViewById(R.id.viewpager);
     TabLayout tabLayout = view.findViewById(R.id.sliding_tabs);
-    mPagerAdapter = new RubikDialogPatternPagerAdapter(act, viewPager);
+    mPagerAdapter = new RubikDialogPatternPagerAdapter(act, viewPager, this);
     tabLayout.setupWithViewPager(viewPager);
 
     int[] iconID = { R.drawable.cube2, R.drawable.cube3, R.drawable.cube4, R.drawable.cube5 };
@@ -102,4 +102,11 @@ public class RubikDialogPattern extends AppCompatDialogFragment
 
     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
index 8cf8b64f..91f44ab1 100644
--- a/src/main/java/org/distorted/dialog/RubikDialogPatternPagerAdapter.java
+++ b/src/main/java/org/distorted/dialog/RubikDialogPatternPagerAdapter.java
@@ -25,7 +25,6 @@ import android.support.v4.view.PagerAdapter;
 import android.support.v4.view.ViewPager;
 import android.view.View;
 import android.view.ViewGroup;
-import android.widget.LinearLayout;
 
 import org.distorted.patterns.RubikPattern;
 
@@ -35,18 +34,21 @@ class RubikDialogPatternPagerAdapter extends PagerAdapter
   {
   private FragmentActivity mAct;
   private RubikDialogPatternView[] mViews;
+  private RubikDialogPattern mDialog;
   private int mNumTabs;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
-// TODO: temporary mockup
 
   private String[] createCategories(int pos)
     {
-    String[] ret = new String[8];
+    RubikPattern pattern = RubikPattern.getInstance();
+    int numCat = pattern.getNumCategories(pos);
 
-    for(int i=0; i<8; i++)
+    String[] ret = new String[numCat];
+
+    for(int i=0; i<numCat; i++)
       {
-      ret[i] = "CATEGORY "+pos+" "+i;
+      ret[i] = pattern.getCategoryName(pos,i);
       }
 
     return ret;
@@ -54,9 +56,10 @@ class RubikDialogPatternPagerAdapter extends PagerAdapter
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  RubikDialogPatternPagerAdapter(FragmentActivity act, ViewPager viewPager)
+  RubikDialogPatternPagerAdapter(FragmentActivity act, ViewPager viewPager, RubikDialogPattern dialog)
     {
     mAct = act;
+    mDialog = dialog;
     mNumTabs = RubikPattern.NUM_CUBES;
     mViews = new RubikDialogPatternView[mNumTabs];
 
@@ -71,7 +74,7 @@ class RubikDialogPatternPagerAdapter extends PagerAdapter
   public Object instantiateItem(@NonNull ViewGroup collection, final int position)
     {
     String[] categories = createCategories(position);
-    mViews[position] = new RubikDialogPatternView(mAct, categories);
+    mViews[position] = new RubikDialogPatternView(mAct, mDialog, categories);
     collection.addView(mViews[position]);
 
     return mViews[position];
diff --git a/src/main/java/org/distorted/dialog/RubikDialogPatternView.java b/src/main/java/org/distorted/dialog/RubikDialogPatternView.java
index 2a21fa8d..a563c05d 100644
--- a/src/main/java/org/distorted/dialog/RubikDialogPatternView.java
+++ b/src/main/java/org/distorted/dialog/RubikDialogPatternView.java
@@ -29,12 +29,15 @@ 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
   {
-  LinearLayout mLayout;
+  private LinearLayout mLayout;
+  private RubikDialogPattern mDialog;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
@@ -52,10 +55,11 @@ public class RubikDialogPatternView extends FrameLayout
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  public RubikDialogPatternView(FragmentActivity act, String[] categories)
+  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);
@@ -65,7 +69,7 @@ public class RubikDialogPatternView extends FrameLayout
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  private void createSection(FragmentActivity act, final String[] categories)
+  private void createSection(final FragmentActivity act, final String[] categories)
     {
     DisplayMetrics metrics = act.getResources().getDisplayMetrics();
     final float scale = metrics.density;
@@ -74,6 +78,8 @@ public class RubikDialogPatternView extends FrameLayout
     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(int i=0; i<len; i++)
       {
       final int fi = i;
@@ -86,7 +92,8 @@ public class RubikDialogPatternView extends FrameLayout
         @Override
         public void onClick(View view)
           {
-          android.util.Log.e("view", "category "+categories[fi]+" clicked");
+          RubikState.switchState(ract,RubikState.PATT);
+          mDialog.dismiss();
           }
         });
 
diff --git a/src/main/java/org/distorted/patterns/RubikPattern.java b/src/main/java/org/distorted/patterns/RubikPattern.java
index adcecdff..4a1c40e3 100644
--- a/src/main/java/org/distorted/patterns/RubikPattern.java
+++ b/src/main/java/org/distorted/patterns/RubikPattern.java
@@ -30,13 +30,15 @@ public class RubikPattern
   private static final int MAX_CUBE  = 5;
   public  static final int NUM_CUBES = MAX_CUBE-MIN_CUBE+1;
 
-  public int[] numCategories = new int[NUM_CUBES];
+  private int[] numCategories = new int[NUM_CUBES];
   private static String buffer="";
   private static Paint mPaint = new Paint();
-  private static int width;
+  private static int mWidth;
 
   private Vector<Category>[] mCategories;
 
+  private static RubikPattern mThis;
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   private class Category
@@ -46,64 +48,64 @@ public class RubikPattern
     private Vector<Pattern> patterns;
     private int curPattern;
 
-    public Category(String n)
+    Category(String n)
       {
       name=n;
       curPattern=0;
       numpatterns=0;
       patterns = new Vector<>();
       }
-    public void addPattern(Pattern p)
+    void addPattern(Pattern p)
       {
       patterns.addElement(p);
       numpatterns++;
       }
-    public int getNumPatterns()
+    int getNumPatterns()
     {
     return numpatterns;
-    };
-    public String getName()
+    }
+    String getName()
     {
     return name;
     }
-    public void next()
+    void next()
       {
       curPattern++;
       if( curPattern>=numpatterns )
         curPattern=0;
       }
-    public void prev()
+    void prev()
       {
       curPattern--;
       if( curPattern<0 )
         curPattern=numpatterns-1;
       }
-    public String getPatternName()
+    String getPatternName()
       {
       Pattern p = patterns.elementAt(curPattern);
       return  p!=null ? p.getName(curPattern+1,numpatterns):null;
       }
-    public int getPatternCurMove()
+    int getPatternCurMove()
       {
       Pattern p = patterns.elementAt(curPattern);
       return  p!=null ? p.getCurMove():-1;
       }
-    public int getPatternNumMove()
+    int getPatternNumMove()
       {
       Pattern p = patterns.elementAt(curPattern);
       return  p!=null ? p.getNumMove():-1;
       }
-    public void initializeCube()
+    void initializeCube()
       {
       Pattern p = patterns.elementAt(curPattern);
       if( p!=null ) p.initializeCube();
       }
-    public void makeNextMove()
+    void makeNextMove()
       {
       Pattern p = patterns.elementAt(curPattern);
       if( p!=null ) p.makeNextMove();
       }
-    public void makePrevMove()
+    void makePrevMove()
       {
       Pattern p = patterns.elementAt(curPattern);
       if( p!=null ) p.makePrevMove();
@@ -120,27 +122,27 @@ public class RubikPattern
     private int curmove;
     private int nummove;
 
-    public Pattern(String n, String m)
+    Pattern(String n, String m)
       {
       name=n;
       moves=m;
       nummove = moves.length()/4;
       curmove=nummove;
       }
-    public String getName(int cur,int num)
+    String getName(int cur,int num)
       {
       if( shortname==null ) shortname=cutPatternName(name);
       return shortname;
       }
-    public int getNumMove()
+    int getNumMove()
     {
     return nummove;
     }
-    public int getCurMove()
+    int getCurMove()
     {
     return curmove;
     }
-    public void makeNextMove()
+    void makeNextMove()
       {
       curmove++;
       if( curmove>nummove)
@@ -150,14 +152,13 @@ public class RubikPattern
         }
       else
         {
-
 // TODO
 //        RubikCube cube = world.getCube();
 //        if( cube!=null && !cube.makeMove(moves.substring(4*curmove-4,4*curmove)) )
           curmove--;
         }
       }
-    public void makePrevMove()
+    void makePrevMove()
       {
       curmove--;
       if( curmove<0)
@@ -173,7 +174,7 @@ public class RubikPattern
           curmove++;
         }
       }
-    public void initializeCube()
+    void initializeCube()
       {
 // TODO
 //	    RubikCube cube = world.getCube();
@@ -183,12 +184,12 @@ public class RubikPattern
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  public RubikPattern(int wi, int h)
+  private RubikPattern()
     {
-    width = wi;
+    mPaint.setTextSize(24);
+    mWidth = 200;
     mCategories = new Vector[NUM_CUBES];
-    mPaint.setTextSize(h);
-  
+
     initializeCategories(0, RubikPatternData2.patterns);
     initializeCategories(1, RubikPatternData3.patterns);
     initializeCategories(2, RubikPatternData4.patterns);
@@ -232,12 +233,12 @@ public class RubikPattern
   private static String cutPatternName(String n)
     {
     int len1 = (int)mPaint.measureText(n);
-  
-    if( len1>width )
+
+    if( len1>mWidth )
       {
       int l = n.length();
 
-      while( l>=2 && len1>width )
+      while( l>=2 && len1>mWidth )
         {
         l--;
         buffer = n.substring(0,l);
@@ -250,13 +251,27 @@ public class RubikPattern
     return n;
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// PUBLIC API
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public static RubikPattern getInstance()
+    {
+    if( mThis==null )
+      {
+      mThis = new RubikPattern();
+      }
+
+    return mThis;
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   public String getCategoryName(int size,int num)
     {
-    if( size>=MIN_CUBE && size<=MAX_CUBE && num>=0 && num< numCategories[size-MIN_CUBE] )
+    if( size>=0 && size<NUM_CUBES && num>=0 && num< numCategories[size] )
       {
-      Category c = mCategories[size-MIN_CUBE].elementAt(num);
+      Category c = mCategories[size].elementAt(num);
       return c!=null ? c.getName() : null;
       }
 
@@ -267,9 +282,9 @@ public class RubikPattern
 
   public String getPatternName(int size,int num)
     {
-    if( size>=MIN_CUBE && size<=MAX_CUBE && num>=0 && num< numCategories[size-MIN_CUBE] )
+    if( size>=0 && size<NUM_CUBES && num>=0 && num< numCategories[size] )
       {
-      Category c = mCategories[size-MIN_CUBE].elementAt(num);
+      Category c = mCategories[size].elementAt(num);
       return c!=null ? c.getPatternName() : null;
       }
 
@@ -280,9 +295,9 @@ public class RubikPattern
 
   public int getNumPatterns(int size, int num )
     {
-    if( size>=MIN_CUBE && size<=MAX_CUBE && num>=0 && num< numCategories[size-MIN_CUBE] )
+    if( size>=0 && size<NUM_CUBES && num>=0 && num< numCategories[size] )
       {
-      Category c = mCategories[size-MIN_CUBE].elementAt(num);
+      Category c = mCategories[size].elementAt(num);
       return c!=null ? c.getNumPatterns() : 0;
       }
 
@@ -293,9 +308,9 @@ public class RubikPattern
 
   public void nextPattern(int size, int num )
     {
-    if( size>=MIN_CUBE && size<=MAX_CUBE && num>=0 && num< numCategories[size-MIN_CUBE] )
+    if( size>=0 && size<NUM_CUBES && num>=0 && num< numCategories[size] )
       {
-      Category c = mCategories[size-MIN_CUBE].elementAt(num);
+      Category c = mCategories[size].elementAt(num);
 
       if( c!=null )
         {
@@ -311,9 +326,9 @@ public class RubikPattern
 
   public void prevPattern(int size, int num )
     {
-    if( size>=MIN_CUBE && size<=MAX_CUBE && num>=0 && num< numCategories[size-MIN_CUBE] )
+    if( size>=0 && size<NUM_CUBES && num>=0 && num< numCategories[size] )
       {
-      Category c = mCategories[size-MIN_CUBE].elementAt(num);
+      Category c = mCategories[size].elementAt(num);
 
       if( c!=null )
         {
@@ -329,9 +344,9 @@ public class RubikPattern
 
   public int getCurrPattern(int size, int num )
     {
-    if( size>=MIN_CUBE && size<=MAX_CUBE && num>=0 && num< numCategories[size-MIN_CUBE] )
+    if( size>=0 && size<NUM_CUBES && num>=0 && num< numCategories[size] )
       {
-      Category c = mCategories[size-MIN_CUBE].elementAt(num);
+      Category c = mCategories[size].elementAt(num);
       return c!=null ? c.curPattern:0;
       }
 
@@ -342,9 +357,9 @@ public class RubikPattern
 
   public int getCurMove(int size, int num )
     {
-    if( size>=MIN_CUBE && size<=MAX_CUBE && num>=0 && num< numCategories[size-MIN_CUBE] )
+    if( size>=0 && size<NUM_CUBES && num>=0 && num< numCategories[size] )
       {
-      Category c = mCategories[size-MIN_CUBE].elementAt(num);
+      Category c = mCategories[size].elementAt(num);
       return c!=null ? c.getPatternCurMove():0;
       }
 
@@ -355,9 +370,9 @@ public class RubikPattern
 
   public int getNumMove(int size, int num )
     {
-    if( size>=MIN_CUBE && size<=MAX_CUBE && num>=0 && num< numCategories[size-MIN_CUBE] )
+    if( size>=0 && size<NUM_CUBES && num>=0 && num< numCategories[size] )
       {
-      Category c = mCategories[size-MIN_CUBE].elementAt(num);
+      Category c = mCategories[size].elementAt(num);
       return c!=null ? c.getPatternNumMove():0;
       }
 
@@ -368,9 +383,9 @@ public class RubikPattern
 
   public void makeNextMove(int size, int num)
     {
-    if( size>=MIN_CUBE && size<=MAX_CUBE && num>=0 && num< numCategories[size-MIN_CUBE] )
+    if( size>=0 && size<NUM_CUBES && num>=0 && num< numCategories[size] )
       {
-      Category c = mCategories[size-MIN_CUBE].elementAt(num);
+      Category c = mCategories[size].elementAt(num);
       if( c!=null ) c.makeNextMove();
       }
     }
@@ -379,9 +394,9 @@ public class RubikPattern
 
   public void makePrevMove(int size, int num)
     {
-    if( size>=MIN_CUBE && size<=MAX_CUBE && num>=0 && num< numCategories[size-MIN_CUBE] )
+    if( size>=0 && size<NUM_CUBES && num>=0 && num< numCategories[size] )
       {
-      Category c = mCategories[size-MIN_CUBE].elementAt(num);
+      Category c = mCategories[size].elementAt(num);
       if( c!=null ) c.makePrevMove();
       }
     }
@@ -390,10 +405,17 @@ public class RubikPattern
 
   public void initializeCube(int size,int num)
     {
-    if( size>=MIN_CUBE && size<=MAX_CUBE && num>=0 && num< numCategories[size-MIN_CUBE] )
+    if( size>=0 && size<NUM_CUBES && num>=0 && num< numCategories[size] )
       {
-      Category c = mCategories[size-MIN_CUBE].elementAt(num);
+      Category c = mCategories[size].elementAt(num);
       if( c!=null ) c.initializeCube();
       }
     }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int getNumCategories(int size)
+    {
+    return size>=0 && size<NUM_CUBES ? numCategories[size] : 0;
+    }
 }
diff --git a/src/main/java/org/distorted/uistate/RubikState.java b/src/main/java/org/distorted/uistate/RubikState.java
index 9daf594e..610ea2f6 100644
--- a/src/main/java/org/distorted/uistate/RubikState.java
+++ b/src/main/java/org/distorted/uistate/RubikState.java
@@ -29,6 +29,7 @@ public enum RubikState
   MAIN ( null , new RubikStateMain()    ),
   PLAY ( MAIN , new RubikStatePlay()    ),
   SOLV ( PLAY , new RubikStateSolving() ),
+  PATT ( MAIN , new RubikStatePattern() ),
   ;
 
   public static final int LENGTH = values().length;
@@ -99,14 +100,14 @@ public enum RubikState
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  public static void switchState(RubikActivity act, RubikState state)
+  public static void switchState(RubikActivity act, RubikState next)
     {
-    if( state!=null )
+    if( next!=null )
       {
       if( mCurrState!=null ) mCurrState.leaveState(act);
-      state.enterState(act,mCurrState);
+      next.enterState(act,mCurrState);
       mPrevState = mCurrState;
-      mCurrState = state;
+      mCurrState = next;
       }
     else
       {
diff --git a/src/main/java/org/distorted/uistate/RubikStateMain.java b/src/main/java/org/distorted/uistate/RubikStateMain.java
index 7016f798..879797c9 100644
--- a/src/main/java/org/distorted/uistate/RubikStateMain.java
+++ b/src/main/java/org/distorted/uistate/RubikStateMain.java
@@ -28,6 +28,7 @@ import android.widget.LinearLayout;
 import android.widget.TextView;
 
 import org.distorted.dialog.RubikDialogMain;
+import org.distorted.dialog.RubikDialogPattern;
 import org.distorted.magic.R;
 import org.distorted.magic.RubikActivity;
 
@@ -63,6 +64,12 @@ public class RubikStateMain extends RubikStateAbstract
       diag2.show( mana, RubikDialogMain.getDialogTag() );
       }
 
+    if( prev==RubikState.PATT )
+      {
+      RubikDialogPattern diag2 = new RubikDialogPattern();
+      diag2.show( mana, RubikDialogPattern.getDialogTag() );
+      }
+
     LayoutInflater inflater = act.getLayoutInflater();
 
     // TOP ////////////////////////////
diff --git a/src/main/java/org/distorted/uistate/RubikStatePattern.java b/src/main/java/org/distorted/uistate/RubikStatePattern.java
new file mode 100644
index 00000000..9253a503
--- /dev/null
+++ b/src/main/java/org/distorted/uistate/RubikStatePattern.java
@@ -0,0 +1,98 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// 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.uistate;
+
+import android.content.SharedPreferences;
+import android.util.DisplayMetrics;
+import android.view.LayoutInflater;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import org.distorted.magic.R;
+import org.distorted.magic.RubikActivity;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+public class RubikStatePattern extends RubikStateAbstract
+  {
+  private TextView mText;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  RubikStatePattern()
+    {
+
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  void leaveState(RubikActivity act)
+    {
+
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  void enterState(RubikActivity act, RubikState prev)
+    {
+    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);
+
+    // BOT ////////////////////////////
+    LinearLayout layoutLeft = act.findViewById(R.id.mainBarLeft);
+    layoutLeft.removeAllViews();
+    LinearLayout layoutRight = act.findViewById(R.id.mainBarRight);
+    layoutRight.removeAllViews();
+
+    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);
+
+    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(act);
+    layoutRight.addView(button);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public void savePreferences(SharedPreferences.Editor editor)
+    {
+
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public void restorePreferences(SharedPreferences preferences)
+    {
+
+    }
+  }
