Revision a742d66b
Added by Leszek Koltunski 10 months ago
| src/main/java/org/distorted/dialogs/RubikDialogSolverView.java | ||
|---|---|---|
| 21 | 21 | 
    import org.distorted.objectlib.solvers.verifiers.SolverAbstract;  | 
| 22 | 22 | 
    import org.distorted.objectlib.solvers.verifiers.SolvingList;  | 
| 23 | 23 | 
    import org.distorted.solverui.ScreenList;  | 
| 24 | 
    import org.distorted.solverui.ScreenSolver;
   | 
|
| 24 | 
    import org.distorted.solverui.ScreenSetupPosition;
   | 
|
| 25 | 25 | 
    import org.distorted.solverui.SolverActivity;  | 
| 26 | 26 | 
     | 
| 27 | 27 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
| ... | ... | |
| 59 | 59 | 
    OperatingSystemInterface os = act.getInterface();  | 
| 60 | 60 | 
    TwistyObject object = act.getObject();  | 
| 61 | 61 | 
    SolverAbstract solver = list.create(os,object);  | 
| 62 | 
            ScreenSolver screen = (ScreenSolver)ScreenList.SVER.getScreenClass();
   | 
|
| 62 | 
            ScreenSetupPosition screen = (ScreenSetupPosition)ScreenList.SVER.getScreenClass();
   | 
|
| 63 | 63 | 
     | 
| 64 | 64 | 
    if( solver!=null )  | 
