/*
* Copyright (c) 2013 Menny Even-Danan
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.anysoftkeyboard.keyboards;
import android.content.Context;
import com.anysoftkeyboard.api.KeyCodes;
import com.anysoftkeyboard.keyboards.Keyboard.Key;
import com.menny.android.anysoftkeyboard.R;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
public class KeyboardCondenser {
private static class KeySize {
public final int width;
public final int height;
public final int X;
public final int Y;
public KeySize(int w, int h, int x, int y) {
width = w;
height = h;
X = x;
Y = y;
}
}
private static final String TAG = "ASK - KeyboardCondenser";
private CondenseType mKeyboardCondenseType = CondenseType.None;
private List<KeySize> mKeySizesMap = null;//it is usually not used, so I'll create an instance when first needed.
private final AnyKeyboard mKeyboard;
private final float mCondensingFullFactor;
private final float mCondensingEdgeFactor;
public KeyboardCondenser(Context askContext, AnyKeyboard keyboard) {
mKeyboard = keyboard;
mCondensingFullFactor = ((float) askContext.getResources()
.getInteger(R.integer.condensing_precentage)) / 100f;
mCondensingEdgeFactor = ((float) askContext.getResources()
.getInteger(R.integer.condensing_precentage_edge)) / 100f;
}
public boolean setCondensedKeys(CondenseType condenseType) {
if (mKeyboardCondenseType.equals(condenseType))
return false;//not changed
final float condensingFactor;
switch (condenseType){
case CompactToLeft:
case CompactToRight:
condensingFactor = mCondensingEdgeFactor;
break;
default:
condensingFactor = mCondensingFullFactor;
break;
}
if (!condenseType.equals(CondenseType.None) && condensingFactor > 0.97f)
return false;
List<Key> keys = mKeyboard.getKeys();
if (mKeySizesMap == null)
mKeySizesMap = new ArrayList<>(keys.size());
//restoring sizes
List<KeySize> stashedKeySizes = mKeySizesMap;
if (stashedKeySizes.size() > 0) {
//we have condensed before
if (stashedKeySizes.size() != keys.size())
throw new IllegalStateException("The size of the stashed keys and the actual keyboard keys is not the same!");
for(int i = 0; i<stashedKeySizes.size(); i++) {
Key k = keys.get(i);
KeySize originalSize = mKeySizesMap.get(i);
k.width = originalSize.width;
k.height = originalSize.height;
k.x = originalSize.X;
k.y = originalSize.Y;
}
}
//back to original state, no need to keep those key-size data anymore
mKeySizesMap.clear();
final int keyboardWidth = mKeyboard.getMinWidth();
switch (condenseType) {
case Split:
splitKeys(keyboardWidth, keyboardWidth/2, condensingFactor);
break;
case CompactToLeft:
splitKeys(keyboardWidth, keyboardWidth, condensingFactor);
break;
case CompactToRight:
splitKeys(keyboardWidth, 0, condensingFactor);
break;
case None:
// keys already restored
break;
default:
throw new IllegalArgumentException("Unknown condensing type given: "+condenseType);
}
mKeyboardCondenseType = condenseType;
//changed
return true;
}
private void splitKeys(final int keyboardWidth, final int watershedLineX, final float condensingFactor) {
int currentLeftX = 0;
int currentRightX = keyboardWidth;
int currentY = 0;
Stack<Key> rightKeys = new Stack<>();
boolean flipSideLeft = true;
Key spaceKey = null;
for (Key k : mKeyboard.getKeys()) {
// first, store the original values
mKeySizesMap.add(new KeySize(k.width, k.height, k.x, k.y));
if (currentY != k.y)// on new line, we want to handle the left
// side of the keyboard
{
flipSideLeft = !flipSideLeft;
condenseRightSide(condensingFactor, keyboardWidth,
currentRightX, rightKeys, spaceKey);
currentLeftX = 0;
currentRightX = keyboardWidth;
currentY = k.y;
rightKeys.clear();
}
int targetWidth = (int) (k.width * condensingFactor);
int keyMidPoint = (k.gap + k.x + (k.width / 2));
if (k.codes[0] == KeyCodes.SPACE &&
(k.gap + k.x) < watershedLineX &&//one side is to the left,
(k.gap + k.x+ k.width) > watershedLineX) { //the other side of the key is to the right of the watershed-line
// space is a special case, I want to make it as wide as
// possible (since it is a space-bar in the middle of the screen
spaceKey = k;
currentLeftX = condenseLeftSide(condensingFactor,
currentLeftX, k, targetWidth);
} else if (keyMidPoint < (watershedLineX - 5)) {
currentLeftX = condenseLeftSide(condensingFactor,
currentLeftX, k, targetWidth);
} else if (keyMidPoint > (watershedLineX + 5)) {
// to handle later. I need to find the last gap
currentRightX = stackRightSideKeyForLater(rightKeys, k,
targetWidth);
} else {
if (flipSideLeft) {
currentLeftX = condenseLeftSide(condensingFactor,
currentLeftX, k, targetWidth);
} else {
currentRightX = stackRightSideKeyForLater(rightKeys, k,
targetWidth);
}
}
}
// now to condense the last row
condenseRightSide(condensingFactor, keyboardWidth, currentRightX,
rightKeys, spaceKey);
}
int stackRightSideKeyForLater(Stack<Key> rightKeys, Key k, int targetWidth) {
int currentRightX;
rightKeys.push(k);
currentRightX = k.x + k.width;
k.width = targetWidth;
return currentRightX;
}
int condenseLeftSide(final float CONDENSING_FACTOR, int currentLeftX,
Key k, int targetWidth) {
currentLeftX += (k.gap * CONDENSING_FACTOR);
k.x = currentLeftX;
k.width = targetWidth;
currentLeftX += k.width;
return currentLeftX;
}
void condenseRightSide(final float CONDENSING_FACTOR,
final int keyboardWidth, int currentRightX, Stack<Key> rightKeys,
Key spaceKey) {
// currentRightX holds the rightest x+width point. condensing a bit
currentRightX = (int) (keyboardWidth - ((keyboardWidth - currentRightX) * CONDENSING_FACTOR));
while (!rightKeys.isEmpty()) {
Key rightKey = rightKeys.pop();
currentRightX -= rightKey.width;// already holds the new width
rightKey.x = currentRightX;
currentRightX -= (rightKey.gap * CONDENSING_FACTOR);
}
// now to handle the space, which will hold as much as possible
if (spaceKey != null) {
spaceKey.width = currentRightX - spaceKey.x;
}
}
}