summaryrefslogtreecommitdiff
path: root/src/com/android/inputmethod/pinyin/ComposingView.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/inputmethod/pinyin/ComposingView.java')
-rw-r--r--src/com/android/inputmethod/pinyin/ComposingView.java280
1 files changed, 280 insertions, 0 deletions
diff --git a/src/com/android/inputmethod/pinyin/ComposingView.java b/src/com/android/inputmethod/pinyin/ComposingView.java
new file mode 100644
index 0000000..f70af45
--- /dev/null
+++ b/src/com/android/inputmethod/pinyin/ComposingView.java
@@ -0,0 +1,280 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * 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.pinyin;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Paint.FontMetricsInt;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.ViewGroup.LayoutParams;
+
+/**
+ * View used to show composing string (The Pinyin string for the unselected
+ * syllables and the Chinese string for the selected syllables.)
+ */
+public class ComposingView extends View {
+ /**
+ * <p>
+ * There are three statuses for the composing view.
+ * </p>
+ *
+ * <p>
+ * {@link #SHOW_PINYIN} is used to show the current Pinyin string without
+ * highlighted effect. When user inputs Pinyin characters one by one, the
+ * Pinyin string will be shown in this mode.
+ * </p>
+ * <p>
+ * {@link #SHOW_STRING_LOWERCASE} is used to show the Pinyin string in
+ * lowercase with highlighted effect. When user presses UP key and there is
+ * no fixed Chinese characters, composing view will switch from
+ * {@link #SHOW_PINYIN} to this mode, and in this mode, user can press
+ * confirm key to input the lower-case string, so that user can input
+ * English letter in Chinese mode.
+ * </p>
+ * <p>
+ * {@link #EDIT_PINYIN} is used to edit the Pinyin string (shown with
+ * highlighted effect). When current status is {@link #SHOW_PINYIN} and user
+ * presses UP key, if there are fixed Characters, the input method will
+ * switch to {@link #EDIT_PINYIN} thus user can modify some characters in
+ * the middle of the Pinyin string. If the current status is
+ * {@link #SHOW_STRING_LOWERCASE} and user presses LEFT and RIGHT key, it
+ * will also switch to {@link #EDIT_PINYIN}.
+ * </p>
+ * <p>
+ * Whenever user presses down key, the status switches to
+ * {@link #SHOW_PINYIN}.
+ * </p>
+ * <p>
+ * When composing view's status is {@link #SHOW_PINYIN}, the IME's status is
+ * {@link PinyinIME.ImeState#STATE_INPUT}, otherwise, the IME's status
+ * should be {@link PinyinIME.ImeState#STATE_COMPOSING}.
+ * </p>
+ */
+ public enum ComposingStatus {
+ SHOW_PINYIN, SHOW_STRING_LOWERCASE, EDIT_PINYIN,
+ }
+
+ private static final int LEFT_RIGHT_MARGIN = 5;
+
+ /**
+ * Used to draw composing string. When drawing the active and idle part of
+ * the spelling(Pinyin) string, the color may be changed.
+ */
+ private Paint mPaint;
+
+ /**
+ * Drawable used to draw highlight effect.
+ */
+ private Drawable mHlDrawable;
+
+ /**
+ * Drawable used to draw cursor for editing mode.
+ */
+ private Drawable mCursor;
+
+ /**
+ * Used to estimate dimensions to show the string .
+ */
+ private FontMetricsInt mFmi;
+
+ private int mStrColor;
+ private int mStrColorHl;
+ private int mStrColorIdle;
+
+ private int mFontSize;
+
+ private ComposingStatus mComposingStatus;
+
+ PinyinIME.DecodingInfo mDecInfo;
+
+ public ComposingView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+
+ Resources r = context.getResources();
+ mHlDrawable = r.getDrawable(R.drawable.composing_hl_bg);
+ mCursor = r.getDrawable(R.drawable.composing_area_cursor);
+
+ mStrColor = r.getColor(R.color.composing_color);
+ mStrColorHl = r.getColor(R.color.composing_color_hl);
+ mStrColorIdle = r.getColor(R.color.composing_color_idle);
+
+ mFontSize = r.getDimensionPixelSize(R.dimen.composing_height);
+
+ mPaint = new Paint();
+ mPaint.setColor(mStrColor);
+ mPaint.setAntiAlias(true);
+ mPaint.setTextSize(mFontSize);
+
+ mFmi = mPaint.getFontMetricsInt();
+ }
+
+ public void reset() {
+ mComposingStatus = ComposingStatus.SHOW_PINYIN;
+ }
+
+ /**
+ * Set the composing string to show. If the IME status is
+ * {@link PinyinIME.ImeState#STATE_INPUT}, the composing view's status will
+ * be set to {@link ComposingStatus#SHOW_PINYIN}, otherwise the composing
+ * view will set its status to {@link ComposingStatus#SHOW_STRING_LOWERCASE}
+ * or {@link ComposingStatus#EDIT_PINYIN} automatically.
+ */
+ public void setDecodingInfo(PinyinIME.DecodingInfo decInfo,
+ PinyinIME.ImeState imeStatus) {
+ mDecInfo = decInfo;
+
+ if (PinyinIME.ImeState.STATE_INPUT == imeStatus) {
+ mComposingStatus = ComposingStatus.SHOW_PINYIN;
+ mDecInfo.moveCursorToEdge(false);
+ } else {
+ if (decInfo.getFixedLen() != 0
+ || ComposingStatus.EDIT_PINYIN == mComposingStatus) {
+ mComposingStatus = ComposingStatus.EDIT_PINYIN;
+ } else {
+ mComposingStatus = ComposingStatus.SHOW_STRING_LOWERCASE;
+ }
+ mDecInfo.moveCursor(0);
+ }
+
+ measure(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
+ requestLayout();
+ invalidate();
+ }
+
+ public boolean moveCursor(int keyCode) {
+ if (keyCode != KeyEvent.KEYCODE_DPAD_LEFT
+ && keyCode != KeyEvent.KEYCODE_DPAD_RIGHT) return false;
+
+ if (ComposingStatus.EDIT_PINYIN == mComposingStatus) {
+ int offset = 0;
+ if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT)
+ offset = -1;
+ else if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) offset = 1;
+ mDecInfo.moveCursor(offset);
+ } else if (ComposingStatus.SHOW_STRING_LOWERCASE == mComposingStatus) {
+ if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT
+ || keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) {
+ mComposingStatus = ComposingStatus.EDIT_PINYIN;
+
+ measure(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
+ requestLayout();
+ }
+
+ }
+ invalidate();
+ return true;
+ }
+
+ public ComposingStatus getComposingStatus() {
+ return mComposingStatus;
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ float width;
+ int height;
+ height = mFmi.bottom - mFmi.top + mPaddingTop + mPaddingBottom;
+
+ if (null == mDecInfo) {
+ width = 0;
+ } else {
+ width = mPaddingLeft + mPaddingRight + LEFT_RIGHT_MARGIN * 2;
+
+ String str;
+ if (ComposingStatus.SHOW_STRING_LOWERCASE == mComposingStatus) {
+ str = mDecInfo.getOrigianlSplStr().toString();
+ } else {
+ str = mDecInfo.getComposingStrForDisplay();
+ }
+ width += mPaint.measureText(str, 0, str.length());
+ }
+ setMeasuredDimension((int) (width + 0.5f), height);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ if (ComposingStatus.EDIT_PINYIN == mComposingStatus
+ || ComposingStatus.SHOW_PINYIN == mComposingStatus) {
+ drawForPinyin(canvas);
+ return;
+ }
+
+ float x, y;
+ x = mPaddingLeft + LEFT_RIGHT_MARGIN;
+ y = -mFmi.top + mPaddingTop;
+
+ mPaint.setColor(mStrColorHl);
+ mHlDrawable.setBounds(mPaddingLeft, mPaddingTop, getWidth()
+ - mPaddingRight, getHeight() - mPaddingBottom);
+ mHlDrawable.draw(canvas);
+
+ String splStr = mDecInfo.getOrigianlSplStr().toString();
+ canvas.drawText(splStr, 0, splStr.length(), x, y, mPaint);
+ }
+
+ private void drawCursor(Canvas canvas, float x) {
+ mCursor.setBounds((int) x, mPaddingTop, (int) x
+ + mCursor.getIntrinsicWidth(), getHeight() - mPaddingBottom);
+ mCursor.draw(canvas);
+ }
+
+ private void drawForPinyin(Canvas canvas) {
+ float x, y;
+ x = mPaddingLeft + LEFT_RIGHT_MARGIN;
+ y = -mFmi.top + mPaddingTop;
+
+ mPaint.setColor(mStrColor);
+
+ int cursorPos = mDecInfo.getCursorPosInCmpsDisplay();
+ int cmpsPos = cursorPos;
+ String cmpsStr = mDecInfo.getComposingStrForDisplay();
+ int activeCmpsLen = mDecInfo.getActiveCmpsDisplayLen();
+ if (cursorPos > activeCmpsLen) cmpsPos = activeCmpsLen;
+ canvas.drawText(cmpsStr, 0, cmpsPos, x, y, mPaint);
+ x += mPaint.measureText(cmpsStr, 0, cmpsPos);
+ if (cursorPos <= activeCmpsLen) {
+ if (ComposingStatus.EDIT_PINYIN == mComposingStatus) {
+ drawCursor(canvas, x);
+ }
+ canvas.drawText(cmpsStr, cmpsPos, activeCmpsLen, x, y, mPaint);
+ }
+
+ x += mPaint.measureText(cmpsStr, cmpsPos, activeCmpsLen);
+
+ if (cmpsStr.length() > activeCmpsLen) {
+ mPaint.setColor(mStrColorIdle);
+ int oriPos = activeCmpsLen;
+ if (cursorPos > activeCmpsLen) {
+ if (cursorPos > cmpsStr.length()) cursorPos = cmpsStr.length();
+ canvas.drawText(cmpsStr, oriPos, cursorPos, x, y, mPaint);
+ x += mPaint.measureText(cmpsStr, oriPos, cursorPos);
+
+ if (ComposingStatus.EDIT_PINYIN == mComposingStatus) {
+ drawCursor(canvas, x);
+ }
+
+ oriPos = cursorPos;
+ }
+ canvas.drawText(cmpsStr, oriPos, cmpsStr.length(), x, y, mPaint);
+ }
+ }
+}