| 65 | 65 | 
              {
   | 
| src/main/java/org/distorted/solverui/ScreenList.java | ||
|---|---|---|
| 18 | 18 | 
     | 
| 19 | 19 | 
    public enum ScreenList  | 
| 20 | 20 | 
      {
   | 
| 21 | 
      SVER ( null , MODE_REPLACE, new ScreenSolver()         ),
   | 
|
| 22 | 
      SOLU ( SVER , MODE_DRAG   , new ScreenSolution()       ),
   | 
|
| 23 | 
      PHAS ( SVER , MODE_DRAG   , new ScreenPhasedSolution() ),
   | 
|
| 21 | 
      SVER ( null , MODE_REPLACE, new ScreenSetupPosition()        ),
   | 
|
| 22 | 
      SOLU ( SVER , MODE_DRAG   , new ScreenSolutionSinglephased() ),
   | 
|
| 23 | 
      PHAS ( SVER , MODE_DRAG   , new ScreenSolutionMultiphased()  ),
   | 
|
| 24 | 24 | 
    ;  | 
| 25 | 25 | 
     | 
| 26 | 26 | 
    public static final int LENGTH = values().length;  | 
| src/main/java/org/distorted/solverui/ScreenPhasedSolution.java | ||
|---|---|---|
| 1 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 2 | 
    // Copyright 2024 Leszek Koltunski //  | 
|
| 3 | 
    // //  | 
|
| 4 | 
    // This file is part of Magic Cube. //  | 
|
| 5 | 
    // //  | 
|
| 6 | 
    // Magic Cube is proprietary software licensed under an EULA which you should have received //  | 
|
| 7 | 
    // along with the code. If not, check https://distorted.org/magic/License-Magic-Cube.html //  | 
|
| 8 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 9 | 
     | 
|
| 10 | 
    package org.distorted.solverui;  | 
|
| 11 | 
     | 
|
| 12 | 
    import android.content.SharedPreferences;  | 
|
| 13 | 
    import android.util.TypedValue;  | 
|
| 14 | 
    import android.view.Gravity;  | 
|
| 15 | 
    import android.view.View;  | 
|
| 16 | 
    import android.widget.LinearLayout;  | 
|
| 17 | 
    import android.widget.TextView;  | 
|
| 18 | 
     | 
|
| 19 | 
    import org.distorted.helpers.TransparentImageButton;  | 
|
| 20 | 
    import org.distorted.library.effect.PostprocessEffectGlow;  | 
|
| 21 | 
    import org.distorted.library.main.DistortedEffects;  | 
|
| 22 | 
    import org.distorted.library.mesh.MeshBase;  | 
|
| 23 | 
    import org.distorted.library.message.EffectListener;  | 
|
| 24 | 
    import org.distorted.library.type.Dynamic2D;  | 
|
| 25 | 
    import org.distorted.library.type.Dynamic4D;  | 
|
| 26 | 
    import org.distorted.library.type.Static2D;  | 
|
| 27 | 
    import org.distorted.library.type.Static4D;  | 
|
| 28 | 
    import org.distorted.main.R;  | 
|
| 29 | 
    import org.distorted.objectlib.helpers.MovesFinished;  | 
|
| 30 | 
    import org.distorted.objectlib.main.ObjectControl;  | 
|
| 31 | 
    import org.distorted.objectlib.main.TwistyObject;  | 
|
| 32 | 
     | 
|
| 33 | 
    import java.lang.ref.WeakReference;  | 
|
| 34 | 
     | 
|
| 35 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 36 | 
     | 
|
| 37 | 
    public class ScreenPhasedSolution extends ScreenAbstract implements MovesFinished, EffectListener  | 
|
| 38 | 
      {
   | 
|
| 39 | 
    private static final int MOVES_PLACE_0 = 100;  | 
|
| 40 | 
    private static final int MOVES_PLACE_1 = 101;  | 
|
| 41 | 
    private static final int FLASH_TIME = 1200;  | 
|
| 42 | 
    private static final int MILLIS_PER_DEGREE = 6;  | 
|
| 43 | 
     | 
|
| 44 | 
    private WeakReference<SolverActivity> mAct;  | 
|
| 45 | 
    private TransparentImageButton mPrevButton, mNextButton, mBackButton, mPrevPhase, mNextPhase;  | 
|
| 46 | 
    private float mButtonSize;  | 
|
| 47 | 
     | 
|
| 48 | 
    private TextView mMovesText, mMovesPhase;  | 
|
| 49 | 
    private String[] mPhaseNames;  | 
|
| 50 | 
    private int mNumPhases;  | 
|
| 51 | 
    private int[][][] mMoves;  | 
|
| 52 | 
    private int[][] mCubitsNotInvolved;  | 
|
| 53 | 
    private int mNumMoves,mCurrMove,mCurrPhase;  | 
|
| 54 | 
    private boolean mCanMove;  | 
|
| 55 | 
     | 
|
| 56 | 
    private Dynamic2D mHaloAndRadiusDyn;  | 
|
| 57 | 
    private Dynamic4D mColorDyn;  | 
|
| 58 | 
    private PostprocessEffectGlow mGlow;  | 
|
| 59 | 
    private boolean mEffectWorking;  | 
|
| 60 | 
     | 
|
| 61 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 62 | 
     | 
|
| 63 | 
    void leaveScreen(SolverActivity act)  | 
|
| 64 | 
        {
   | 
|
| 65 | 
    ObjectControl control = act.getControl();  | 
|
| 66 | 
    control.solveOnly();  | 
|
| 67 | 
    }  | 
|
| 68 | 
     | 
|
| 69 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 70 | 
     | 
|
| 71 | 
    void enterScreen(final SolverActivity act)  | 
|
| 72 | 
        {
   | 
|
| 73 | 
    mAct = new WeakReference<>(act);  | 
|
| 74 | 
     | 
|
| 75 | 
    mHaloAndRadiusDyn = new Dynamic2D(FLASH_TIME,1.0f);  | 
|
| 76 | 
    mHaloAndRadiusDyn.add(new Static2D( 0,0));  | 
|
| 77 | 
    mHaloAndRadiusDyn.add(new Static2D(10,5));  | 
|
| 78 | 
     | 
|
| 79 | 
    mColorDyn = new Dynamic4D(FLASH_TIME,1.0f);  | 
|
| 80 | 
     | 
|
| 81 | 
        final int[] colors  = new int[] {1,1,1}; // white
   | 
|
| 82 | 
     | 
|
| 83 | 
    Static4D P1 = new Static4D(colors[0],colors[1],colors[2], 0.0f);  | 
|
| 84 | 
    Static4D P2 = new Static4D(colors[0],colors[1],colors[2], 1.0f);  | 
|
| 85 | 
    mColorDyn.add(P1);  | 
|
| 86 | 
    mColorDyn.add(P2);  | 
|
| 87 | 
     | 
|
| 88 | 
    mGlow = new PostprocessEffectGlow(mHaloAndRadiusDyn,mColorDyn);  | 
|
| 89 | 
     | 
|
| 90 | 
    float width = act.getScreenWidthInPixels();  | 
|
| 91 | 
    mButtonSize = width*SolverActivity.BUTTON_TEXT_SIZE;  | 
|
| 92 | 
     | 
|
| 93 | 
    // TOP ////////////////////////////  | 
|
| 94 | 
    LinearLayout layoutTop = act.findViewById(R.id.upperBar);  | 
|
| 95 | 
    layoutTop.removeAllViews();  | 
|
| 96 | 
     | 
|
| 97 | 
    setupPrevPhase(act);  | 
|
| 98 | 
    setupNextPhase(act);  | 
|
| 99 | 
    setupTextPhase(act,width);  | 
|
| 100 | 
     | 
|
| 101 | 
    layoutTop.addView(mPrevPhase);  | 
|
| 102 | 
    layoutTop.addView(mMovesPhase);  | 
|
| 103 | 
    layoutTop.addView(mNextPhase);  | 
|
| 104 | 
     | 
|
| 105 | 
    // BOT ////////////////////////////  | 
|
| 106 | 
    LinearLayout layoutBot = act.findViewById(R.id.lowerBar);  | 
|
| 107 | 
    layoutBot.removeAllViews();  | 
|
| 108 | 
     | 
|
| 109 | 
    LinearLayout.LayoutParams paramsL = new LinearLayout.LayoutParams((int)(width/2),LinearLayout.LayoutParams.MATCH_PARENT);  | 
|
| 110 | 
    LinearLayout.LayoutParams paramsM = new LinearLayout.LayoutParams((int)(width/6),LinearLayout.LayoutParams.MATCH_PARENT);  | 
|
| 111 | 
    LinearLayout.LayoutParams paramsR = new LinearLayout.LayoutParams((int)(width/3),LinearLayout.LayoutParams.MATCH_PARENT);  | 
|
| 112 | 
     | 
|
| 113 | 
    LinearLayout layoutLeft = new LinearLayout(act);  | 
|
| 114 | 
    layoutLeft.setLayoutParams(paramsL);  | 
|
| 115 | 
    LinearLayout layoutMid = new LinearLayout(act);  | 
|
| 116 | 
    layoutMid.setLayoutParams(paramsM);  | 
|
| 117 | 
    LinearLayout layoutRight = new LinearLayout(act);  | 
|
| 118 | 
    layoutRight.setLayoutParams(paramsR);  | 
|
| 119 | 
     | 
|
| 120 | 
    setupPrevButton(act);  | 
|
| 121 | 
    setupNextButton(act);  | 
|
| 122 | 
    setupTextView(act,width);  | 
|
| 123 | 
     | 
|
| 124 | 
    layoutLeft.addView(mPrevButton);  | 
|
| 125 | 
    layoutLeft.addView(mMovesText);  | 
|
| 126 | 
    layoutLeft.addView(mNextButton);  | 
|
| 127 | 
     | 
|
| 128 | 
    setupBackButton(act);  | 
|
| 129 | 
     | 
|
| 130 | 
    layoutRight.addView(mBackButton);  | 
|
| 131 | 
     | 
|
| 132 | 
    layoutBot.addView(layoutLeft);  | 
|
| 133 | 
    layoutBot.addView(layoutMid);  | 
|
| 134 | 
    layoutBot.addView(layoutRight);  | 
|
| 135 | 
    }  | 
|
| 136 | 
     | 
|
| 137 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 138 | 
     | 
|
| 139 | 
    private void setupPrevButton(final SolverActivity act)  | 
|
| 140 | 
        {
   | 
|
| 141 | 
    LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(0,LinearLayout.LayoutParams.MATCH_PARENT,1.0f);  | 
|
| 142 | 
    mPrevButton = new TransparentImageButton(act,R.drawable.ui_left,params);  | 
|
| 143 | 
     | 
|
| 144 | 
    mPrevButton.setOnClickListener( new View.OnClickListener()  | 
|
| 145 | 
          {
   | 
|
| 146 | 
          @Override public void onClick(View v) { backMove(); }
   | 
|
| 147 | 
    });  | 
|
| 148 | 
    }  | 
|
| 149 | 
     | 
|
| 150 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 151 | 
     | 
|
| 152 | 
    private void setupNextButton(final SolverActivity act)  | 
|
| 153 | 
        {
   | 
|
| 154 | 
    LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(0,LinearLayout.LayoutParams.MATCH_PARENT,1.0f);  | 
|
| 155 | 
    mNextButton = new TransparentImageButton(act,R.drawable.ui_right,params);  | 
|
| 156 | 
     | 
|
| 157 | 
    mNextButton.setOnClickListener( new View.OnClickListener()  | 
|
| 158 | 
          {
   | 
|
| 159 | 
          @Override public void onClick(View v) { nextMove(); }
   | 
|
| 160 | 
    });  | 
|
| 161 | 
    }  | 
|
| 162 | 
     | 
|
| 163 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 164 | 
     | 
|
| 165 | 
    private void setupTextView(final SolverActivity act, final float width)  | 
|
| 166 | 
        {
   | 
|
| 167 | 
    int padding = (int)(width*SolverActivity.PADDING);  | 
|
| 168 | 
    int margin = (int)(width*SolverActivity.SMALL_MARGIN);  | 
|
| 169 | 
    LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(0,LinearLayout.LayoutParams.MATCH_PARENT,2.0f);  | 
|
| 170 | 
    params.topMargin = margin;  | 
|
| 171 | 
    params.bottomMargin = margin;  | 
|
| 172 | 
    params.leftMargin = margin;  | 
|
| 173 | 
    params.rightMargin = margin;  | 
|
| 174 | 
     | 
|
| 175 | 
    mMovesText = new TextView(act);  | 
|
| 176 | 
    mMovesText.setTextSize(20);  | 
|
| 177 | 
    mMovesText.setLayoutParams(params);  | 
|
| 178 | 
    mMovesText.setPadding(padding,0,padding,0);  | 
|
| 179 | 
    mMovesText.setGravity(Gravity.CENTER);  | 
|
| 180 | 
    mMovesText.setTextSize(TypedValue.COMPLEX_UNIT_PX, mButtonSize);  | 
|
| 181 | 
    mMovesText.setText(act.getString(R.string.mo_placeholder,mCurrMove,mNumMoves));  | 
|
| 182 | 
    }  | 
|
| 183 | 
     | 
|
| 184 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 185 | 
     | 
|
| 186 | 
    private void setupPrevPhase(final SolverActivity act)  | 
|
| 187 | 
        {
   | 
|
| 188 | 
    LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(0,LinearLayout.LayoutParams.MATCH_PARENT,1.0f);  | 
|
| 189 | 
    mPrevPhase = new TransparentImageButton(act,R.drawable.ui_left,params);  | 
|
| 190 | 
     | 
|
| 191 | 
    mPrevPhase.setOnClickListener( new View.OnClickListener()  | 
|
| 192 | 
          {
   | 
|
| 193 | 
          @Override public void onClick(View v) { backPhase(); }
   | 
|
| 194 | 
    });  | 
|
| 195 | 
    }  | 
|
| 196 | 
     | 
|
| 197 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 198 | 
     | 
|
| 199 | 
    private void setupNextPhase(final SolverActivity act)  | 
|
| 200 | 
        {
   | 
|
| 201 | 
    LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(0,LinearLayout.LayoutParams.MATCH_PARENT,1.0f);  | 
|
| 202 | 
    mNextPhase = new TransparentImageButton(act,R.drawable.ui_right,params);  | 
|
| 203 | 
     | 
|
| 204 | 
    mNextPhase.setOnClickListener( new View.OnClickListener()  | 
|
| 205 | 
          {
   | 
|
| 206 | 
          @Override public void onClick(View v) { nextPhase(); }
   | 
|
| 207 | 
    });  | 
|
| 208 | 
    }  | 
|
| 209 | 
     | 
|
| 210 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 211 | 
     | 
|
| 212 | 
    private void setupTextPhase(final SolverActivity act, final float width)  | 
|
| 213 | 
        {
   | 
|
| 214 | 
    int padding = (int)(width*SolverActivity.PADDING);  | 
|
| 215 | 
    int margin = (int)(width*SolverActivity.SMALL_MARGIN);  | 
|
| 216 | 
    LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(0,LinearLayout.LayoutParams.MATCH_PARENT,2.0f);  | 
|
| 217 | 
    params.topMargin = margin;  | 
|
| 218 | 
    params.bottomMargin = margin;  | 
|
| 219 | 
    params.leftMargin = margin;  | 
|
| 220 | 
    params.rightMargin = margin;  | 
|
| 221 | 
     | 
|
| 222 | 
    mMovesPhase = new TextView(act);  | 
|
| 223 | 
    mMovesPhase.setTextSize(20);  | 
|
| 224 | 
    mMovesPhase.setLayoutParams(params);  | 
|
| 225 | 
    mMovesPhase.setPadding(padding,0,padding,0);  | 
|
| 226 | 
    mMovesPhase.setGravity(Gravity.CENTER);  | 
|
| 227 | 
    mMovesPhase.setTextSize(TypedValue.COMPLEX_UNIT_PX, mButtonSize);  | 
|
| 228 | 
    mMovesPhase.setText(act.getString(R.string.mo_placeholder,mCurrMove,mNumMoves));  | 
|
| 229 | 
    }  | 
|
| 230 | 
     | 
|
| 231 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 232 | 
     | 
|
| 233 | 
    private void setupBackButton(final SolverActivity act)  | 
|
| 234 | 
        {
   | 
|
| 235 | 
    LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.MATCH_PARENT,1.0f);  | 
|
| 236 | 
    mBackButton = new TransparentImageButton(act,R.drawable.ui_back,params);  | 
|
| 237 | 
     | 
|
| 238 | 
    mBackButton.setOnClickListener( new View.OnClickListener()  | 
|
| 239 | 
          {
   | 
|
| 240 | 
    @Override  | 
|
| 241 | 
    public void onClick(View v)  | 
|
| 242 | 
            {
   | 
|
| 243 | 
    ScreenList.goBack(act);  | 
|
| 244 | 
    }  | 
|
| 245 | 
    });  | 
|
| 246 | 
    }  | 
|
| 247 | 
     | 
|
| 248 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 249 | 
     | 
|
| 250 | 
      public void savePreferences(SharedPreferences.Editor editor) { }
   | 
|
| 251 | 
      public void restorePreferences(SharedPreferences preferences) { }
   | 
|
| 252 | 
     | 
|
| 253 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 254 | 
     | 
|
| 255 | 
    void backPhase()  | 
|
| 256 | 
        {
   | 
|
| 257 | 
    SolverActivity act = mAct.get();  | 
|
| 258 | 
    ObjectControl control = act.getControl();  | 
|
| 259 | 
     | 
|
| 260 | 
    if( mCurrMove>0 )  | 
|
| 261 | 
          {
   | 
|
| 262 | 
    int[][] moves = transformMoves(mMoves[mCurrPhase],0,mCurrMove, false);  | 
|
| 263 | 
    control.applyScrambles(moves);  | 
|
| 264 | 
    mCurrMove = 0;  | 
|
| 265 | 
    }  | 
|
| 266 | 
    else if( mCurrPhase>0 )  | 
|
| 267 | 
          {
   | 
|
| 268 | 
    mCurrPhase--;  | 
|
| 269 | 
    mNumMoves = mMoves[mCurrPhase]==null ? 0 : mMoves[mCurrPhase].length;  | 
|
| 270 | 
    mCurrMove = 0;  | 
|
| 271 | 
    int[][] moves = transformMoves(mMoves[mCurrPhase],0,mNumMoves, false);  | 
|
| 272 | 
    control.applyScrambles(moves);  | 
|
| 273 | 
    }  | 
|
| 274 | 
    else  | 
|
| 275 | 
          {
   | 
|
| 276 | 
    mCurrPhase = mNumPhases-1;  | 
|
| 277 | 
    mNumMoves = mMoves[mCurrPhase]==null ? 0 : mMoves[mCurrPhase].length;  | 
|
| 278 | 
    mCurrMove = mNumMoves;  | 
|
| 279 | 
    int[][] moves = transformMoves(mMoves, true);  | 
|
| 280 | 
    control.applyScrambles(moves);  | 
|
| 281 | 
    }  | 
|
| 282 | 
     | 
|
| 283 | 
    setText(act);  | 
|
| 284 | 
    }  | 
|
| 285 | 
     | 
|
| 286 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 287 | 
     | 
|
| 288 | 
    void nextPhase()  | 
|
| 289 | 
        {
   | 
|
| 290 | 
    SolverActivity act = mAct.get();  | 
|
| 291 | 
    ObjectControl control = act.getControl();  | 
|
| 292 | 
     | 
|
| 293 | 
    if( mCurrPhase<mNumPhases-1 )  | 
|
| 294 | 
          {
   | 
|
| 295 | 
    glowCubits(mCubitsNotInvolved[mCurrPhase]);  | 
|
| 296 | 
    int[][] moves = transformMoves(mMoves[mCurrPhase],mCurrMove,mNumMoves, true);  | 
|
| 297 | 
    control.applyScrambles(moves);  | 
|
| 298 | 
    mCurrPhase++;  | 
|
| 299 | 
    mNumMoves = mMoves[mCurrPhase]==null ? 0 : mMoves[mCurrPhase].length;  | 
|
| 300 | 
    mCurrMove = 0;  | 
|
| 301 | 
    }  | 
|
| 302 | 
    else if( mCurrMove<mNumMoves )  | 
|
| 303 | 
          {
   | 
|
| 304 | 
    glowCubits(mCubitsNotInvolved[mCurrPhase]);  | 
|
| 305 | 
    int[][] moves = transformMoves(mMoves[mCurrPhase],mCurrMove,mNumMoves, true);  | 
|
| 306 | 
    control.applyScrambles(moves);  | 
|
| 307 | 
    mCurrMove = mNumMoves;  | 
|
| 308 | 
    }  | 
|
| 309 | 
    else  | 
|
| 310 | 
          {
   | 
|
| 311 | 
    mCurrPhase = 0;  | 
|
| 312 | 
    mNumMoves = mMoves[mCurrPhase]==null ? 0 : mMoves[mCurrPhase].length;  | 
|
| 313 | 
    mCurrMove = 0;  | 
|
| 314 | 
    int[][] moves = transformMoves(mMoves, false);  | 
|
| 315 | 
    control.applyScrambles(moves);  | 
|
| 316 | 
    }  | 
|
| 317 | 
     | 
|
| 318 | 
    setText(act);  | 
|
| 319 | 
    }  | 
|
| 320 | 
     | 
|
| 321 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 322 | 
     | 
|
| 323 | 
    private void setText(SolverActivity act)  | 
|
| 324 | 
        {
   | 
|
| 325 | 
    int currMove = 0;  | 
|
| 326 | 
    int totalMove = 0;  | 
|
| 327 | 
     | 
|
| 328 | 
    if( mMoves!=null )  | 
|
| 329 | 
          {
   | 
|
| 330 | 
    currMove = mCurrMove;  | 
|
| 331 | 
    for(int p=0; p<mCurrPhase; p++) currMove += (mMoves[p]==null ? 0: mMoves[p].length);  | 
|
| 332 | 
    for(int p=0; p<mNumPhases; p++) totalMove += (mMoves[p]==null ? 0: mMoves[p].length);  | 
|
| 333 | 
    }  | 
|
| 334 | 
     | 
|
| 335 | 
    final int cMove = currMove;  | 
|
| 336 | 
    final int tMove = totalMove;  | 
|
| 337 | 
     | 
|
| 338 | 
    act.runOnUiThread(new Runnable()  | 
|
| 339 | 
          {
   | 
|
| 340 | 
    @Override  | 
|
| 341 | 
    public void run()  | 
|
| 342 | 
            {
   | 
|
| 343 | 
    mMovesPhase.setText(mPhaseNames[mCurrPhase]+" "+mCurrMove+"/"+mNumMoves);  | 
|
| 344 | 
    mMovesText.setText(cMove+"/"+tMove);  | 
|
| 345 | 
    }  | 
|
| 346 | 
    });  | 
|
| 347 | 
    }  | 
|
| 348 | 
     | 
|
| 349 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 350 | 
     | 
|
| 351 | 
    private int[][] transformMoves(int[][] moves, int start, int end, boolean front)  | 
|
| 352 | 
        {
   | 
|
| 353 | 
    int mult = front ? 1:-1;  | 
|
| 354 | 
    int len = end-start;  | 
|
| 355 | 
    int[][] ret = new int[len][];  | 
|
| 356 | 
     | 
|
| 357 | 
    for(int m=0; m<len; m++)  | 
|
| 358 | 
          {
   | 
|
| 359 | 
    int[] mv = moves[front ? start+m : end-1-m];  | 
|
| 360 | 
    int[] rt = new int[3];  | 
|
| 361 | 
    rt[0] = mv[0];  | 
|
| 362 | 
    rt[1] = (1<<mv[1]);  | 
|
| 363 | 
    rt[2] = mult*mv[2];  | 
|
| 364 | 
    ret[m] = rt;  | 
|
| 365 | 
    }  | 
|
| 366 | 
     | 
|
| 367 | 
    return ret;  | 
|
| 368 | 
    }  | 
|
| 369 | 
     | 
|
| 370 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 371 | 
     | 
|
| 372 | 
    private int[][] transformMoves(int[][][] moves, boolean front)  | 
|
| 373 | 
        {
   | 
|
| 374 | 
    int len = moves.length;  | 
|
| 375 | 
    int totalLen = 0;  | 
|
| 376 | 
    for (int[][] move : moves) totalLen += (move==null ? 0 : move.length);  | 
|
| 377 | 
     | 
|
| 378 | 
    int[][] ret = new int[totalLen][];  | 
|
| 379 | 
    int mult = front ? 1:-1;  | 
|
| 380 | 
    int index = 0;  | 
|
| 381 | 
     | 
|
| 382 | 
    for(int m=0; m<len; m++)  | 
|
| 383 | 
          {
   | 
|
| 384 | 
    int[][] mv = moves[front ? m : len-1-m];  | 
|
| 385 | 
    int l = (mv==null ? 0 : mv.length);  | 
|
| 386 | 
     | 
|
| 387 | 
    for(int p=0; p<l; p++)  | 
|
| 388 | 
            {
   | 
|
| 389 | 
    int[] mve = mv[front ? p : l-1-p];  | 
|
| 390 | 
    int[] rt = new int[3];  | 
|
| 391 | 
    rt[0] = mve[0];  | 
|
| 392 | 
    rt[1] = (1<<mve[1]);  | 
|
| 393 | 
    rt[2] = mult*mve[2];  | 
|
| 394 | 
    ret[index++] = rt;  | 
|
| 395 | 
    }  | 
|
| 396 | 
    }  | 
|
| 397 | 
     | 
|
| 398 | 
    return ret;  | 
|
| 399 | 
    }  | 
|
| 400 | 
     | 
|
| 401 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 402 | 
     | 
|
| 403 | 
    private void glowCubits(int[] cubits)  | 
|
| 404 | 
        {
   | 
|
| 405 | 
    if( !mEffectWorking )  | 
|
| 406 | 
          {
   | 
|
| 407 | 
    mEffectWorking = true;  | 
|
| 408 | 
    SolverActivity act=mAct.get();  | 
|
| 409 | 
    ObjectControl control = act.getControl();  | 
|
| 410 | 
    TwistyObject object=control.getObject();  | 
|
| 411 | 
    DistortedEffects effects=object.getObjectEffects();  | 
|
| 412 | 
    effects.apply(mGlow);  | 
|
| 413 | 
     | 
|
| 414 | 
    MeshBase mesh=object.getObjectMesh();  | 
|
| 415 | 
    mesh.setComponentsNotAffectedByPostprocessing(cubits);  | 
|
| 416 | 
     | 
|
| 417 | 
    mHaloAndRadiusDyn.resetToBeginning();  | 
|
| 418 | 
    mColorDyn.resetToBeginning();  | 
|
| 419 | 
    mGlow.notifyWhenFinished(this);  | 
|
| 420 | 
    }  | 
|
| 421 | 
    }  | 
|
| 422 | 
     | 
|
| 423 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 424 | 
     | 
|
| 425 | 
    private int[] computeCubitsNotInvolved(int[][] subphases, int numCubits)  | 
|
| 426 | 
        {
   | 
|
| 427 | 
    int numCubitsInvolved = 0;  | 
|
| 428 | 
    boolean[] involved = new boolean[numCubits];  | 
|
| 429 | 
     | 
|
| 430 | 
    for(int[] sub : subphases)  | 
|
| 431 | 
    if( sub!=null )  | 
|
| 432 | 
    for(int s : sub)  | 
|
| 433 | 
              {
   | 
|
| 434 | 
    numCubitsInvolved++;  | 
|
| 435 | 
    involved[s] = true;  | 
|
| 436 | 
    }  | 
|
| 437 | 
     | 
|
| 438 | 
    int[] ret = new int[numCubits-numCubitsInvolved];  | 
|
| 439 | 
    int index = 0;  | 
|
| 440 | 
     | 
|
| 441 | 
    for(int c=0; c<numCubits; c++)  | 
|
| 442 | 
    if( !involved[c] ) ret[index++] = c;  | 
|
| 443 | 
     | 
|
| 444 | 
    return ret;  | 
|
| 445 | 
    }  | 
|
| 446 | 
     | 
|
| 447 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 448 | 
     | 
|
| 449 | 
    void backMove()  | 
|
| 450 | 
        {
   | 
|
| 451 | 
    if( mMoves!=null && mCanMove )  | 
|
| 452 | 
          {
   | 
|
| 453 | 
    SolverActivity act=mAct.get();  | 
|
| 454 | 
     | 
|
| 455 | 
    if( mCurrMove>0 )  | 
|
| 456 | 
            {
   | 
|
| 457 | 
    mCanMove = false;  | 
|
| 458 | 
    int[] move = mMoves[mCurrPhase][--mCurrMove];  | 
|
| 459 | 
    ObjectControl control = act.getControl();  | 
|
| 460 | 
    control.blockTouch(MOVES_PLACE_0);  | 
|
| 461 | 
    control.addRotation(this, move[0], (1<<move[1]), -move[2], MILLIS_PER_DEGREE);  | 
|
| 462 | 
    }  | 
|
| 463 | 
    else if( mCurrPhase>0 )  | 
|
| 464 | 
            {
   | 
|
| 465 | 
    mCurrPhase--;  | 
|
| 466 | 
    mNumMoves = mMoves[mCurrPhase]==null ? 0 : mMoves[mCurrPhase].length;  | 
|
| 467 | 
    mCurrMove = mNumMoves;  | 
|
| 468 | 
    glowCubits(mCubitsNotInvolved[mCurrPhase]);  | 
|
| 469 | 
    }  | 
|
| 470 | 
    else  | 
|
| 471 | 
            {
   | 
|
| 472 | 
    mCurrPhase = mNumPhases-1;  | 
|
| 473 | 
    mNumMoves = mMoves[mCurrPhase]==null ? 0 : mMoves[mCurrPhase].length;  | 
|
| 474 | 
    mCurrMove = mNumMoves;  | 
|
| 475 | 
    int[][] moves = transformMoves(mMoves, true);  | 
|
| 476 | 
    ObjectControl control = act.getControl();  | 
|
| 477 | 
    control.applyScrambles(moves);  | 
|
| 478 | 
    glowCubits(mCubitsNotInvolved[mCurrPhase]);  | 
|
| 479 | 
    }  | 
|
| 480 | 
     | 
|
| 481 | 
    setText(act);  | 
|
| 482 | 
    }  | 
|
| 483 | 
    }  | 
|
| 484 | 
     | 
|
| 485 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 486 | 
     | 
|
| 487 | 
    void nextMove()  | 
|
| 488 | 
        {
   | 
|
| 489 | 
    if( mMoves!=null && mCanMove )  | 
|
| 490 | 
          {
   | 
|
| 491 | 
    SolverActivity act=mAct.get();  | 
|
| 492 | 
     | 
|
| 493 | 
    if( mCurrMove<mNumMoves )  | 
|
| 494 | 
            {
   | 
|
| 495 | 
    mCanMove = false;  | 
|
| 496 | 
    int[] move = mMoves[mCurrPhase][mCurrMove++];  | 
|
| 497 | 
    ObjectControl control = act.getControl();  | 
|
| 498 | 
    control.blockTouch(MOVES_PLACE_1);  | 
|
| 499 | 
    control.addRotation(this, move[0], (1<<move[1]), move[2], MILLIS_PER_DEGREE);  | 
|
| 500 | 
    if( mCurrMove==mNumMoves && mCurrPhase==mNumPhases-1 ) glowCubits(mCubitsNotInvolved[mCurrPhase]);  | 
|
| 501 | 
    }  | 
|
| 502 | 
    else if( mCurrPhase<mNumPhases-1 )  | 
|
| 503 | 
            {
   | 
|
| 504 | 
    mCurrPhase++;  | 
|
| 505 | 
    mNumMoves = mMoves[mCurrPhase]==null ? 0 : mMoves[mCurrPhase].length;  | 
|
| 506 | 
    mCurrMove = 0;  | 
|
| 507 | 
    glowCubits(mCubitsNotInvolved[mCurrPhase-1]);  | 
|
| 508 | 
    }  | 
|
| 509 | 
    else  | 
|
| 510 | 
            {
   | 
|
| 511 | 
    mCurrPhase = 0;  | 
|
| 512 | 
    mNumMoves = mMoves[mCurrPhase]==null ? 0 : mMoves[mCurrPhase].length;  | 
|
| 513 | 
    mCurrMove = 0;  | 
|
| 514 | 
    int[][] moves = transformMoves(mMoves, false);  | 
|
| 515 | 
    ObjectControl control = act.getControl();  | 
|
| 516 | 
    control.applyScrambles(moves);  | 
|
| 517 | 
    }  | 
|
| 518 | 
     | 
|
| 519 | 
    setText(act);  | 
|
| 520 | 
    }  | 
|
| 521 | 
    }  | 
|
| 522 | 
     | 
|
| 523 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 524 | 
     | 
|
| 525 | 
    public void updateNames(String[] names)  | 
|
| 526 | 
        {
   | 
|
| 527 | 
    mPhaseNames = names;  | 
|
| 528 | 
    mNumPhases = names.length;  | 
|
| 529 | 
    mMoves = new int[mNumPhases][][];  | 
|
| 530 | 
    mCubitsNotInvolved = new int[mNumPhases][];  | 
|
| 531 | 
    mCanMove = true;  | 
|
| 532 | 
    if( mAct!=null ) setSolution(null,0,null);  | 
|
| 533 | 
    }  | 
|
| 534 | 
     | 
|
| 535 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 536 | 
     | 
|
| 537 | 
    public void setSolution(int[][] moves, int phase, int[][] subphases)  | 
|
| 538 | 
        {
   | 
|
| 539 | 
    SolverActivity act=mAct.get();  | 
|
| 540 | 
     | 
|
| 541 | 
    if( subphases!=null )  | 
|
| 542 | 
          {
   | 
|
| 543 | 
    ObjectControl control=act.getControl();  | 
|
| 544 | 
    TwistyObject object=control.getObject();  | 
|
| 545 | 
    int numCubits=object.getNumCubits();  | 
|
| 546 | 
    mCubitsNotInvolved[phase]= computeCubitsNotInvolved(subphases, numCubits);  | 
|
| 547 | 
    }  | 
|
| 548 | 
     | 
|
| 549 | 
    mMoves[phase] = moves;  | 
|
| 550 | 
    if( phase==0 ) mNumMoves = (moves==null ? 0 : moves.length);  | 
|
| 551 | 
    mCurrPhase = 0;  | 
|
| 552 | 
    mCurrMove = 0;  | 
|
| 553 | 
     | 
|
| 554 | 
    setText(act);  | 
|
| 555 | 
    }  | 
|
| 556 | 
     | 
|
| 557 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 558 | 
     | 
|
| 559 | 
    public void onActionFinished(final long effectID)  | 
|
| 560 | 
        {
   | 
|
| 561 | 
    mCanMove = true;  | 
|
| 562 | 
    SolverActivity act=mAct.get();  | 
|
| 563 | 
    ObjectControl control = act.getControl();  | 
|
| 564 | 
    control.unblockRotation();  | 
|
| 565 | 
    }  | 
|
| 566 | 
     | 
|
| 567 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 568 | 
     | 
|
| 569 | 
    public void effectFinished(long id)  | 
|
| 570 | 
        {
   | 
|
| 571 | 
    SolverActivity act=mAct.get();  | 
|
| 572 | 
    ObjectControl control = act.getControl();  | 
|
| 573 | 
    TwistyObject object=control.getObject();  | 
|
| 574 | 
    DistortedEffects effects=object.getObjectEffects();  | 
|
| 575 | 
    effects.abortById(id);  | 
|
| 576 | 
    mEffectWorking = false;  | 
|
| 577 | 
    }  | 
|
| 578 | 
    }  | 
|
| src/main/java/org/distorted/solverui/ScreenSetupPosition.java | ||
|---|---|---|
| 1 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 2 | 
    // Copyright 2023 Leszek Koltunski //  | 
|
| 3 | 
    // //  | 
|
| 4 | 
    // This file is part of Magic Cube. //  | 
|
| 5 | 
    // //  | 
|
| 6 | 
    // Magic Cube is proprietary software licensed under an EULA which you should have received //  | 
|
| 7 | 
    // along with the code. If not, check https://distorted.org/magic/License-Magic-Cube.html //  | 
|
| 8 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 9 | 
     | 
|
| 10 | 
    package org.distorted.solverui;  | 
|
| 11 | 
     | 
|
| 12 | 
    import static org.distorted.objectlib.metadata.ListObjects.*;  | 
|
| 13 | 
    import static org.distorted.objectlib.solvers.verifiers.SolverTablebase.*;  | 
|
| 14 | 
     | 
|
| 15 | 
    import android.content.SharedPreferences;  | 
|
| 16 | 
    import android.content.res.Resources;  | 
|
| 17 | 
    import android.graphics.Bitmap;  | 
|
| 18 | 
    import android.graphics.Canvas;  | 
|
| 19 | 
    import android.graphics.Paint;  | 
|
| 20 | 
    import android.graphics.PorterDuff;  | 
|
| 21 | 
    import android.graphics.drawable.Drawable;  | 
|
| 22 | 
    import android.os.Bundle;  | 
|
| 23 | 
    import android.view.View;  | 
|
| 24 | 
    import android.widget.ImageButton;  | 
|
| 25 | 
    import android.widget.LinearLayout;  | 
|
| 26 | 
     | 
|
| 27 | 
    import androidx.core.content.ContextCompat;  | 
|
| 28 | 
     | 
|
| 29 | 
    import org.distorted.dialogs.RubikDialogSolverError;  | 
|
| 30 | 
    import org.distorted.dialogs.RubikDialogSolverImpossible;  | 
|
| 31 | 
    import org.distorted.dialogs.RubikDialogSolvers;  | 
|
| 32 | 
    import org.distorted.helpers.TransparentImageButton;  | 
|
| 33 | 
    import org.distorted.main.MainActivity;  | 
|
| 34 | 
    import org.distorted.main.R;  | 
|
| 35 | 
    import org.distorted.objectlib.helpers.OperatingSystemInterface;  | 
|
| 36 | 
    import org.distorted.objectlib.main.ObjectControl;  | 
|
| 37 | 
    import org.distorted.objectlib.main.TwistyObject;  | 
|
| 38 | 
    import org.distorted.objectlib.metadata.ListObjects;  | 
|
| 39 | 
    import org.distorted.objectlib.shape.*;  | 
|
| 40 | 
    import org.distorted.objectlib.solvers.verifiers.ResultScreen;  | 
|
| 41 | 
    import org.distorted.objectlib.solvers.verifiers.SolverAbstract;  | 
|
| 42 | 
    import org.distorted.objectlib.solvers.verifiers.SolvingList;  | 
|
| 43 | 
     | 
|
| 44 | 
    import java.lang.ref.WeakReference;  | 
|
| 45 | 
     | 
|
| 46 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 47 | 
     | 
|
| 48 | 
    public class ScreenSetupPosition extends ScreenAbstract implements ResultScreen  | 
|
| 49 | 
      {
   | 
|
| 50 | 
    private static final int RESET_DURATION = 1000;  | 
|
| 51 | 
    private static final int MODE_NORMAL = 0;  | 
|
| 52 | 
    private static final int MODE_DINO_4 = 1;  | 
|
| 53 | 
     | 
|
| 54 | 
    private static final int[][] colorsHex =  | 
|
| 55 | 
        {
   | 
|
| 56 | 
          {R.string.color_yellow1,R.string.color_yellow2,R.string.color_yellow3,R.string.color_yellow4,R.string.color_yellow5,R.string.color_yellow6,R.string.color_yellow7 },
   | 
|
| 57 | 
          {R.string.color_white1 ,R.string.color_white2 ,R.string.color_white3 ,R.string.color_white4 ,R.string.color_white5 ,R.string.color_white6 ,R.string.color_white7  },
   | 
|
| 58 | 
          {R.string.color_blue1  ,R.string.color_blue2  ,R.string.color_blue3  ,R.string.color_blue4  ,R.string.color_blue5  ,R.string.color_blue6  ,R.string.color_blue7   },
   | 
|
| 59 | 
          {R.string.color_green1 ,R.string.color_green2 ,R.string.color_green3 ,R.string.color_green4 ,R.string.color_green5 ,R.string.color_green6 ,R.string.color_green7  },
   | 
|
| 60 | 
          {R.string.color_red1   ,R.string.color_red2   ,R.string.color_red3   ,R.string.color_red4   ,R.string.color_red5   ,R.string.color_red6   ,R.string.color_red7    },
   | 
|
| 61 | 
          {R.string.color_orange1,R.string.color_orange2,R.string.color_orange3,R.string.color_orange4,R.string.color_orange5,R.string.color_orange6,R.string.color_orange7 },
   | 
|
| 62 | 
    };  | 
|
| 63 | 
    private static final int[][] colorsTet =  | 
|
| 64 | 
        {
   | 
|
| 65 | 
          {R.string.color_green1 ,R.string.color_green2 ,R.string.color_green3 ,R.string.color_green4 ,R.string.color_green5 ,R.string.color_green6 ,R.string.color_green7  },
   | 
|
| 66 | 
          {R.string.color_yellow1,R.string.color_yellow2,R.string.color_yellow3,R.string.color_yellow4,R.string.color_yellow5,R.string.color_yellow6,R.string.color_yellow7 },
   | 
|
| 67 | 
          {R.string.color_blue1  ,R.string.color_blue2  ,R.string.color_blue3  ,R.string.color_blue4  ,R.string.color_blue5  ,R.string.color_blue6  ,R.string.color_blue7   },
   | 
|
| 68 | 
          {R.string.color_red1   ,R.string.color_red2   ,R.string.color_red3   ,R.string.color_red4   ,R.string.color_red5   ,R.string.color_red6   ,R.string.color_red7    },
   | 
|
| 69 | 
    };  | 
|
| 70 | 
    private static final int[][] colorsOct =  | 
|
| 71 | 
        {
   | 
|
| 72 | 
          {R.string.color_violet1,R.string.color_violet2,R.string.color_violet3,R.string.color_violet4,R.string.color_violet5,R.string.color_violet6,R.string.color_violet7 },
   | 
|
| 73 | 
          {R.string.color_grey1  ,R.string.color_grey2  ,R.string.color_grey3  ,R.string.color_grey4  ,R.string.color_grey5  ,R.string.color_grey6  ,R.string.color_grey7   },
   | 
|
| 74 | 
          {R.string.color_blue1  ,R.string.color_blue2  ,R.string.color_blue3  ,R.string.color_blue4  ,R.string.color_blue5  ,R.string.color_blue6  ,R.string.color_blue7   },
   | 
|
| 75 | 
          {R.string.color_red1   ,R.string.color_red2   ,R.string.color_red3   ,R.string.color_red4   ,R.string.color_red5   ,R.string.color_red6   ,R.string.color_red7    },
   | 
|
| 76 | 
          {R.string.color_orange1,R.string.color_orange2,R.string.color_orange3,R.string.color_orange4,R.string.color_orange5,R.string.color_orange6,R.string.color_orange7 },
   | 
|
| 77 | 
          {R.string.color_green1 ,R.string.color_green2 ,R.string.color_green3 ,R.string.color_green4 ,R.string.color_green5 ,R.string.color_green6 ,R.string.color_green7  },
   | 
|
| 78 | 
          {R.string.color_white1 ,R.string.color_white2 ,R.string.color_white3 ,R.string.color_white4 ,R.string.color_white5 ,R.string.color_white6 ,R.string.color_white7  },
   | 
|
| 79 | 
          {R.string.color_yellow1,R.string.color_yellow2,R.string.color_yellow3,R.string.color_yellow4,R.string.color_yellow5,R.string.color_yellow6,R.string.color_yellow7 },
   | 
|
| 80 | 
    };  | 
|
| 81 | 
    private static final int[][] colorsDi4 =  | 
|
| 82 | 
        {
   | 
|
| 83 | 
          {R.string.color_yellow1,R.string.color_yellow2,R.string.color_yellow3,R.string.color_yellow4,R.string.color_yellow5,R.string.color_yellow6,R.string.color_yellow7 },
   | 
|
| 84 | 
          {R.string.color_white1 ,R.string.color_white2 ,R.string.color_white3 ,R.string.color_white4 ,R.string.color_white5 ,R.string.color_white6 ,R.string.color_white7  },
   | 
|
| 85 | 
          {R.string.color_blue1  ,R.string.color_blue2  ,R.string.color_blue3  ,R.string.color_blue4  ,R.string.color_blue5  ,R.string.color_blue6  ,R.string.color_blue7   },
   | 
|
| 86 | 
          {R.string.color_red1   ,R.string.color_red2   ,R.string.color_red3   ,R.string.color_red4   ,R.string.color_red5   ,R.string.color_red6   ,R.string.color_red7    },
   | 
|
| 87 | 
    };  | 
|
| 88 | 
     | 
|
| 89 | 
    private static Bitmap[] mBitmap;  | 
|
| 90 | 
    private ImageButton[] mColorButton;  | 
|
| 91 | 
    private TransparentImageButton mResetButton,mBackButton, mSolveButton;  | 
|
| 92 | 
    private boolean mSolving;  | 
|
| 93 | 
    private int mCurrentColor, mCurrentButton;  | 
|
| 94 | 
    private int[] mFaceColors;  | 
|
| 95 | 
    private int mColorMode;  | 
|
| 96 | 
    private int mNumColors;  | 
|
| 97 | 
    private int mNumBitmapRows;  | 
|
| 98 | 
    private float mBitmapSize;  | 
|
| 99 | 
    private WeakReference<SolverActivity> mWeakAct;  | 
|
| 100 | 
    private int mObjectOrdinal;  | 
|
| 101 | 
    private String[] mPhaseNames;  | 
|
| 102 | 
     | 
|
| 103 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 104 | 
     | 
|
| 105 | 
    void leaveScreen(SolverActivity act)  | 
|
| 106 | 
        {
   | 
|
| 107 | 
    ObjectControl control = act.getControl();  | 
|
| 108 | 
    control.unsetLock();  | 
|
| 109 | 
    }  | 
|
| 110 | 
     | 
|
| 111 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 112 | 
     | 
|
| 113 | 
    void enterScreen(final SolverActivity act)  | 
|
| 114 | 
        {
   | 
|
| 115 | 
    ObjectControl control = act.getControl();  | 
|
| 116 | 
    control.setLock(false);  | 
|
| 117 | 
     | 
|
| 118 | 
    float width = act.getScreenWidthInPixels();  | 
|
| 119 | 
    float heigh = act.getScreenHeightInPixels();  | 
|
| 120 | 
     | 
|
| 121 | 
    mWeakAct = new WeakReference<>(act);  | 
|
| 122 | 
    mSolving = false;  | 
|
| 123 | 
    mPhaseNames = null;  | 
|
| 124 | 
     | 
|
| 125 | 
    mObjectOrdinal = act.getObjectOrdinal();  | 
|
| 126 | 
    control.solveOnly();  | 
|
| 127 | 
    generateFaceColors(mObjectOrdinal);  | 
|
| 128 | 
     | 
|
| 129 | 
    mNumBitmapRows = mNumColors>8 ? 2 : 1;  | 
|
| 130 | 
    mBitmapSize = computeBitmapSize(width,heigh);  | 
|
| 131 | 
     | 
|
| 132 | 
    // TOP ////////////////////////////  | 
|
| 133 | 
    LinearLayout layoutTop = act.findViewById(R.id.upperBar);  | 
|
| 134 | 
    layoutTop.removeAllViews();  | 
|
| 135 | 
     | 
|
| 136 | 
    if( mNumColors>0 )  | 
|
| 137 | 
          {
   | 
|
| 138 | 
    setupBitmaps();  | 
|
| 139 | 
    setupColorButtons(act);  | 
|
| 140 | 
    markButton(act);  | 
|
| 141 | 
    addButtonsToTopLayout(act,layoutTop);  | 
|
| 142 | 
    }  | 
|
| 143 | 
     | 
|
| 144 | 
    // BOT ////////////////////////////  | 
|
| 145 | 
    LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.MATCH_PARENT,1);  | 
|
| 146 | 
     | 
|
| 147 | 
    LinearLayout layoutL = new LinearLayout(act);  | 
|
| 148 | 
    layoutL.setLayoutParams(params);  | 
|
| 149 | 
    LinearLayout layoutM = new LinearLayout(act);  | 
|
| 150 | 
    layoutM.setLayoutParams(params);  | 
|
| 151 | 
    LinearLayout layoutR = new LinearLayout(act);  | 
|
| 152 | 
    layoutR.setLayoutParams(params);  | 
|
| 153 | 
     | 
|
| 154 | 
    LinearLayout layoutBot = act.findViewById(R.id.lowerBar);  | 
|
| 155 | 
    layoutBot.removeAllViews();  | 
|
| 156 | 
     | 
|
| 157 | 
    setupResetButton(act);  | 
|
| 158 | 
    setupSolveButton(act);  | 
|
| 159 | 
    setupBackButton(act);  | 
|
| 160 | 
     | 
|
| 161 | 
    layoutL.addView(mResetButton);  | 
|
| 162 | 
    layoutM.addView(mSolveButton);  | 
|
| 163 | 
    layoutR.addView(mBackButton);  | 
|
| 164 | 
     | 
|
| 165 | 
    layoutBot.addView(layoutL);  | 
|
| 166 | 
    layoutBot.addView(layoutM);  | 
|
| 167 | 
    layoutBot.addView(layoutR);  | 
|
| 168 | 
    }  | 
|
| 169 | 
     | 
|
| 170 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 171 | 
     | 
|
| 172 | 
    private float computeBitmapSize(float width, float heigh)  | 
|
| 173 | 
        {
   | 
|
| 174 | 
    final float BUTTON_RATIO = 0.75f;  | 
|
| 175 | 
    float sizeV = (heigh/mNumBitmapRows)*MainActivity.RATIO_BAR;  | 
|
| 176 | 
    float sizeH = (width*mNumBitmapRows)/mNumColors;  | 
|
| 177 | 
     | 
|
| 178 | 
    return BUTTON_RATIO*Math.min(sizeV,sizeH);  | 
|
| 179 | 
    }  | 
|
| 180 | 
     | 
|
| 181 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 182 | 
     | 
|
| 183 | 
    private void addButtonsToTopLayout(SolverActivity act, LinearLayout layout)  | 
|
| 184 | 
        {
   | 
|
| 185 | 
    if( mNumBitmapRows==1 )  | 
|
| 186 | 
          {
   | 
|
| 187 | 
    for(ImageButton button: mColorButton) layout.addView(button);  | 
|
| 188 | 
    }  | 
|
| 189 | 
    else if( mNumBitmapRows==2 )  | 
|
| 190 | 
          {
   | 
|
| 191 | 
    LinearLayout layoutV = new LinearLayout(act);  | 
|
| 192 | 
    layoutV.setOrientation(LinearLayout.VERTICAL);  | 
|
| 193 | 
    LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.MATCH_PARENT,1);  | 
|
| 194 | 
    layoutV.setLayoutParams(params);  | 
|
| 195 | 
    LinearLayout layoutT = new LinearLayout(act);  | 
|
| 196 | 
    layoutT.setOrientation(LinearLayout.HORIZONTAL);  | 
|
| 197 | 
    LinearLayout layoutB = new LinearLayout(act);  | 
|
| 198 | 
    layoutB.setOrientation(LinearLayout.HORIZONTAL);  | 
|
| 199 | 
     | 
|
| 200 | 
    int numB = mColorButton.length;  | 
|
| 201 | 
    for(int b=0 ; b<numB/2; b++) layoutT.addView(mColorButton[b]);  | 
|
| 202 | 
    for(int b=numB/2; b<numB ; b++) layoutB.addView(mColorButton[b]);  | 
|
| 203 | 
     | 
|
| 204 | 
    layoutV.addView(layoutT);  | 
|
| 205 | 
    layoutV.addView(layoutB);  | 
|
| 206 | 
    layout.addView(layoutV);  | 
|
| 207 | 
    }  | 
|
| 208 | 
    }  | 
