1/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of 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,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.inputmethod.keyboard.internal;
18
19import android.content.res.TypedArray;
20import android.graphics.Canvas;
21import android.graphics.Paint;
22import android.graphics.Paint.Align;
23import android.graphics.Rect;
24import android.graphics.RectF;
25import android.text.TextUtils;
26
27import com.android.inputmethod.keyboard.PointerTracker;
28import com.android.inputmethod.latin.R;
29import com.android.inputmethod.latin.SuggestedWords;
30import com.android.inputmethod.latin.utils.CoordinateUtils;
31
32/**
33 * The class for single gesture preview text. The class for multiple gesture preview text will be
34 * derived from it.
35 *
36 * @attr ref R.styleable#KeyboardView_gestureFloatingPreviewTextSize
37 * @attr ref R.styleable#KeyboardView_gestureFloatingPreviewTextColor
38 * @attr ref R.styleable#KeyboardView_gestureFloatingPreviewTextOffset
39 * @attr ref R.styleable#KeyboardView_gestureFloatingPreviewColor
40 * @attr ref R.styleable#KeyboardView_gestureFloatingPreviewHorizontalPadding
41 * @attr ref R.styleable#KeyboardView_gestureFloatingPreviewVerticalPadding
42 * @attr ref R.styleable#KeyboardView_gestureFloatingPreviewRoundRadius
43 */
44public class GestureFloatingTextDrawingPreview extends AbstractDrawingPreview {
45    protected static final class GesturePreviewTextParams {
46        public final int mGesturePreviewTextOffset;
47        public final int mGesturePreviewTextHeight;
48        public final float mGesturePreviewHorizontalPadding;
49        public final float mGesturePreviewVerticalPadding;
50        public final float mGesturePreviewRoundRadius;
51        public final int mDisplayWidth;
52
53        private final int mGesturePreviewTextSize;
54        private final int mGesturePreviewTextColor;
55        private final int mGesturePreviewColor;
56        private final Paint mPaint = new Paint();
57
58        private static final char[] TEXT_HEIGHT_REFERENCE_CHAR = { 'M' };
59
60        public GesturePreviewTextParams(final TypedArray mainKeyboardViewAttr) {
61            mGesturePreviewTextSize = mainKeyboardViewAttr.getDimensionPixelSize(
62                    R.styleable.MainKeyboardView_gestureFloatingPreviewTextSize, 0);
63            mGesturePreviewTextColor = mainKeyboardViewAttr.getColor(
64                    R.styleable.MainKeyboardView_gestureFloatingPreviewTextColor, 0);
65            mGesturePreviewTextOffset = mainKeyboardViewAttr.getDimensionPixelOffset(
66                    R.styleable.MainKeyboardView_gestureFloatingPreviewTextOffset, 0);
67            mGesturePreviewColor = mainKeyboardViewAttr.getColor(
68                    R.styleable.MainKeyboardView_gestureFloatingPreviewColor, 0);
69            mGesturePreviewHorizontalPadding = mainKeyboardViewAttr.getDimension(
70                    R.styleable.MainKeyboardView_gestureFloatingPreviewHorizontalPadding, 0.0f);
71            mGesturePreviewVerticalPadding = mainKeyboardViewAttr.getDimension(
72                    R.styleable.MainKeyboardView_gestureFloatingPreviewVerticalPadding, 0.0f);
73            mGesturePreviewRoundRadius = mainKeyboardViewAttr.getDimension(
74                    R.styleable.MainKeyboardView_gestureFloatingPreviewRoundRadius, 0.0f);
75            mDisplayWidth = mainKeyboardViewAttr.getResources().getDisplayMetrics().widthPixels;
76
77            final Paint textPaint = getTextPaint();
78            final Rect textRect = new Rect();
79            textPaint.getTextBounds(TEXT_HEIGHT_REFERENCE_CHAR, 0, 1, textRect);
80            mGesturePreviewTextHeight = textRect.height();
81        }
82
83        public Paint getTextPaint() {
84            mPaint.setAntiAlias(true);
85            mPaint.setTextAlign(Align.CENTER);
86            mPaint.setTextSize(mGesturePreviewTextSize);
87            mPaint.setColor(mGesturePreviewTextColor);
88            return mPaint;
89        }
90
91        public Paint getBackgroundPaint() {
92            mPaint.setColor(mGesturePreviewColor);
93            return mPaint;
94        }
95    }
96
97    private final GesturePreviewTextParams mParams;
98    private final RectF mGesturePreviewRectangle = new RectF();
99    private int mPreviewTextX;
100    private int mPreviewTextY;
101    private SuggestedWords mSuggestedWords = SuggestedWords.EMPTY;
102    private final int[] mLastPointerCoords = CoordinateUtils.newInstance();
103
104    public GestureFloatingTextDrawingPreview(final TypedArray mainKeyboardViewAttr) {
105        mParams = new GesturePreviewTextParams(mainKeyboardViewAttr);
106    }
107
108    @Override
109    public void onDeallocateMemory() {
110        // Nothing to do here.
111    }
112
113    public void setSuggetedWords(final SuggestedWords suggestedWords) {
114        if (!isPreviewEnabled()) {
115            return;
116        }
117        mSuggestedWords = suggestedWords;
118        updatePreviewPosition();
119    }
120
121    @Override
122    public void setPreviewPosition(final PointerTracker tracker) {
123        if (!isPreviewEnabled()) {
124            return;
125        }
126        tracker.getLastCoordinates(mLastPointerCoords);
127        updatePreviewPosition();
128    }
129
130    /**
131     * Draws gesture preview text
132     * @param canvas The canvas where preview text is drawn.
133     */
134    @Override
135    public void drawPreview(final Canvas canvas) {
136        if (!isPreviewEnabled() || mSuggestedWords.isEmpty()
137                || TextUtils.isEmpty(mSuggestedWords.getWord(0))) {
138            return;
139        }
140        final float round = mParams.mGesturePreviewRoundRadius;
141        canvas.drawRoundRect(
142                mGesturePreviewRectangle, round, round, mParams.getBackgroundPaint());
143        final String text = mSuggestedWords.getWord(0);
144        canvas.drawText(text, mPreviewTextX, mPreviewTextY, mParams.getTextPaint());
145    }
146
147    /**
148     * Updates gesture preview text position based on mLastPointerCoords.
149     */
150    protected void updatePreviewPosition() {
151        if (mSuggestedWords.isEmpty() || TextUtils.isEmpty(mSuggestedWords.getWord(0))) {
152            invalidateDrawingView();
153            return;
154        }
155        final String text = mSuggestedWords.getWord(0);
156
157        final RectF rectangle = mGesturePreviewRectangle;
158
159        final int textHeight = mParams.mGesturePreviewTextHeight;
160        final float textWidth = mParams.getTextPaint().measureText(text);
161        final float hPad = mParams.mGesturePreviewHorizontalPadding;
162        final float vPad = mParams.mGesturePreviewVerticalPadding;
163        final float rectWidth = textWidth + hPad * 2.0f;
164        final float rectHeight = textHeight + vPad * 2.0f;
165
166        final float rectX = Math.min(
167                Math.max(CoordinateUtils.x(mLastPointerCoords) - rectWidth / 2.0f, 0.0f),
168                mParams.mDisplayWidth - rectWidth);
169        final float rectY = CoordinateUtils.y(mLastPointerCoords)
170                - mParams.mGesturePreviewTextOffset - rectHeight;
171        rectangle.set(rectX, rectY, rectX + rectWidth, rectY + rectHeight);
172
173        mPreviewTextX = (int)(rectX + hPad + textWidth / 2.0f);
174        mPreviewTextY = (int)(rectY + vPad) + textHeight;
175        // TODO: Should narrow the invalidate region.
176        invalidateDrawingView();
177    }
178}
179