commit e108b57e08e0a58f00d0f82760798fdfadca35dc
Author: Leszek Koltunski <leszek@koltunski.pl>
Date:   Fri Mar 27 22:29:47 2020 +0000

    Re-add the Pattern dialog, but attach it to the Pattern uistate this time.
    The idea to do away with the dialog proves impossible - we'd have to resize the top bar, which causes very unpleasant flashes.

diff --git a/src/main/java/org/distorted/dialog/RubikDialogPattern.java b/src/main/java/org/distorted/dialog/RubikDialogPattern.java
new file mode 100644
index 00000000..712a57d1
--- /dev/null
+++ b/src/main/java/org/distorted/dialog/RubikDialogPattern.java
@@ -0,0 +1,139 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// 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.Context;
+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.util.DisplayMetrics;
+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);
+
+    Bundle args = getArguments();
+    int curTab;
+
+    try
+      {
+      curTab = args.getInt("tab");
+      }
+    catch(Exception e)
+      {
+      curTab = 0;
+      }
+
+    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);
+    viewPager.setCurrentItem(curTab);
+
+    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();
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  @Override
+  public void onResume()
+    {
+    super.onResume();
+
+    Window window = getDialog().getWindow();
+    Context context = getContext();
+
+    if( window!=null && context!=null )
+      {
+      DisplayMetrics metrics = context.getResources().getDisplayMetrics();
+      final float height= metrics.heightPixels;
+
+      WindowManager.LayoutParams params = window.getAttributes();
+      params.width = WindowManager.LayoutParams.WRAP_CONTENT;
+      params.height = (int)(0.75f*height);
+      window.setAttributes(params);
+      }
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  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
new file mode 100644
index 00000000..91f44ab1
--- /dev/null
+++ b/src/main/java/org/distorted/dialog/RubikDialogPatternPagerAdapter.java
@@ -0,0 +1,106 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// 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
new file mode 100644
index 00000000..31914c91
--- /dev/null
+++ b/src/main/java/org/distorted/dialog/RubikDialogPatternView.java
@@ -0,0 +1,101 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// 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_pattern_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/RubikDialogScoresView.java b/src/main/java/org/distorted/dialog/RubikDialogScoresView.java
index 506a1f6c..22cf5169 100644
--- a/src/main/java/org/distorted/dialog/RubikDialogScoresView.java
+++ b/src/main/java/org/distorted/dialog/RubikDialogScoresView.java
@@ -157,7 +157,7 @@ public class RubikDialogScoresView extends FrameLayout
     {
     removeAllViews();
 
-    View tab = inflate(act, R.layout.dialog_tab, null);
+    View tab = inflate(act, R.layout.dialog_scores_tab, null);
     mLayout = tab.findViewById(R.id.tabLayout);
     addView(tab);
     }
diff --git a/src/main/java/org/distorted/uistate/RubikStatePattern.java b/src/main/java/org/distorted/uistate/RubikStatePattern.java
index ee0564f0..545763ac 100644
--- a/src/main/java/org/distorted/uistate/RubikStatePattern.java
+++ b/src/main/java/org/distorted/uistate/RubikStatePattern.java
@@ -19,19 +19,17 @@
 
 package org.distorted.uistate;
 
-import android.content.Context;
 import android.content.SharedPreferences;
-import android.graphics.drawable.BitmapDrawable;
+import android.os.Bundle;
+import android.support.v4.app.FragmentManager;
 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;
@@ -41,11 +39,7 @@ import org.distorted.patterns.RubikPattern;
 
 public class RubikStatePattern extends RubikStateAbstract
   {
-  private ImageButton mObjButton;
   private Button mBackButton;
-  private PopupWindow mPopup;
-  private int mLayoutWidth, mLayoutHeight;
-  private LinearLayout mLayout;
   private int mSize;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -88,6 +82,11 @@ public class RubikStatePattern extends RubikStateAbstract
       act.changeObject(RubikObjectList.CUBE,mSize);
       }
 
+    FragmentManager mana = act.getSupportFragmentManager();
+    RubikDialogPattern diag = (RubikDialogPattern) mana.findFragmentByTag(RubikDialogPattern.getDialogTag());
+
+    if( diag==null ) showDialog(mana);
+
     LayoutInflater inflater = act.getLayoutInflater();
 
     // TOP ////////////////////////////
@@ -101,49 +100,25 @@ public class RubikStatePattern extends RubikStateAbstract
     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);
-
-    if( mPopup==null ) setupPopupWindow(act, scale);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  private void setupObjectButton(final RubikActivity act, final float scale)
+  private void showDialog(FragmentManager manager)
     {
-    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);
-        }
-      });
+    Bundle bundle = new Bundle();
+    int object = RubikObjectList.CUBE.ordinal();
+    int sizeIndex = RubikObjectList.getSizeIndex(object,mSize);
+    bundle.putInt("tab", RubikObjectList.pack(object,sizeIndex) );
+
+    RubikDialogPattern diag = new RubikDialogPattern();
+    diag.setArguments(bundle);
+    diag.show( manager, RubikDialogPattern.getDialogTag() );
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -163,73 +138,27 @@ public class RubikStatePattern extends RubikStateAbstract
       @Override
       public void onClick(View v)
         {
-        RubikState.goBack(act);
-        }
-      });
-    }
+        FragmentManager mana = act.getSupportFragmentManager();
+        RubikDialogPattern diag = (RubikDialogPattern) mana.findFragmentByTag(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);
-
-    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)
+        if( diag==null )
           {
-          mSize = sizes[size];
-          act.changeObject(RubikObjectList.CUBE,sizes[size]);
-          mPopup.dismiss();
+          showDialog(mana);
           }
-        });
-
-      mLayout.addView(button);
-      }
+        else
+          {
+          diag.dismiss();
+          RubikState.goBack(act);
+          }
+        }
+      });
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   public void savePreferences(SharedPreferences.Editor editor)
     {
-    mObjButton = null;
     mBackButton= null;
-
-    if( mPopup!=null )
-      {
-      mPopup.dismiss();
-      mPopup = null;
-      }
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/main/res/layout/dialog_pattern_tab.xml b/src/main/res/layout/dialog_pattern_tab.xml
new file mode 100644
index 00000000..1c67f764
--- /dev/null
+++ b/src/main/res/layout/dialog_pattern_tab.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/tabScrollView"
+    android:background="@color/grey"
+    android:paddingBottom="10dp"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <LinearLayout
+        android:id="@+id/tabLayout"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical" >
+    </LinearLayout>
+
+</ScrollView>
+
diff --git a/src/main/res/layout/dialog_scores_tab.xml b/src/main/res/layout/dialog_scores_tab.xml
new file mode 100644
index 00000000..74f63cd8
--- /dev/null
+++ b/src/main/res/layout/dialog_scores_tab.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/tabScrollView"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <LinearLayout
+        android:id="@+id/tabLayout"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical" >
+    </LinearLayout>
+
+</ScrollView>
+
diff --git a/src/main/res/layout/dialog_tab.xml b/src/main/res/layout/dialog_tab.xml
deleted file mode 100644
index 74f63cd8..00000000
--- a/src/main/res/layout/dialog_tab.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/tabScrollView"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent">
-
-    <LinearLayout
-        android:id="@+id/tabLayout"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:orientation="vertical" >
-    </LinearLayout>
-
-</ScrollView>
-