|
| 209 | 
     | 
|
| 210 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 211 | 
    // This doesn't quite work in many cases, but in case of the solvers that will pop up in foreseeable  | 
|
| 212 | 
    // future it should be ok.  | 
|
| 213 | 
     | 
|
| 214 | 
    public void generateFaceColors(int object)  | 
|
| 215 | 
        {
   | 
|
| 216 | 
    mColorMode = MODE_NORMAL;  | 
|
| 217 | 
     | 
|
| 218 | 
    if( object==PYRA_3.ordinal() ||  | 
|
| 219 | 
    object==PYRA_4.ordinal() ||  | 
|
| 220 | 
    object==PYRA_5.ordinal() ||  | 
|
| 221 | 
    object==PDUO_2.ordinal() ||  | 
|
| 222 | 
    object==JING_2.ordinal() ||  | 
|
| 223 | 
    object==MORP_2.ordinal() ||  | 
|
| 224 | 
    object==MORP_3.ordinal() ||  | 
|
| 225 | 
    object==MORP_4.ordinal() )  | 
|
| 226 | 
          {
   | 
|
| 227 | 
    mNumColors = ShapeTetrahedron.NUM_FACES;  | 
|
| 228 | 
    mFaceColors = ShapeTetrahedron.FACE_COLORS;  | 
|
| 229 | 
    }  | 
|
| 230 | 
    else if( object==DIAM_2.ordinal() ||  | 
|
| 231 | 
    object==DIAM_3.ordinal() ||  | 
|
| 232 | 
    object==DIAM_4.ordinal() ||  | 
|
| 233 | 
    object==TRAJ_3.ordinal() ||  | 
|
| 234 | 
    object==TRAJ_4.ordinal() ||  | 
|
| 235 | 
    object==PDIA_3.ordinal() )  | 
|
| 236 | 
          {
   | 
|
| 237 | 
    mNumColors = ShapeOctahedron.NUM_FACES;  | 
|
| 238 | 
    mFaceColors = ShapeOctahedron.FACE_COLORS;  | 
|
| 239 | 
    }  | 
|
| 240 | 
    else if( object==CRYS_3.ordinal() ||  | 
|
| 241 | 
    object==STAR_3.ordinal() ||  | 
|
| 242 | 
    object==PENT_2.ordinal() ||  | 
|
| 243 | 
    object==KILO_3.ordinal() ||  | 
|
| 244 | 
    object==KILO_5.ordinal() ||  | 
|
| 245 | 
    object==MEGA_3.ordinal() ||  | 
|
| 246 | 
    object==MEGA_5.ordinal() )  | 
|
| 247 | 
          {
   | 
|
| 248 | 
    mNumColors = ShapeDodecahedron.NUM_FACES;  | 
|
| 249 | 
    mFaceColors = ShapeDodecahedron.FACE_COLORS;  | 
|
| 250 | 
    }  | 
|
| 251 | 
    else if( object==BALL_4.ordinal() )  | 
|
| 252 | 
          {
   | 
|
| 253 | 
    mNumColors = ShapeDiamond.NUM_FACES;  | 
|
| 254 | 
    mFaceColors = ShapeDiamond.FACE_COLORS;  | 
|
| 255 | 
    }  | 
|
| 256 | 
    else if( object==ICOS_2.ordinal() )  | 
|
| 257 | 
          {
   | 
|
| 258 | 
    mNumColors = ShapeIcosahedron.NUM_FACES;  | 
|
| 259 | 
    mFaceColors = ShapeIcosahedron.FACE_COLORS;  | 
|
| 260 | 
    }  | 
|
| 261 | 
    else if( object==DIN4_3.ordinal() )  | 
|
| 262 | 
          {
   | 
|
| 263 | 
    mNumColors = 4;  | 
|
| 264 | 
          mFaceColors = new int[] { ShapeColors.COLOR_YELLOW, ShapeColors.COLOR_RED, ShapeColors.COLOR_BLUE, ShapeColors.COLOR_WHITE};
   | 
|
| 265 | 
    mColorMode = MODE_DINO_4;  | 
|
| 266 | 
    }  | 
|
| 267 | 
    else  | 
|
| 268 | 
          {
   | 
|
| 269 | 
    mNumColors = ShapeHexahedron.NUM_FACES;  | 
|
| 270 | 
    mFaceColors = ShapeHexahedron.FACE_COLORS;  | 
|
| 271 | 
    }  | 
|
| 272 | 
    }  | 
