Home | History | Annotate | Download | only in latin
      1 /*
      2  * Copyright (C) 2011 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
      5  * use this file except in compliance with the License. You may obtain a copy of
      6  * the License at
      7  *
      8  * http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
     12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
     13  * License for the specific language governing permissions and limitations under
     14  * the License.
     15  */
     16 
     17 package com.android.inputmethod.latin;
     18 
     19 import android.content.res.Resources;
     20 import android.graphics.Paint;
     21 import android.graphics.drawable.Drawable;
     22 import android.text.TextUtils;
     23 
     24 import com.android.inputmethod.keyboard.Key;
     25 import com.android.inputmethod.keyboard.Keyboard;
     26 import com.android.inputmethod.keyboard.KeyboardSwitcher;
     27 import com.android.inputmethod.keyboard.KeyboardView;
     28 import com.android.inputmethod.keyboard.internal.KeyboardBuilder;
     29 import com.android.inputmethod.keyboard.internal.KeyboardParams;
     30 import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
     31 
     32 public class MoreSuggestions extends Keyboard {
     33     private static final boolean DBG = LatinImeLogger.sDBG;
     34 
     35     public static final int SUGGESTION_CODE_BASE = 1024;
     36 
     37     private MoreSuggestions(Builder.MoreSuggestionsParam params) {
     38         super(params);
     39     }
     40 
     41     public static class Builder extends KeyboardBuilder<Builder.MoreSuggestionsParam> {
     42         private final MoreSuggestionsView mPaneView;
     43         private SuggestedWords mSuggestions;
     44         private int mFromPos;
     45         private int mToPos;
     46 
     47         public static class MoreSuggestionsParam extends KeyboardParams {
     48             private final int[] mWidths = new int[SuggestionsView.MAX_SUGGESTIONS];
     49             private final int[] mRowNumbers = new int[SuggestionsView.MAX_SUGGESTIONS];
     50             private final int[] mColumnOrders = new int[SuggestionsView.MAX_SUGGESTIONS];
     51             private final int[] mNumColumnsInRow = new int[SuggestionsView.MAX_SUGGESTIONS];
     52             private static final int MAX_COLUMNS_IN_ROW = 3;
     53             private int mNumRows;
     54             public Drawable mDivider;
     55             public int mDividerWidth;
     56 
     57             public int layout(SuggestedWords suggestions, int fromPos, int maxWidth, int minWidth,
     58                     int maxRow, KeyboardView view) {
     59                 clearKeys();
     60                 final Paint paint = new Paint();
     61                 paint.setAntiAlias(true);
     62                 final Resources res = view.getContext().getResources();
     63                 mDivider = res.getDrawable(R.drawable.more_suggestions_divider);
     64                 // TODO: Drawable itself should has an alpha value.
     65                 mDivider.setAlpha(128);
     66                 mDividerWidth = mDivider.getIntrinsicWidth();
     67                 final int padding = (int) res.getDimension(
     68                         R.dimen.more_suggestions_key_horizontal_padding);
     69 
     70                 int row = 0;
     71                 int pos = fromPos, rowStartPos = fromPos;
     72                 final int size = Math.min(suggestions.size(), SuggestionsView.MAX_SUGGESTIONS);
     73                 while (pos < size) {
     74                     final CharSequence word = suggestions.getWord(pos);
     75                     // TODO: Should take care of text x-scaling.
     76                     mWidths[pos] = (int)view.getDefaultLabelWidth(word, paint) + padding;
     77                     final int numColumn = pos - rowStartPos + 1;
     78                     final int columnWidth =
     79                             (maxWidth - mDividerWidth * (numColumn - 1)) / numColumn;
     80                     if (numColumn > MAX_COLUMNS_IN_ROW
     81                             || !fitInWidth(rowStartPos, pos + 1, columnWidth)) {
     82                         if ((row + 1) >= maxRow) {
     83                             break;
     84                         }
     85                         mNumColumnsInRow[row] = pos - rowStartPos;
     86                         rowStartPos = pos;
     87                         row++;
     88                     }
     89                     mColumnOrders[pos] = pos - rowStartPos;
     90                     mRowNumbers[pos] = row;
     91                     pos++;
     92                 }
     93                 mNumColumnsInRow[row] = pos - rowStartPos;
     94                 mNumRows = row + 1;
     95                 mBaseWidth = mOccupiedWidth = Math.max(
     96                         minWidth, calcurateMaxRowWidth(fromPos, pos));
     97                 mBaseHeight = mOccupiedHeight = mNumRows * mDefaultRowHeight + mVerticalGap;
     98                 return pos - fromPos;
     99             }
    100 
    101             private boolean fitInWidth(int startPos, int endPos, int width) {
    102                 for (int pos = startPos; pos < endPos; pos++) {
    103                     if (mWidths[pos] > width)
    104                         return false;
    105                 }
    106                 return true;
    107             }
    108 
    109             private int calcurateMaxRowWidth(int startPos, int endPos) {
    110                 int maxRowWidth = 0;
    111                 int pos = startPos;
    112                 for (int row = 0; row < mNumRows; row++) {
    113                     final int numColumnInRow = mNumColumnsInRow[row];
    114                     int maxKeyWidth = 0;
    115                     while (pos < endPos && mRowNumbers[pos] == row) {
    116                         maxKeyWidth = Math.max(maxKeyWidth, mWidths[pos]);
    117                         pos++;
    118                     }
    119                     maxRowWidth = Math.max(maxRowWidth,
    120                             maxKeyWidth * numColumnInRow + mDividerWidth * (numColumnInRow - 1));
    121                 }
    122                 return maxRowWidth;
    123             }
    124 
    125             private static final int[][] COLUMN_ORDER_TO_NUMBER = {
    126                 { 0, },
    127                 { 1, 0, },
    128                 { 2, 0, 1},
    129             };
    130 
    131             public int getNumColumnInRow(int pos) {
    132                 return mNumColumnsInRow[mRowNumbers[pos]];
    133             }
    134 
    135             public int getColumnNumber(int pos) {
    136                 final int columnOrder = mColumnOrders[pos];
    137                 final int numColumn = getNumColumnInRow(pos);
    138                 return COLUMN_ORDER_TO_NUMBER[numColumn - 1][columnOrder];
    139             }
    140 
    141             public int getX(int pos) {
    142                 final int columnNumber = getColumnNumber(pos);
    143                 return columnNumber * (getWidth(pos) + mDividerWidth);
    144             }
    145 
    146             public int getY(int pos) {
    147                 final int row = mRowNumbers[pos];
    148                 return (mNumRows -1 - row) * mDefaultRowHeight + mTopPadding;
    149             }
    150 
    151             public int getWidth(int pos) {
    152                 final int numColumnInRow = getNumColumnInRow(pos);
    153                 return (mOccupiedWidth - mDividerWidth * (numColumnInRow - 1)) / numColumnInRow;
    154             }
    155 
    156             public void markAsEdgeKey(Key key, int pos) {
    157                 final int row = mRowNumbers[pos];
    158                 if (row == 0)
    159                     key.markAsBottomEdge(this);
    160                 if (row == mNumRows - 1)
    161                     key.markAsTopEdge(this);
    162 
    163                 final int numColumnInRow = mNumColumnsInRow[row];
    164                 final int column = getColumnNumber(pos);
    165                 if (column == 0)
    166                     key.markAsLeftEdge(this);
    167                 if (column == numColumnInRow - 1)
    168                     key.markAsRightEdge(this);
    169             }
    170         }
    171 
    172         public Builder(MoreSuggestionsView paneView) {
    173             super(paneView.getContext(), new MoreSuggestionsParam());
    174             mPaneView = paneView;
    175         }
    176 
    177         public Builder layout(SuggestedWords suggestions, int fromPos, int maxWidth,
    178                 int minWidth, int maxRow) {
    179             final Keyboard keyboard = KeyboardSwitcher.getInstance().getLatinKeyboard();
    180             final int xmlId = R.xml.kbd_suggestions_pane_template;
    181             load(keyboard.mId.cloneWithNewXml(mResources.getResourceEntryName(xmlId), xmlId));
    182             mParams.mVerticalGap = mParams.mTopPadding = keyboard.mVerticalGap / 2;
    183 
    184             final int count = mParams.layout(suggestions, fromPos, maxWidth, minWidth, maxRow,
    185                     mPaneView);
    186             mFromPos = fromPos;
    187             mToPos = fromPos + count;
    188             mSuggestions = suggestions;
    189             return this;
    190         }
    191 
    192         private static String getDebugInfo(SuggestedWords suggestions, int pos) {
    193             if (!DBG) return null;
    194             final SuggestedWordInfo wordInfo = suggestions.getInfo(pos);
    195             if (wordInfo == null) return null;
    196             final String info = wordInfo.getDebugString();
    197             if (TextUtils.isEmpty(info)) return null;
    198             return info;
    199         }
    200 
    201         @Override
    202         public MoreSuggestions build() {
    203             final MoreSuggestionsParam params = mParams;
    204             for (int pos = mFromPos; pos < mToPos; pos++) {
    205                 final int x = params.getX(pos);
    206                 final int y = params.getY(pos);
    207                 final int width = params.getWidth(pos);
    208                 final String word = mSuggestions.getWord(pos).toString();
    209                 final String info = getDebugInfo(mSuggestions, pos);
    210                 final int index = pos + SUGGESTION_CODE_BASE;
    211                 final Key key = new Key(
    212                         params, word, info, null, index, null, x, y, width,
    213                         params.mDefaultRowHeight);
    214                 params.markAsEdgeKey(key, pos);
    215                 params.onAddKey(key);
    216                 final int columnNumber = params.getColumnNumber(pos);
    217                 final int numColumnInRow = params.getNumColumnInRow(pos);
    218                 if (columnNumber < numColumnInRow - 1) {
    219                     final Key.Spacer spacer = new Key.Spacer(params, params.mDivider, x + width, y,
    220                             params.mDividerWidth, params.mDefaultRowHeight);
    221                     params.onAddKey(spacer);
    222                 }
    223             }
    224             return new MoreSuggestions(params);
    225         }
    226     }
    227 }
    228