203 lines
8.0 KiB
Java
203 lines
8.0 KiB
Java
/*
|
|
* Copyright (C) 2010 Google Inc.
|
|
*
|
|
* 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.android.inputmethod.keyboard;
|
|
|
|
import com.android.inputmethod.latin.R;
|
|
|
|
import android.content.Context;
|
|
import android.content.res.Resources;
|
|
import android.graphics.Paint;
|
|
import android.graphics.Rect;
|
|
|
|
import java.util.List;
|
|
|
|
public class MiniKeyboardBuilder {
|
|
private final Resources mRes;
|
|
private final MiniKeyboard mKeyboard;
|
|
private final CharSequence[] mPopupCharacters;
|
|
private final MiniKeyboardLayoutParams mParams;
|
|
|
|
/* package */ static class MiniKeyboardLayoutParams {
|
|
public final int mKeyWidth;
|
|
public final int mRowHeight;
|
|
/* package */ final boolean mTopRowNeedsCentering;
|
|
public final int mNumRows;
|
|
public final int mNumColumns;
|
|
public final int mLeftKeys;
|
|
public final int mRightKeys; // includes default key.
|
|
|
|
/**
|
|
* The object holding mini keyboard layout parameters.
|
|
*
|
|
* @param numKeys number of keys in this mini keyboard.
|
|
* @param maxColumns number of maximum columns of this mini keyboard.
|
|
* @param keyWidth mini keyboard key width in pixel, including horizontal gap.
|
|
* @param rowHeight mini keyboard row height in pixel, including vertical gap.
|
|
* @param coordXInParent coordinate x of the popup key in parent keyboard.
|
|
* @param parentKeyboardWidth parent keyboard width in pixel.
|
|
*/
|
|
public MiniKeyboardLayoutParams(int numKeys, int maxColumns, int keyWidth, int rowHeight,
|
|
int coordXInParent, int parentKeyboardWidth) {
|
|
if (parentKeyboardWidth / keyWidth < maxColumns)
|
|
throw new IllegalArgumentException("Keyboard is too small to hold mini keyboard: "
|
|
+ parentKeyboardWidth + " " + keyWidth + " " + maxColumns);
|
|
final int numRows = (numKeys + maxColumns - 1) / maxColumns;
|
|
mKeyWidth = keyWidth;
|
|
mRowHeight = rowHeight;
|
|
mNumRows = numRows;
|
|
|
|
final int numColumns = Math.min(numKeys, maxColumns);
|
|
final int topRowKeys = numKeys % numColumns;
|
|
mNumColumns = numColumns;
|
|
mTopRowNeedsCentering = topRowKeys != 0 && (numColumns - topRowKeys) % 2 != 0;
|
|
|
|
final int numLeftKeys = (numColumns - 1) / 2;
|
|
final int numRightKeys = numColumns - numLeftKeys; // including default key.
|
|
final int maxLeftKeys = coordXInParent / keyWidth;
|
|
final int maxRightKeys = Math.max(1, (parentKeyboardWidth - coordXInParent) / keyWidth);
|
|
if (numLeftKeys > maxLeftKeys) {
|
|
mLeftKeys = maxLeftKeys;
|
|
mRightKeys = numColumns - maxLeftKeys;
|
|
} else if (numRightKeys > maxRightKeys) {
|
|
mLeftKeys = numColumns - maxRightKeys;
|
|
mRightKeys = maxRightKeys;
|
|
} else {
|
|
mLeftKeys = numLeftKeys;
|
|
mRightKeys = numRightKeys;
|
|
}
|
|
}
|
|
|
|
// Return key position according to column count (0 is default).
|
|
/* package */ int getColumnPos(int n) {
|
|
final int col = n % mNumColumns;
|
|
if (col == 0) {
|
|
// default position.
|
|
return 0;
|
|
}
|
|
int pos = 0;
|
|
int right = 1; // include default position key.
|
|
int left = 0;
|
|
int i = 0;
|
|
while (true) {
|
|
// Assign right key if available.
|
|
if (right < mRightKeys) {
|
|
pos = right;
|
|
right++;
|
|
i++;
|
|
}
|
|
if (i >= col)
|
|
break;
|
|
// Assign left key if available.
|
|
if (left < mLeftKeys) {
|
|
left++;
|
|
pos = -left;
|
|
i++;
|
|
}
|
|
if (i >= col)
|
|
break;
|
|
}
|
|
return pos;
|
|
}
|
|
|
|
public int getDefaultKeyCoordX() {
|
|
return mLeftKeys * mKeyWidth;
|
|
}
|
|
|
|
public int getX(int n, int row) {
|
|
final int x = getColumnPos(n) * mKeyWidth + getDefaultKeyCoordX();
|
|
if (isLastRow(row) && mTopRowNeedsCentering)
|
|
return x - mKeyWidth / 2;
|
|
return x;
|
|
}
|
|
|
|
public int getY(int row) {
|
|
return (mNumRows - 1 - row) * mRowHeight;
|
|
}
|
|
|
|
public int getRowFlags(int row) {
|
|
int rowFlags = 0;
|
|
if (row == 0) rowFlags |= Keyboard.EDGE_TOP;
|
|
if (isLastRow(row)) rowFlags |= Keyboard.EDGE_BOTTOM;
|
|
return rowFlags;
|
|
}
|
|
|
|
private boolean isLastRow(int rowCount) {
|
|
return rowCount == mNumRows - 1;
|
|
}
|
|
}
|
|
|
|
public MiniKeyboardBuilder(KeyboardView view, int layoutTemplateResId, Key popupKey) {
|
|
final Context context = view.getContext();
|
|
mRes = context.getResources();
|
|
final MiniKeyboard keyboard = new MiniKeyboard(context, layoutTemplateResId, null);
|
|
mKeyboard = keyboard;
|
|
mPopupCharacters = popupKey.mPopupCharacters;
|
|
|
|
final int keyWidth = getMaxKeyWidth(view, mPopupCharacters, keyboard.getKeyWidth());
|
|
final MiniKeyboardLayoutParams params = new MiniKeyboardLayoutParams(
|
|
mPopupCharacters.length, popupKey.mMaxPopupColumn,
|
|
keyWidth, keyboard.getRowHeight(),
|
|
popupKey.mX + (popupKey.mWidth + popupKey.mGap) / 2 - keyWidth / 2,
|
|
view.getMeasuredWidth());
|
|
mParams = params;
|
|
|
|
keyboard.setHeight(params.mNumRows * params.mRowHeight - keyboard.getVerticalGap());
|
|
keyboard.setMinWidth(params.mNumColumns * params.mKeyWidth);
|
|
keyboard.setDefaultCoordX(params.getDefaultKeyCoordX() + params.mKeyWidth / 2);
|
|
}
|
|
|
|
private static int getMaxKeyWidth(KeyboardView view, CharSequence[] popupCharacters,
|
|
int minKeyWidth) {
|
|
Paint paint = null;
|
|
Rect bounds = null;
|
|
int maxWidth = 0;
|
|
for (CharSequence popupSpec : popupCharacters) {
|
|
final CharSequence label = PopupCharactersParser.getLabel(popupSpec.toString());
|
|
// If the label is single letter, minKeyWidth is enough to hold the label.
|
|
if (label != null && label.length() > 1) {
|
|
if (paint == null) {
|
|
paint = new Paint();
|
|
paint.setAntiAlias(true);
|
|
}
|
|
final int labelSize = view.getLabelSizeAndSetPaint(label, 0, paint);
|
|
paint.setTextSize(labelSize);
|
|
if (bounds == null) bounds = new Rect();
|
|
paint.getTextBounds(label.toString(), 0, label.length(), bounds);
|
|
if (maxWidth < bounds.width())
|
|
maxWidth = bounds.width();
|
|
}
|
|
}
|
|
final int horizontalPadding = (int)view.getContext().getResources().getDimension(
|
|
R.dimen.mini_keyboard_key_horizontal_padding);
|
|
return Math.max(minKeyWidth, maxWidth + horizontalPadding);
|
|
}
|
|
|
|
public MiniKeyboard build() {
|
|
final MiniKeyboard keyboard = mKeyboard;
|
|
final List<Key> keys = keyboard.getKeys();
|
|
final MiniKeyboardLayoutParams params = mParams;
|
|
for (int n = 0; n < mPopupCharacters.length; n++) {
|
|
final CharSequence label = mPopupCharacters[n];
|
|
final int row = n / params.mNumColumns;
|
|
final Key key = new Key(mRes, keyboard, label, params.getX(n, row), params.getY(row),
|
|
params.mKeyWidth, params.getRowFlags(row));
|
|
keys.add(key);
|
|
}
|
|
return keyboard;
|
|
}
|
|
}
|