|
| 273 | 
     | 
|
| 274 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 275 | 
     | 
|
| 276 | 
    private void setupBitmaps()  | 
|
| 277 | 
        {
   | 
|
| 278 | 
    final int SIZE = (int)mBitmapSize;  | 
|
| 279 | 
    final float R = SIZE*0.15f;  | 
|
| 280 | 
    final float M = SIZE*0.08f;  | 
|
| 281 | 
     | 
|
| 282 | 
    mBitmap = new Bitmap[mNumColors];  | 
|
| 283 | 
     | 
|
| 284 | 
    Paint paint = new Paint();  | 
|
| 285 | 
    paint.setColor(0xff008800);  | 
|
| 286 | 
    paint.setStyle(Paint.Style.FILL);  | 
|
| 287 | 
     | 
|
| 288 | 
    paint.setAntiAlias(true);  | 
|
| 289 | 
    paint.setTextAlign(Paint.Align.CENTER);  | 
|
| 290 | 
    paint.setStyle(Paint.Style.FILL);  | 
|
| 291 | 
     | 
|
| 292 | 
    for(int i=0; i<mNumColors; i++)  | 
|
| 293 | 
          {
   | 
|
| 294 | 
    mBitmap[i] = Bitmap.createBitmap(SIZE, SIZE, Bitmap.Config.ARGB_8888);  | 
|
| 295 | 
    Canvas canvas = new Canvas(mBitmap[i]);  | 
|
| 296 | 
     | 
|
| 297 | 
    paint.setColor(0xff000000);  | 
|
| 298 | 
    canvas.drawRect(0, 0, SIZE, SIZE, paint);  | 
|
| 299 | 
     | 
|
| 300 | 
    paint.setColor(mFaceColors[i]);  | 
|
| 301 | 
    canvas.drawRoundRect( M, M, SIZE-M, SIZE-M, R, R, paint);  | 
|
| 302 | 
    }  | 
|
| 303 | 
    }  | 
