2011-08-24 05:44:46 +00:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2011 The Android Open Source Project
|
|
|
|
*
|
2013-01-21 12:52:57 +00:00
|
|
|
* 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
|
2011-08-24 05:44:46 +00:00
|
|
|
*
|
2013-01-21 12:52:57 +00:00
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
2011-08-24 05:44:46 +00:00
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
2013-01-21 12:52:57 +00:00
|
|
|
* 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.
|
2011-08-24 05:44:46 +00:00
|
|
|
*/
|
|
|
|
|
2011-12-16 02:26:14 +00:00
|
|
|
package com.android.inputmethod.latin.suggestions;
|
2011-08-24 05:44:46 +00:00
|
|
|
|
2013-04-11 03:08:36 +00:00
|
|
|
import android.content.Context;
|
2011-09-08 09:57:44 +00:00
|
|
|
import android.content.res.Resources;
|
2011-08-24 05:44:46 +00:00
|
|
|
import android.graphics.Paint;
|
2011-09-08 09:57:44 +00:00
|
|
|
import android.graphics.drawable.Drawable;
|
2011-08-24 05:44:46 +00:00
|
|
|
|
|
|
|
import com.android.inputmethod.keyboard.Key;
|
|
|
|
import com.android.inputmethod.keyboard.Keyboard;
|
2013-05-01 08:02:27 +00:00
|
|
|
import com.android.inputmethod.keyboard.KeyboardActionListener;
|
2013-04-11 03:08:36 +00:00
|
|
|
import com.android.inputmethod.keyboard.TypefaceUtils;
|
2012-08-30 05:22:40 +00:00
|
|
|
import com.android.inputmethod.keyboard.internal.KeyboardBuilder;
|
2012-02-02 15:18:47 +00:00
|
|
|
import com.android.inputmethod.keyboard.internal.KeyboardIconsSet;
|
2012-08-30 05:22:40 +00:00
|
|
|
import com.android.inputmethod.keyboard.internal.KeyboardParams;
|
2011-12-16 02:26:14 +00:00
|
|
|
import com.android.inputmethod.latin.R;
|
|
|
|
import com.android.inputmethod.latin.SuggestedWords;
|
2013-05-01 08:02:27 +00:00
|
|
|
import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
|
2011-08-24 05:44:46 +00:00
|
|
|
|
2012-09-27 09:16:16 +00:00
|
|
|
public final class MoreSuggestions extends Keyboard {
|
2011-08-24 05:44:46 +00:00
|
|
|
public static final int SUGGESTION_CODE_BASE = 1024;
|
|
|
|
|
2013-05-01 08:02:27 +00:00
|
|
|
public final SuggestedWords mSuggestedWords;
|
|
|
|
|
|
|
|
public static abstract class MoreSuggestionsListener extends KeyboardActionListener.Adapter {
|
|
|
|
public abstract void onSuggestionSelected(final int index, final SuggestedWordInfo info);
|
|
|
|
}
|
|
|
|
|
|
|
|
MoreSuggestions(final MoreSuggestionsParam params, final SuggestedWords suggestedWords) {
|
2011-08-24 05:44:46 +00:00
|
|
|
super(params);
|
2013-05-01 08:02:27 +00:00
|
|
|
mSuggestedWords = suggestedWords;
|
2011-08-24 05:44:46 +00:00
|
|
|
}
|
|
|
|
|
2012-09-27 09:16:16 +00:00
|
|
|
private static final class MoreSuggestionsParam extends KeyboardParams {
|
2012-08-30 05:22:40 +00:00
|
|
|
private final int[] mWidths = new int[SuggestionStripView.MAX_SUGGESTIONS];
|
|
|
|
private final int[] mRowNumbers = new int[SuggestionStripView.MAX_SUGGESTIONS];
|
|
|
|
private final int[] mColumnOrders = new int[SuggestionStripView.MAX_SUGGESTIONS];
|
|
|
|
private final int[] mNumColumnsInRow = new int[SuggestionStripView.MAX_SUGGESTIONS];
|
|
|
|
private static final int MAX_COLUMNS_IN_ROW = 3;
|
|
|
|
private int mNumRows;
|
|
|
|
public Drawable mDivider;
|
|
|
|
public int mDividerWidth;
|
|
|
|
|
|
|
|
public MoreSuggestionsParam() {
|
|
|
|
super();
|
|
|
|
}
|
2011-08-24 05:44:46 +00:00
|
|
|
|
2013-05-30 14:47:54 +00:00
|
|
|
public int layout(final SuggestedWords suggestedWords, final int fromIndex,
|
2013-05-01 08:02:27 +00:00
|
|
|
final int maxWidth, final int minWidth, final int maxRow, final Paint paint,
|
|
|
|
final Resources res) {
|
2012-08-30 05:22:40 +00:00
|
|
|
clearKeys();
|
|
|
|
mDivider = res.getDrawable(R.drawable.more_suggestions_divider);
|
|
|
|
mDividerWidth = mDivider.getIntrinsicWidth();
|
2013-04-11 03:08:36 +00:00
|
|
|
final float padding = res.getDimension(R.dimen.more_suggestions_key_horizontal_padding);
|
2012-08-30 05:22:40 +00:00
|
|
|
|
|
|
|
int row = 0;
|
2013-05-30 14:47:54 +00:00
|
|
|
int index = fromIndex;
|
|
|
|
int rowStartIndex = fromIndex;
|
2013-05-01 08:02:27 +00:00
|
|
|
final int size = Math.min(suggestedWords.size(), SuggestionStripView.MAX_SUGGESTIONS);
|
2013-05-30 14:47:54 +00:00
|
|
|
while (index < size) {
|
|
|
|
final String word = suggestedWords.getWord(index);
|
2012-08-30 05:22:40 +00:00
|
|
|
// TODO: Should take care of text x-scaling.
|
2013-05-30 14:47:54 +00:00
|
|
|
mWidths[index] = (int)(TypefaceUtils.getLabelWidth(word, paint) + padding);
|
|
|
|
final int numColumn = index - rowStartIndex + 1;
|
2012-08-30 05:22:40 +00:00
|
|
|
final int columnWidth =
|
|
|
|
(maxWidth - mDividerWidth * (numColumn - 1)) / numColumn;
|
|
|
|
if (numColumn > MAX_COLUMNS_IN_ROW
|
2013-05-30 14:47:54 +00:00
|
|
|
|| !fitInWidth(rowStartIndex, index + 1, columnWidth)) {
|
2012-08-30 05:22:40 +00:00
|
|
|
if ((row + 1) >= maxRow) {
|
|
|
|
break;
|
2011-08-24 05:44:46 +00:00
|
|
|
}
|
2013-05-30 14:47:54 +00:00
|
|
|
mNumColumnsInRow[row] = index - rowStartIndex;
|
|
|
|
rowStartIndex = index;
|
2012-08-30 05:22:40 +00:00
|
|
|
row++;
|
2011-08-24 05:44:46 +00:00
|
|
|
}
|
2013-05-30 14:47:54 +00:00
|
|
|
mColumnOrders[index] = index - rowStartIndex;
|
|
|
|
mRowNumbers[index] = row;
|
|
|
|
index++;
|
2011-08-24 05:44:46 +00:00
|
|
|
}
|
2013-05-30 14:47:54 +00:00
|
|
|
mNumColumnsInRow[row] = index - rowStartIndex;
|
2012-08-30 05:22:40 +00:00
|
|
|
mNumRows = row + 1;
|
|
|
|
mBaseWidth = mOccupiedWidth = Math.max(
|
2013-05-30 14:47:54 +00:00
|
|
|
minWidth, calcurateMaxRowWidth(fromIndex, index));
|
2012-08-30 05:22:40 +00:00
|
|
|
mBaseHeight = mOccupiedHeight = mNumRows * mDefaultRowHeight + mVerticalGap;
|
2013-05-30 14:47:54 +00:00
|
|
|
return index - fromIndex;
|
2012-08-30 05:22:40 +00:00
|
|
|
}
|
2011-08-24 05:44:46 +00:00
|
|
|
|
2013-05-30 14:47:54 +00:00
|
|
|
private boolean fitInWidth(final int startIndex, final int endIndex, final int width) {
|
|
|
|
for (int index = startIndex; index < endIndex; index++) {
|
|
|
|
if (mWidths[index] > width)
|
2012-08-30 05:22:40 +00:00
|
|
|
return false;
|
2011-08-24 05:44:46 +00:00
|
|
|
}
|
2012-08-30 05:22:40 +00:00
|
|
|
return true;
|
|
|
|
}
|
2011-08-24 05:44:46 +00:00
|
|
|
|
2013-05-30 14:47:54 +00:00
|
|
|
private int calcurateMaxRowWidth(final int startIndex, final int endIndex) {
|
2012-08-30 05:22:40 +00:00
|
|
|
int maxRowWidth = 0;
|
2013-05-30 14:47:54 +00:00
|
|
|
int index = startIndex;
|
2012-08-30 05:22:40 +00:00
|
|
|
for (int row = 0; row < mNumRows; row++) {
|
|
|
|
final int numColumnInRow = mNumColumnsInRow[row];
|
|
|
|
int maxKeyWidth = 0;
|
2013-05-30 14:47:54 +00:00
|
|
|
while (index < endIndex && mRowNumbers[index] == row) {
|
|
|
|
maxKeyWidth = Math.max(maxKeyWidth, mWidths[index]);
|
|
|
|
index++;
|
2011-08-24 05:44:46 +00:00
|
|
|
}
|
2012-08-30 05:22:40 +00:00
|
|
|
maxRowWidth = Math.max(maxRowWidth,
|
|
|
|
maxKeyWidth * numColumnInRow + mDividerWidth * (numColumnInRow - 1));
|
2011-08-24 05:44:46 +00:00
|
|
|
}
|
2012-08-30 05:22:40 +00:00
|
|
|
return maxRowWidth;
|
|
|
|
}
|
2011-08-24 05:44:46 +00:00
|
|
|
|
2012-08-30 05:22:40 +00:00
|
|
|
private static final int[][] COLUMN_ORDER_TO_NUMBER = {
|
|
|
|
{ 0, },
|
|
|
|
{ 1, 0, },
|
|
|
|
{ 2, 0, 1},
|
|
|
|
};
|
2011-09-08 09:57:44 +00:00
|
|
|
|
2013-05-30 14:47:54 +00:00
|
|
|
public int getNumColumnInRow(final int index) {
|
|
|
|
return mNumColumnsInRow[mRowNumbers[index]];
|
2012-08-30 05:22:40 +00:00
|
|
|
}
|
2011-08-24 05:44:46 +00:00
|
|
|
|
2013-05-30 14:47:54 +00:00
|
|
|
public int getColumnNumber(final int index) {
|
|
|
|
final int columnOrder = mColumnOrders[index];
|
|
|
|
final int numColumn = getNumColumnInRow(index);
|
2012-08-30 05:22:40 +00:00
|
|
|
return COLUMN_ORDER_TO_NUMBER[numColumn - 1][columnOrder];
|
|
|
|
}
|
2011-08-24 05:44:46 +00:00
|
|
|
|
2013-05-30 14:47:54 +00:00
|
|
|
public int getX(final int index) {
|
|
|
|
final int columnNumber = getColumnNumber(index);
|
|
|
|
return columnNumber * (getWidth(index) + mDividerWidth);
|
2012-08-30 05:22:40 +00:00
|
|
|
}
|
2011-08-24 05:44:46 +00:00
|
|
|
|
2013-05-30 14:47:54 +00:00
|
|
|
public int getY(final int index) {
|
|
|
|
final int row = mRowNumbers[index];
|
2012-08-30 05:22:40 +00:00
|
|
|
return (mNumRows -1 - row) * mDefaultRowHeight + mTopPadding;
|
|
|
|
}
|
2011-08-24 05:44:46 +00:00
|
|
|
|
2013-05-30 14:47:54 +00:00
|
|
|
public int getWidth(final int index) {
|
|
|
|
final int numColumnInRow = getNumColumnInRow(index);
|
2012-08-30 05:22:40 +00:00
|
|
|
return (mOccupiedWidth - mDividerWidth * (numColumnInRow - 1)) / numColumnInRow;
|
|
|
|
}
|
2011-08-24 05:44:46 +00:00
|
|
|
|
2013-05-30 14:47:54 +00:00
|
|
|
public void markAsEdgeKey(final Key key, final int index) {
|
|
|
|
final int row = mRowNumbers[index];
|
2012-08-30 05:22:40 +00:00
|
|
|
if (row == 0)
|
|
|
|
key.markAsBottomEdge(this);
|
|
|
|
if (row == mNumRows - 1)
|
|
|
|
key.markAsTopEdge(this);
|
|
|
|
|
|
|
|
final int numColumnInRow = mNumColumnsInRow[row];
|
2013-05-30 14:47:54 +00:00
|
|
|
final int column = getColumnNumber(index);
|
2012-08-30 05:22:40 +00:00
|
|
|
if (column == 0)
|
|
|
|
key.markAsLeftEdge(this);
|
|
|
|
if (column == numColumnInRow - 1)
|
|
|
|
key.markAsRightEdge(this);
|
2011-08-24 05:44:46 +00:00
|
|
|
}
|
2012-08-30 05:22:40 +00:00
|
|
|
}
|
2011-08-24 05:44:46 +00:00
|
|
|
|
2012-09-27 09:16:16 +00:00
|
|
|
public static final class Builder extends KeyboardBuilder<MoreSuggestionsParam> {
|
2012-08-30 05:22:40 +00:00
|
|
|
private final MoreSuggestionsView mPaneView;
|
2013-05-01 08:02:27 +00:00
|
|
|
private SuggestedWords mSuggestedWords;
|
2013-05-30 14:47:54 +00:00
|
|
|
private int mFromIndex;
|
|
|
|
private int mToIndex;
|
2012-08-30 05:22:40 +00:00
|
|
|
|
2013-04-11 03:08:36 +00:00
|
|
|
public Builder(final Context context, final MoreSuggestionsView paneView) {
|
|
|
|
super(context, new MoreSuggestionsParam());
|
2011-08-24 05:44:46 +00:00
|
|
|
mPaneView = paneView;
|
|
|
|
}
|
|
|
|
|
2013-05-30 14:47:54 +00:00
|
|
|
public Builder layout(final SuggestedWords suggestedWords, final int fromIndex,
|
2012-10-01 05:26:38 +00:00
|
|
|
final int maxWidth, final int minWidth, final int maxRow,
|
|
|
|
final Keyboard parentKeyboard) {
|
2011-08-24 05:44:46 +00:00
|
|
|
final int xmlId = R.xml.kbd_suggestions_pane_template;
|
2012-10-01 05:26:38 +00:00
|
|
|
load(xmlId, parentKeyboard.mId);
|
|
|
|
mParams.mVerticalGap = mParams.mTopPadding = parentKeyboard.mVerticalGap / 2;
|
2011-08-24 05:44:46 +00:00
|
|
|
|
2012-10-16 20:26:45 +00:00
|
|
|
mPaneView.updateKeyboardGeometry(mParams.mDefaultRowHeight);
|
2013-05-30 14:47:54 +00:00
|
|
|
final int count = mParams.layout(suggestedWords, fromIndex, maxWidth, minWidth, maxRow,
|
2013-04-11 03:08:36 +00:00
|
|
|
mPaneView.newLabelPaint(null /* key */), mResources);
|
2013-05-30 14:47:54 +00:00
|
|
|
mFromIndex = fromIndex;
|
|
|
|
mToIndex = fromIndex + count;
|
2013-05-01 08:02:27 +00:00
|
|
|
mSuggestedWords = suggestedWords;
|
2011-08-24 05:44:46 +00:00
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public MoreSuggestions build() {
|
|
|
|
final MoreSuggestionsParam params = mParams;
|
2013-05-30 14:47:54 +00:00
|
|
|
for (int index = mFromIndex; index < mToIndex; index++) {
|
|
|
|
final int x = params.getX(index);
|
|
|
|
final int y = params.getY(index);
|
|
|
|
final int width = params.getWidth(index);
|
|
|
|
final String word = mSuggestedWords.getWord(index);
|
2013-07-05 09:23:22 +00:00
|
|
|
final String info = mSuggestedWords.getDebugString(index);
|
2013-05-30 14:47:54 +00:00
|
|
|
final int indexInMoreSuggestions = index + SUGGESTION_CODE_BASE;
|
2011-08-24 05:44:46 +00:00
|
|
|
final Key key = new Key(
|
2013-05-30 14:47:54 +00:00
|
|
|
params, word, info, KeyboardIconsSet.ICON_UNDEFINED, indexInMoreSuggestions,
|
|
|
|
null, x, y, width, params.mDefaultRowHeight, 0);
|
|
|
|
params.markAsEdgeKey(key, index);
|
2011-08-24 05:44:46 +00:00
|
|
|
params.onAddKey(key);
|
2013-05-30 14:47:54 +00:00
|
|
|
final int columnNumber = params.getColumnNumber(index);
|
|
|
|
final int numColumnInRow = params.getNumColumnInRow(index);
|
2011-09-08 09:57:44 +00:00
|
|
|
if (columnNumber < numColumnInRow - 1) {
|
2012-02-02 15:18:47 +00:00
|
|
|
final Divider divider = new Divider(params, params.mDivider, x + width, y,
|
2011-09-08 09:57:44 +00:00
|
|
|
params.mDividerWidth, params.mDefaultRowHeight);
|
2012-02-02 15:18:47 +00:00
|
|
|
params.onAddKey(divider);
|
2011-09-08 09:57:44 +00:00
|
|
|
}
|
2011-08-24 05:44:46 +00:00
|
|
|
}
|
2013-05-01 08:02:27 +00:00
|
|
|
return new MoreSuggestions(params, mSuggestedWords);
|
2011-08-24 05:44:46 +00:00
|
|
|
}
|
|
|
|
}
|
2012-08-30 05:22:40 +00:00
|
|
|
|
2012-09-27 09:16:16 +00:00
|
|
|
private static final class Divider extends Key.Spacer {
|
2012-08-30 05:22:40 +00:00
|
|
|
private final Drawable mIcon;
|
|
|
|
|
|
|
|
public Divider(final KeyboardParams params, final Drawable icon, final int x,
|
|
|
|
final int y, final int width, final int height) {
|
|
|
|
super(params, x, y, width, height);
|
|
|
|
mIcon = icon;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public Drawable getIcon(final KeyboardIconsSet iconSet, final int alpha) {
|
|
|
|
// KeyboardIconsSet and alpha are unused. Use the icon that has been passed to the
|
|
|
|
// constructor.
|
|
|
|
// TODO: Drawable itself should have an alpha value.
|
|
|
|
mIcon.setAlpha(128);
|
|
|
|
return mIcon;
|
|
|
|
}
|
|
|
|
}
|
2011-08-24 05:44:46 +00:00
|
|
|
}
|