|
| 304 | 
     | 
|
| 305 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 306 | 
     | 
|
| 307 | 
    private int translateColor(int color)  | 
|
| 308 | 
        {
   | 
|
| 309 | 
    if( mColorMode==MODE_DINO_4 )  | 
|
| 310 | 
          {
   | 
|
| 311 | 
    int realColor = mFaceColors[color];  | 
|
| 312 | 
    int[] hexColors = ShapeHexahedron.FACE_COLORS;  | 
|
| 313 | 
     | 
|
| 314 | 
    for(int i=0; i<6; i++)  | 
|
| 315 | 
    if( hexColors[i]==realColor ) return i;  | 
|
| 316 | 
    }  | 
|
| 317 | 
     | 
|
| 318 | 
    return color;  | 
|
| 319 | 
    }  | 
|
| 320 | 
     | 
|
| 321 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 322 | 
     | 
|
| 323 | 
    private boolean pressSolve(SolverActivity act)  | 
|
| 324 | 
        {
   | 
|
| 325 | 
    int[] solverOrdinals = SolvingList.getSolverOrdinals(mObjectOrdinal);  | 
|
| 326 | 
     | 
|
| 327 | 
    if( solverOrdinals!=null )  | 
|
| 328 | 
          {
   | 
|
| 329 | 
    SolvingList slvList = SolvingList.getSolver(solverOrdinals[0]);  | 
|
| 330 | 
    OperatingSystemInterface os = act.getInterface();  | 
|
| 331 | 
    TwistyObject object = act.getObject();  | 
|
| 332 | 
    SolverAbstract solver = slvList.create(os,object);  | 
|
| 333 | 
     | 
|
| 334 | 
    if( solver!=null )  | 
|
| 335 | 
            {
   | 
|
| 336 | 
    int[] result = solver.validatePosition(object);  | 
|
| 337 | 
     | 
|
| 338 | 
    if( result[0]>=0 ) // position is valid  | 
|
| 339 | 
              {
   | 
|
| 340 | 
    if( solverOrdinals.length==1 ) // just one solver - simply launch it  | 
|
| 341 | 
                {
   | 
|
| 342 | 
    solver.solve(this,result);  | 
|
| 343 | 
    return true;  | 
|
| 344 | 
    }  | 
|
| 345 | 
    else // more than one solver - pop up a choosing dialog  | 
|
| 346 | 
                {
   | 
|
| 347 | 
    ListObjects objList = ListObjects.getObject(mObjectOrdinal);  | 
|
| 348 | 
    String upperName = objList.name();  | 
|
| 349 | 
    Bundle bundle = new Bundle();  | 
|
| 350 | 
                bundle.putString("argument", upperName );
   | 
|
| 351 | 
    RubikDialogSolvers solv = new RubikDialogSolvers();  | 
|
| 352 | 
    solv.setArguments(bundle);  | 
|
| 353 | 
    solv.show( act.getSupportFragmentManager(), RubikDialogSolvers.getDialogTag() );  | 
|
| 354 | 
    return false;  | 
|
| 355 | 
    }  | 
|
| 356 | 
    }  | 
|
| 357 | 
    else  | 
|
| 358 | 
              {
   | 
|
| 359 | 
    displayImpossibleDialog(result,solver.getFaceColors());  | 
|
| 360 | 
    return false;  | 
|
| 361 | 
    }  | 
|
| 362 | 
    }  | 
|
| 363 | 
    else  | 
|
| 364 | 
            {
   | 
|
| 365 | 
    displayErrorDialog(act.getString(R.string.solver_generic_not_implemented));  | 
|
| 366 | 
    return false;  | 
|
| 367 | 
    }  | 
|
| 368 | 
    }  | 
|
| 369 | 
    else // no solvers? Impossible!  | 
|
| 370 | 
          {
   | 
|
| 371 | 
          displayErrorDialog("No solvers found for object "+mObjectOrdinal);
   | 
|
| 372 | 
    return false;  | 
|
| 373 | 
    }  | 
|
| 374 | 
    }  | 
|
| 375 | 
     | 
|
| 376 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 377 | 
     | 
|
| 378 | 
      public void fail(String result) {}
   | 
|
| 379 | 
      public void setPhaseNames(String[] names) { mPhaseNames = names; }
   | 
|
| 380 | 
     | 
|
| 381 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 382 | 
     | 
|
| 383 | 
    private void setupColorButtons(final SolverActivity act)  | 
|
| 384 | 
        {
   | 
|
| 385 | 
    mColorButton = new ImageButton[mNumColors];  | 
|
| 386 | 
     | 
|
| 387 | 
    for(int i=0; i<mNumColors; i++)  | 
|
| 388 | 
          {
   | 
|
| 389 | 
    final int ii = i;  | 
|
| 390 | 
    LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,LinearLayout.LayoutParams.MATCH_PARENT, 1.0f);  | 
|
| 391 | 
     | 
|
| 392 | 
    mColorButton[i] = new ImageButton(act);  | 
|
| 393 | 
    mColorButton[i].setLayoutParams(params);  | 
|
| 394 | 
    mColorButton[i].setImageBitmap(mBitmap[i]);  | 
|
| 395 | 
     | 
|
| 396 | 
    mColorButton[i].setOnClickListener( new View.OnClickListener()  | 
|
| 397 | 
            {
   | 
|
| 398 | 
    @Override  | 
|
| 399 | 
    public void onClick(View view)  | 
|
| 400 | 
              {
   | 
|
| 401 | 
    mCurrentColor = translateColor(ii);  | 
|
| 402 | 
    mCurrentButton= ii;  | 
|
| 403 | 
    markButton(act);  | 
|
| 404 | 
    }  | 
|
| 405 | 
    });  | 
|
| 406 | 
    }  | 
|
| 407 | 
    }  | 
|
| 408 | 
     | 
|
| 409 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 410 | 
     | 
|
| 411 | 
    private void setupResetButton(final SolverActivity act)  | 
|
| 412 | 
        {
   | 
|
| 413 | 
    LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.MATCH_PARENT);  | 
|
| 414 | 
    mResetButton = new TransparentImageButton(act, R.drawable.ui_reset, params);  | 
|
| 415 | 
     | 
|
| 416 | 
    mResetButton.setOnClickListener( new View.OnClickListener()  | 
|
| 417 | 
          {
   | 
|
| 418 | 
    @Override  | 
|
| 419 | 
    public void onClick(View v)  | 
|
| 420 | 
            {
   | 
|
| 421 | 
    ObjectControl control = act.getControl();  | 
|
| 422 | 
    control.resetTextureMapsEffect(RESET_DURATION);  | 
|
| 423 | 
    }  | 
|
| 424 | 
    });  | 
|
| 425 | 
    }  | 
|
| 426 | 
     | 
|
| 427 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 428 | 
     | 
|
| 429 | 
    private void setupSolveButton(final SolverActivity act)  | 
|
| 430 | 
        {
   | 
|
| 431 | 
    LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.MATCH_PARENT,1.0f);  | 
|
| 432 | 
    mSolveButton = new TransparentImageButton(act,R.drawable.ui_solve,params);  | 
|
| 433 | 
     | 
|
| 434 | 
    mSolveButton.setOnClickListener( new View.OnClickListener()  | 
|
| 435 | 
          {
   | 
|
| 436 | 
    @Override  | 
|
| 437 | 
    public void onClick(View v)  | 
|
| 438 | 
            {
   | 
|
| 439 | 
    if( !mSolving && pressSolve(act) ) mSolving = true;  | 
|
| 440 | 
    }  | 
|
| 441 | 
    });  | 
|
| 442 | 
    }  | 
|
| 443 | 
     | 
|
| 444 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 445 | 
     | 
|
| 446 | 
    private void setupBackButton(final SolverActivity act)  | 
|
| 447 | 
        {
   | 
|
| 448 | 
    LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.MATCH_PARENT,1.0f);  | 
|
| 449 | 
    mBackButton = new TransparentImageButton(act,R.drawable.ui_back,params);  | 
|
| 450 | 
     | 
|
| 451 | 
    mBackButton.setOnClickListener( new View.OnClickListener()  | 
|
| 452 | 
          {
   | 
|
| 453 | 
    @Override  | 
|
| 454 | 
    public void onClick(View v)  | 
|
| 455 | 
            {
   | 
|
| 456 | 
    ObjectControl control = act.getControl();  | 
|
| 457 | 
    control.resetAllTextureMaps();  | 
|
| 458 | 
    ScreenList.goBack(act);  | 
|
| 459 | 
    }  | 
|
| 460 | 
    });  | 
|
| 461 | 
    }  | 
|
| 462 | 
     | 
|
| 463 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 464 | 
     | 
|
| 465 | 
    private void markButton(SolverActivity act)  | 
|
| 466 | 
        {
   | 
|
| 467 | 
    if( mCurrentButton>=mNumColors )  | 
|
| 468 | 
          {
   | 
|
| 469 | 
    mCurrentButton = 0;  | 
|
| 470 | 
    mCurrentColor = translateColor(0);  | 
|
| 471 | 
    }  | 
|
| 472 | 
     | 
|
| 473 | 
    for(int b=0; b<mNumColors; b++)  | 
|
| 474 | 
          {
   | 
|
| 475 | 
    Drawable d = mColorButton[b].getBackground();  | 
|
| 476 | 
    int s = b==mCurrentButton ? act.getSelectedColor() : act.getNormalColor();  | 
|
| 477 | 
    d.setColorFilter(ContextCompat.getColor(act,s), PorterDuff.Mode.MULTIPLY);  | 
|
| 478 | 
    }  | 
|
| 479 | 
    }  | 
|
| 480 | 
     | 
|
| 481 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 482 | 
     | 
|
| 483 | 
    public void savePreferences(SharedPreferences.Editor editor)  | 
|
| 484 | 
        {
   | 
|
| 485 | 
        editor.putInt("stateSolver_color" , mCurrentColor );
   | 
|
| 486 | 
        editor.putInt("stateSolver_button", mCurrentButton);
   | 
|
| 487 | 
    }  | 
|
| 488 | 
     | 
|
| 489 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 490 | 
     | 
|
| 491 | 
    public void restorePreferences(SharedPreferences preferences)  | 
|
| 492 | 
        {
   | 
|
| 493 | 
        mCurrentColor = preferences.getInt("stateSolver_color" , 0);
   | 
|
| 494 | 
        mCurrentButton= preferences.getInt("stateSolver_button", 0);
   | 
|
| 495 | 
    }  | 
|
| 496 | 
     | 
|
| 497 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 498 | 
     | 
|
| 499 | 
    public int getCurrentColor()  | 
|
| 500 | 
        {
   | 
|
| 501 | 
    return mCurrentColor;  | 
|
| 502 | 
    }  | 
|
| 503 | 
     | 
|
| 504 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 505 | 
     | 
|
| 506 | 
    public void setSolved(final String moves)  | 
|
| 507 | 
        {
   | 
|
| 508 | 
    mSolving = false;  | 
|
| 509 | 
    final SolverActivity act = mWeakAct.get();  | 
|
| 510 | 
     | 
|
| 511 | 
    if( act!=null )  | 
|
| 512 | 
          {
   | 
|
| 513 | 
    act.runOnUiThread(new Runnable()  | 
|
| 514 | 
            {
   | 
|
| 515 | 
    @Override  | 
|
| 516 | 
    public void run()  | 
|
| 517 | 
              {
   | 
|
| 518 | 
    ScreenList.switchScreen(act, ScreenList.SOLU);  | 
|
| 519 | 
    ScreenSolutionSinglephased solution = (ScreenSolutionSinglephased) ScreenList.SOLU.getScreenClass();  | 
|
| 520 | 
    solution.setSolution(moves);  | 
|
| 521 | 
    if( !moves.isEmpty() ) act.doNotShowDialogAnymore();  | 
|
| 522 | 
    }  | 
|
| 523 | 
    });  | 
|
| 524 | 
    }  | 
|
| 525 | 
    }  | 
|
| 526 | 
     | 
|
| 527 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 528 | 
     | 
|
| 529 | 
    public void setSolved(final int[][] moves, final int phaseNumber, final int[][] subphases)  | 
|
| 530 | 
        {
   | 
|
| 531 | 
    mSolving = false;  | 
|
| 532 | 
    final SolverActivity act = mWeakAct.get();  | 
|
| 533 | 
     | 
|
| 534 | 
    if( act!=null )  | 
|
| 535 | 
          {
   | 
|
| 536 | 
    act.runOnUiThread(new Runnable()  | 
|
| 537 | 
            {
   | 
|
| 538 | 
    @Override  | 
|
| 539 | 
    public void run()  | 
|
| 540 | 
              {
   | 
|
| 541 | 
    if( mPhaseNames!=null )  | 
|
| 542 | 
                {
   | 
|
| 543 | 
    ScreenSolutionMultiphased screen = (ScreenSolutionMultiphased) ScreenList.PHAS.getScreenClass();  | 
|
| 544 | 
    if( phaseNumber==0 )  | 
|
| 545 | 
                  {
   | 
|
| 546 | 
    ScreenList.switchScreen(act, ScreenList.PHAS);  | 
|
| 547 | 
    screen.updateNames(mPhaseNames);  | 
|
| 548 | 
    }  | 
|
| 549 | 
    screen.setSolution(moves, phaseNumber,subphases);  | 
|
| 550 | 
    }  | 
|
| 551 | 
    else  | 
|
| 552 | 
                {
   | 
|
| 553 | 
    ScreenList.switchScreen(act, ScreenList.SOLU);  | 
|
| 554 | 
    ScreenSolutionSinglephased screen = (ScreenSolutionSinglephased) ScreenList.SOLU.getScreenClass();  | 
|
| 555 | 
    screen.setSolution(moves);  | 
|
| 556 | 
    }  | 
|
| 557 | 
     | 
|
| 558 | 
    if( moves!=null && moves.length>0 ) act.doNotShowDialogAnymore();  | 
|
| 559 | 
    }  | 
|
| 560 | 
    });  | 
|
| 561 | 
    }  | 
|
| 562 | 
    }  | 
|
| 563 | 
     | 
|
| 564 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 565 | 
     | 
|
| 566 | 
    public void displayErrorDialog(String message)  | 
|
| 567 | 
        {
   | 
|
| 568 | 
    mSolving = false;  | 
|
| 569 | 
    SolverActivity act = mWeakAct.get();  | 
|
| 570 | 
     | 
|
| 571 | 
    if( act!=null )  | 
|
| 572 | 
          {
   | 
|
| 573 | 
    RubikDialogSolverError dialog = new RubikDialogSolverError();  | 
|
| 574 | 
    Bundle bundle = new Bundle();  | 
|
| 575 | 
          bundle.putString("argument", message );
   | 
|
| 576 | 
    dialog.setArguments(bundle);  | 
|
| 577 | 
    dialog.show( act.getSupportFragmentManager(), null);  | 
|
| 578 | 
    }  | 
|
| 579 | 
    }  | 
|
| 580 | 
     | 
|
| 581 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 582 | 
     | 
|
| 583 | 
    public void displayImpossibleDialog(String message)  | 
|
| 584 | 
        {
   | 
|
| 585 | 
    mSolving = false;  | 
|
| 586 | 
    SolverActivity act = mWeakAct.get();  | 
|
| 587 | 
     | 
|
| 588 | 
    if( act!=null )  | 
|
| 589 | 
          {
   | 
|
| 590 | 
    RubikDialogSolverImpossible dialog = new RubikDialogSolverImpossible();  | 
|
| 591 | 
    Bundle bundle = new Bundle();  | 
|
| 592 | 
          bundle.putString("argument", message );
   | 
|
| 593 | 
    dialog.setArguments(bundle);  | 
|
| 594 | 
    dialog.show( act.getSupportFragmentManager(), null);  | 
|
| 595 | 
    }  | 
|
| 596 | 
    }  | 
|
| 597 | 
     | 
|
| 598 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 599 | 
     | 
|
| 600 | 
    public void displayImpossibleDialog(int[] errorCode, int[] faceColors)  | 
|
| 601 | 
        {
   | 
|
| 602 | 
    mSolving = false;  | 
|
| 603 | 
    SolverActivity act = mWeakAct.get();  | 
|
| 604 | 
     | 
|
| 605 | 
    if( act!=null )  | 
|
| 606 | 
          {
   | 
|
| 607 | 
    String message = error(act.getResources(),errorCode,faceColors);  | 
|
| 608 | 
    displayImpossibleDialog(message);  | 
|
| 609 | 
    }  | 
|
| 610 | 
    }  | 
|
| 611 | 
     | 
|
| 612 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 613 | 
     | 
|
| 614 | 
      int getHexColor(int color,int variant) { return colorsHex[color][variant]; }
   | 
|
| 615 | 
      int getTetColor(int color,int variant) { return colorsTet[color][variant]; }
   | 
|
| 616 | 
      int getOctColor(int color,int variant) { return colorsOct[color][variant]; }
   | 
|
| 617 | 
      int getDi4Color(int color,int variant) { return colorsDi4[color][variant]; }
   | 
|
| 618 | 
     | 
|
| 619 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 620 | 
     | 
|
| 621 | 
    String hexCornerMissingError(Resources res, int face0, int face1, int face2)  | 
|
| 622 | 
        {
   | 
|
| 623 | 
    int j0 = getHexColor(face0,3);  | 
|
| 624 | 
    int j1 = getHexColor(face1,3);  | 
|
| 625 | 
    int j2 = getHexColor(face2,4);  | 
|
| 626 | 
     | 
|
| 627 | 
    String c0 = res.getString(j0);  | 
|
| 628 | 
    String c1 = res.getString(j1);  | 
|
| 629 | 
    String c2 = res.getString(j2);  | 
|
| 630 | 
     | 
|
| 631 | 
    return res.getString(R.string.solver_generic_missing_corner,c0,c1,c2);  | 
|
| 632 | 
    }  | 
|
| 633 | 
     | 
|
| 634 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 635 | 
     | 
|
| 636 | 
    String hexCenterMissingError(Resources res, int face)  | 
|
| 637 | 
        {
   | 
|
| 638 | 
    int color = getHexColor(face,2);  | 
|
| 639 | 
    String clr= res.getString(color);  | 
|
| 640 | 
    return res.getString(R.string.solver_generic_missing_center,clr);  | 
|
| 641 | 
    }  | 
|
| 642 | 
     | 
|
| 643 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 644 | 
     | 
|
| 645 | 
    String hexEdgeMissingError(Resources res, int face0, int face1)  | 
|
| 646 | 
        {
   | 
|
| 647 | 
    int j0 = getHexColor(face0,3);  | 
|
| 648 | 
    int j1 = getHexColor(face1,6);  | 
|
| 649 | 
     | 
|
| 650 | 
    String c0 = res.getString(j0);  | 
|
| 651 | 
    String c1 = res.getString(j1);  | 
|
| 652 | 
     | 
|
| 653 | 
    return res.getString(R.string.solver_generic_missing_edge,c0,c1);  | 
|
| 654 | 
    }  | 
|
| 655 | 
     | 
|
| 656 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 657 | 
     | 
|
| 658 | 
    String hexEdgeTwistedError(Resources res, int color0, int color1)  | 
|
| 659 | 
        {
   | 
|
| 660 | 
    int j0 = getHexColor(color0,3);  | 
|
| 661 | 
    int j1 = getHexColor(color1,6);  | 
|
| 662 | 
     | 
|
| 663 | 
    String c0 = res.getString(j0);  | 
|
| 664 | 
    String c1 = res.getString(j1);  | 
|
| 665 | 
     | 
|
| 666 | 
    return res.getString(R.string.solver_generic_twisted_edge,c0,c1);  | 
|
| 667 | 
    }  | 
|
| 668 | 
     | 
|
| 669 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 670 | 
     | 
|
| 671 | 
    String hexCornerTwistedError(Resources res, int color0, int color1, int color2)  | 
|
| 672 | 
        {
   | 
|
| 673 | 
    int j0 = getHexColor(color0,3);  | 
|
| 674 | 
    int j1 = getHexColor(color1,3);  | 
|
| 675 | 
    int j2 = getHexColor(color2,5);  | 
|
| 676 | 
     | 
|
| 677 | 
    String c0 = res.getString(j0);  | 
|
| 678 | 
    String c1 = res.getString(j1);  | 
|
| 679 | 
    String c2 = res.getString(j2);  | 
|
| 680 | 
     | 
|
| 681 | 
    return res.getString(R.string.solver_generic_twisted_corner,c0,c1,c2);  | 
|
| 682 | 
    }  | 
|
| 683 | 
     | 
|
| 684 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 685 | 
     | 
|
| 686 | 
    String hexEdgeMonoError(Resources res, int color)  | 
|
| 687 | 
        {
   | 
|
| 688 | 
    int j0 = getHexColor(color,3);  | 
|
| 689 | 
    int j1 = getHexColor(color,6);  | 
|
| 690 | 
    String c0 = res.getString(j0);  | 
|
| 691 | 
    String c1 = res.getString(j1);  | 
|
| 692 | 
     | 
|
| 693 | 
    return res.getString(R.string.solver_generic_edge_mono,c0,c1);  | 
|
| 694 | 
    }  | 
|
| 695 | 
     | 
|
| 696 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 697 | 
     | 
|
| 698 | 
    String hexEdgeTwiceError(Resources res, int color0, int color1)  | 
|
| 699 | 
        {
   | 
|
| 700 | 
    int j0 = getHexColor(color0,3);  | 
|
| 701 | 
    int j1 = getHexColor(color1,6);  | 
|
| 702 | 
    String c0 = res.getString(j0);  | 
|
| 703 | 
    String c1 = res.getString(j1);  | 
|
| 704 | 
     | 
|
| 705 | 
    return res.getString(R.string.solver_generic_edge_twice,c0,c1);  | 
|
| 706 | 
    }  | 
|
| 707 | 
     | 
|
| 708 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 709 | 
     | 
|
| 710 | 
    String octCenterMissingError(Resources res, int face)  | 
|
| 711 | 
        {
   | 
|
| 712 | 
    int index = getOctColor(face,2);  | 
|
| 713 | 
    String color = res.getString(index);  | 
|
| 714 | 
    return res.getString(R.string.solver_generic_missing_center,color);  | 
|
| 715 | 
    }  | 
|
| 716 | 
     | 
|
| 717 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 718 | 
     | 
|
| 719 | 
    String octCornerMissingError(Resources res, int f1, int f2)  | 
|
| 720 | 
        {
   | 
|
| 721 | 
    int i1 = getOctColor(f1,3);  | 
|
| 722 | 
    int i2 = getOctColor(f2,4);  | 
|
| 723 | 
    String c1 = res.getString(i1);  | 
|
| 724 | 
    String c2 = res.getString(i2);  | 
|
| 725 | 
    return res.getString(R.string.solver_generic_missing_corner2,c1,c2);  | 
|
| 726 | 
    }  | 
|
| 727 | 
     | 
|
| 728 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 729 | 
     | 
|
| 730 | 
    String tetCornerMissingError(Resources res, int color0, int color1, int color2)  | 
|
| 731 | 
        {
   | 
|
| 732 | 
    int j0 = getTetColor(color0,3);  | 
|
| 733 | 
    int j1 = getTetColor(color1,3);  | 
|
| 734 | 
    int j2 = getTetColor(color2,4);  | 
|
| 735 | 
     | 
|
| 736 | 
    String c0 = res.getString(j0);  | 
|
| 737 | 
    String c1 = res.getString(j1);  | 
|
| 738 | 
    String c2 = res.getString(j2);  | 
|
| 739 | 
     | 
|
| 740 | 
    return res.getString(R.string.solver_generic_missing_corner,c0,c1,c2);  | 
|
| 741 | 
    }  | 
|
| 742 | 
     | 
|
| 743 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 744 | 
     | 
|
| 745 | 
    String tetEdgeMissingError(Resources res, int face0, int face1)  | 
|
| 746 | 
        {
   | 
|
| 747 | 
    int j0 = getTetColor(face0,3);  | 
|
| 748 | 
    int j1 = getTetColor(face1,6);  | 
|
| 749 | 
     | 
|
| 750 | 
    String c0 = res.getString(j0);  | 
|
| 751 | 
    String c1 = res.getString(j1);  | 
|
| 752 | 
     | 
|
| 753 | 
    return res.getString(R.string.solver_generic_missing_edge,c0,c1);  | 
|
| 754 | 
    }  | 
|
| 755 | 
     | 
|
| 756 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 757 | 
     | 
|
| 758 | 
    String tetCenterMissingError(Resources res, int face)  | 
|
| 759 | 
        {
   | 
|
| 760 | 
    int j = getTetColor(face,2);  | 
|
| 761 | 
    String c = res.getString(j);  | 
|
| 762 | 
    return res.getString(R.string.solver_generic_missing_center,c);  | 
|
| 763 | 
    }  | 
|
| 764 | 
     | 
|
| 765 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 766 | 
     | 
|
| 767 | 
    String tetVertexMissingError(Resources res, int color0, int color1, int color2)  | 
|
| 768 | 
        {
   | 
|
| 769 | 
    int j0 = getTetColor(color0,3);  | 
|
| 770 | 
    int j1 = getTetColor(color1,3);  | 
|
| 771 | 
    int j2 = getTetColor(color2,4);  | 
|
| 772 | 
     | 
|
| 773 | 
    String c0 = res.getString(j0);  | 
|
| 774 | 
    String c1 = res.getString(j1);  | 
|
| 775 | 
    String c2 = res.getString(j2);  | 
|
| 776 | 
     | 
|
| 777 | 
    return res.getString(R.string.solver_generic_missing_vertex,c0,c1,c2);  | 
|
| 778 | 
    }  | 
|
| 779 | 
     | 
|
| 780 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 781 | 
     | 
|
| 782 | 
    String di4EdgeThreeError(Resources res, int color)  | 
|
| 783 | 
        {
   | 
|
| 784 | 
    int j0 = getDi4Color(color,7);  | 
|
| 785 | 
    String c0 = res.getString(j0);  | 
|
| 786 | 
    return res.getString(R.string.solver_generic_edge_three,c0);  | 
|
| 787 | 
    }  | 
|
| 788 | 
     | 
|
| 789 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 790 | 
     | 
|
| 791 | 
    public String error(Resources res, int[] err, int[] faceColors)  | 
|
| 792 | 
        {
   | 
|
| 793 | 
    switch(err[0])  | 
|
| 794 | 
          {
   | 
|
| 795 | 
    case ERROR_HEX_CORNER_MISSING : return hexCornerMissingError(res,err[1],err[2],err[3]);  | 
|
| 796 | 
    case ERROR_HEX_CENTER_MISSING : return hexCenterMissingError(res,err[1]);  | 
|
| 797 | 
    case ERROR_HEX_EDGE_MISSING : return hexEdgeMissingError(res,err[1],err[2]);  | 
|
| 798 | 
    case ERROR_HEX_EDGE_TWISTED : return hexEdgeTwistedError(res,err[1],err[2]);  | 
|
| 799 | 
    case ERROR_HEX_EDGE_MONOCHROMATIC: return hexEdgeMonoError(res,err[1]);  | 
|
| 800 | 
    case ERROR_HEX_EDGE_TWICE : return hexEdgeTwiceError(res,err[1],err[2]);  | 
|
| 801 | 
    case ERROR_HEX_CORNER_TWISTED : return hexCornerTwistedError(res,err[1],err[2],err[3]);  | 
|
| 802 | 
     | 
|
| 803 | 
    case ERROR_TET_CORNER_MISSING : return tetCornerMissingError(res,err[1],err[2],err[3]);  | 
|
| 804 | 
    case ERROR_TET_VERTEX_MISSING : return tetVertexMissingError(res,err[1],err[2],err[3]);  | 
|
| 805 | 
    case ERROR_TET_EDGE_MISSING : return tetEdgeMissingError(res,faceColors[err[1]],faceColors[err[2]]);  | 
|
| 806 | 
    case ERROR_TET_CENTER_MISSING : return tetCenterMissingError(res,err[1]);  | 
|
| 807 | 
     | 
|
| 808 | 
    case ERROR_OCT_CENTER_MISSING : return octCenterMissingError(res,err[1]);  | 
|
| 809 | 
    case ERROR_OCT_CORNER_MISSING : return octCornerMissingError(res,err[1],err[2]);  | 
|
| 810 | 
     | 
|
| 811 | 
    case ERROR_DI4_EDGE_THREE : return di4EdgeThreeError(res,err[1]);  | 
|
| 812 | 
     | 
|
| 813 | 
    case ERROR_CORNERS_CANNOT : return res.getString(R.string.solver_generic_corners_cannot);  | 
|
| 814 | 
    case ERROR_EDGE_CANNOT : return res.getString(R.string.solver_generic_edges_cannot);  | 
|
| 815 | 
    case ERROR_CORNER_TWISTED : return res.getString(R.string.solver_generic_corner_twist);  | 
|
| 816 | 
    case ERROR_CORNER_TWIST_90 : return res.getString(R.string.solver_generic_corner_twist) + " (90)";  | 
|
| 817 | 
    case ERROR_CORNER_TWIST_180 : return res.getString(R.string.solver_generic_corner_twist) + " (180)";  | 
|
| 818 | 
    case ERROR_EDGE_TWISTED : return res.getString(R.string.solver_generic_edge_twist);  | 
|
| 819 | 
    case ERROR_TWO_CENTERS : return res.getString(R.string.solver_generic_two_centers);  | 
|
| 820 | 
    case ERROR_TWO_CORNERS : return res.getString(R.string.solver_generic_two_corners);  | 
|
| 821 | 
    case ERROR_TWO_EDGES : return res.getString(R.string.solver_generic_two_edges);  | 
|
| 822 | 
    case ERROR_FREE_CORNERS_NOT_EVEN : return res.getString(R.string.solver_generic_free_corners_odd);  | 
|
| 823 | 
    case ERROR_FREE_CORNERS_ROTATED : return res.getString(R.string.solver_generic_free_corners_rotated);  | 
|
| 824 | 
    case ERROR_VERTICES_CANNOT : return res.getString(R.string.solver_generic_vertices_cannot);  | 
|
| 825 | 
    case ERROR_C_V_DONT_MATCH : return res.getString(R.string.solver_generic_c_v_dont_match);  | 
|
| 826 | 
    case ERROR_TWO_CORNERS_TWO_EDGES : return res.getString(R.string.solver_two_corners_two_edges);  | 
|
| 827 | 
    }  | 
|
| 828 | 
     | 
|
| 829 | 
    return null;  | 
|
| 830 | 
    }  | 
|
| 831 | 
    }  | 
|
| src/main/java/org/distorted/solverui/ScreenSolution.java | ||
|---|---|---|
| 1 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 2 | 
    // Copyright 2023 Leszek Koltunski //  | 
|
| 3 | 
    // //  | 
|
| 4 | 
    // This file is part of Magic Cube. //  | 
|
| 5 | 
    // //  | 
|
| 6 | 
    // Magic Cube is proprietary software licensed under an EULA which you should have received //  | 
|
| 7 | 
    // along with the code. If not, check https://distorted.org/magic/License-Magic-Cube.html //  | 
|
| 8 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 9 | 
     | 
|
| 10 | 
    package org.distorted.solverui;  | 
|
| 11 | 
     | 
|
| 12 | 
    import android.content.SharedPreferences;  | 
|
| 13 | 
    import android.util.TypedValue;  | 
|
| 14 | 
    import android.view.Gravity;  | 
|
| 15 | 
    import android.view.LayoutInflater;  | 
|
| 16 | 
    import android.view.View;  | 
|
| 17 | 
    import android.widget.LinearLayout;  | 
|
| 18 | 
    import android.widget.TextView;  | 
|
| 19 | 
     | 
|
| 20 | 
    import org.distorted.helpers.TransparentImageButton;  | 
|
| 21 | 
    import org.distorted.main.R;  | 
|
| 22 | 
    import org.distorted.objectlib.helpers.MovesFinished;  | 
|
| 23 | 
    import org.distorted.objectlib.main.ObjectControl;  | 
|
| 24 | 
    import org.distorted.objectlib.patterns.RubikPattern;  | 
|
| 25 | 
     | 
|
| 26 | 
    import java.lang.ref.WeakReference;  | 
|
| 27 | 
     | 
|
| 28 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 29 | 
     | 
|
Also available in: Unified diff
If an object has more than 8 colors, in the solver's SetupPosition screen display the bitmaps in two rows.