1/*
2 * Copyright (C) 2009 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.pinyin;
18
19import android.graphics.drawable.Drawable;
20
21/**
22 * Class for soft keys which defined in the keyboard xml file. A soft key can be
23 * a basic key or a toggling key.
24 *
25 * @see com.android.inputmethod.pinyin.SoftKey
26 */
27public class SoftKeyToggle extends SoftKey {
28    /**
29     * The current state number is stored in the lowest 8 bits of mKeyMask, this
30     * mask is used to get the state number. If the current state is 0, the
31     * normal state is enabled; if the current state is more than 0, a toggle
32     * state in the toggle state chain will be enabled.
33     */
34    private static final int KEYMASK_TOGGLE_STATE = 0x000000ff;
35
36    private ToggleState mToggleState;
37
38    public int getToggleStateId() {
39        return (mKeyMask & KEYMASK_TOGGLE_STATE);
40    }
41
42    // The state id should be valid, and less than 255.
43    // If resetIfNotFound is true and there is no such toggle state with the
44    // given id, the key state will be reset.
45    // If the key state is newly changed (enabled to the given state, or
46    // reseted) and needs re-draw, return true.
47    public boolean enableToggleState(int stateId, boolean resetIfNotFound) {
48        int oldStateId = (mKeyMask & KEYMASK_TOGGLE_STATE);
49        if (oldStateId == stateId) return false;
50
51        mKeyMask &= (~KEYMASK_TOGGLE_STATE);
52        if (stateId > 0) {
53            mKeyMask |= (KEYMASK_TOGGLE_STATE & stateId);
54            if (getToggleState() == null) {
55                mKeyMask &= (~KEYMASK_TOGGLE_STATE);
56                if (!resetIfNotFound && oldStateId > 0) {
57                    mKeyMask |= (KEYMASK_TOGGLE_STATE & oldStateId);
58                }
59                return resetIfNotFound;
60            } else {
61                return true;
62            }
63        } else {
64            return true;
65        }
66    }
67
68    // The state id should be valid, and less than 255.
69    // If resetIfNotFound is true and there is no such toggle state with the
70    // given id, the key state will be reset.
71    // If the key state is newly changed and needs re-draw, return true.
72    public boolean disableToggleState(int stateId, boolean resetIfNotFound) {
73        int oldStateId = (mKeyMask & KEYMASK_TOGGLE_STATE);
74        if (oldStateId == stateId) {
75            mKeyMask &= (~KEYMASK_TOGGLE_STATE);
76            return stateId != 0;
77        }
78
79        if (resetIfNotFound) {
80            mKeyMask &= (~KEYMASK_TOGGLE_STATE);
81            return oldStateId != 0;
82        }
83        return false;
84    }
85
86    // Clear any toggle state. If the key needs re-draw, return true.
87    public boolean disableAllToggleStates() {
88        int oldStateId = (mKeyMask & KEYMASK_TOGGLE_STATE);
89        mKeyMask &= (~KEYMASK_TOGGLE_STATE);
90        return oldStateId != 0;
91    }
92
93    @Override
94    public Drawable getKeyIcon() {
95        ToggleState state = getToggleState();
96        if (null != state) return state.mKeyIcon;
97        return super.getKeyIcon();
98    }
99
100    @Override
101    public Drawable getKeyIconPopup() {
102        ToggleState state = getToggleState();
103        if (null != state) {
104            if (null != state.mKeyIconPopup) {
105                return state.mKeyIconPopup;
106            } else {
107                return state.mKeyIcon;
108            }
109        }
110        return super.getKeyIconPopup();
111    }
112
113    @Override
114    public int getKeyCode() {
115        ToggleState state = getToggleState();
116        if (null != state) return state.mKeyCode;
117        return mKeyCode;
118    }
119
120    @Override
121    public String getKeyLabel() {
122        ToggleState state = getToggleState();
123        if (null != state) return state.mKeyLabel;
124        return mKeyLabel;
125    }
126
127    @Override
128    public Drawable getKeyBg() {
129        ToggleState state = getToggleState();
130        if (null != state && null != state.mKeyType) {
131            return state.mKeyType.mKeyBg;
132        }
133        return mKeyType.mKeyBg;
134    }
135
136    @Override
137    public Drawable getKeyHlBg() {
138        ToggleState state = getToggleState();
139        if (null != state && null != state.mKeyType) {
140            return state.mKeyType.mKeyHlBg;
141        }
142        return mKeyType.mKeyHlBg;
143    }
144
145    @Override
146    public int getColor() {
147        ToggleState state = getToggleState();
148        if (null != state && null != state.mKeyType) {
149            return state.mKeyType.mColor;
150        }
151        return mKeyType.mColor;
152    }
153
154    @Override
155    public int getColorHl() {
156        ToggleState state = getToggleState();
157        if (null != state && null != state.mKeyType) {
158            return state.mKeyType.mColorHl;
159        }
160        return mKeyType.mColorHl;
161    }
162
163    @Override
164    public int getColorBalloon() {
165        ToggleState state = getToggleState();
166        if (null != state && null != state.mKeyType) {
167            return state.mKeyType.mColorBalloon;
168        }
169        return mKeyType.mColorBalloon;
170    }
171
172    @Override
173    public boolean isKeyCodeKey() {
174        ToggleState state = getToggleState();
175        if (null != state) {
176            if (state.mKeyCode > 0) return true;
177            return false;
178        }
179        return super.isKeyCodeKey();
180    }
181
182    @Override
183    public boolean isUserDefKey() {
184        ToggleState state = getToggleState();
185        if (null != state) {
186            if (state.mKeyCode < 0) return true;
187            return false;
188        }
189        return super.isUserDefKey();
190    }
191
192    @Override
193    public boolean isUniStrKey() {
194        ToggleState state = getToggleState();
195        if (null != state) {
196            if (null != state.mKeyLabel && state.mKeyCode == 0) {
197                return true;
198            }
199            return false;
200        }
201        return super.isUniStrKey();
202    }
203
204    @Override
205    public boolean needBalloon() {
206        ToggleState state = getToggleState();
207        if (null != state) {
208            return (state.mIdAndFlags & KEYMASK_BALLOON) != 0;
209        }
210        return super.needBalloon();
211    }
212
213    @Override
214    public boolean repeatable() {
215        ToggleState state = getToggleState();
216        if (null != state) {
217            return (state.mIdAndFlags & KEYMASK_REPEAT) != 0;
218        }
219        return super.repeatable();
220    }
221
222    @Override
223    public void changeCase(boolean lowerCase) {
224        ToggleState state = getToggleState();
225        if (null != state && null != state.mKeyLabel) {
226            if (lowerCase)
227                state.mKeyLabel = state.mKeyLabel.toLowerCase();
228            else
229                state.mKeyLabel = state.mKeyLabel.toUpperCase();
230        }
231    }
232
233    public ToggleState createToggleState() {
234        return new ToggleState();
235    }
236
237    public boolean setToggleStates(ToggleState rootState) {
238        if (null == rootState) return false;
239        mToggleState = rootState;
240        return true;
241    }
242
243    private ToggleState getToggleState() {
244        int stateId = (mKeyMask & KEYMASK_TOGGLE_STATE);
245        if (0 == stateId) return null;
246
247        ToggleState state = mToggleState;
248        while ((null != state)
249                && (state.mIdAndFlags & KEYMASK_TOGGLE_STATE) != stateId) {
250            state = state.mNextState;
251        }
252        return state;
253    }
254
255    public class ToggleState {
256        // The id should be bigger than 0;
257        private int mIdAndFlags;
258        public SoftKeyType mKeyType;
259        public int mKeyCode;
260        public Drawable mKeyIcon;
261        public Drawable mKeyIconPopup;
262        public String mKeyLabel;
263        public ToggleState mNextState;
264
265        public void setStateId(int stateId) {
266            mIdAndFlags |= (stateId & KEYMASK_TOGGLE_STATE);
267        }
268
269        public void setStateFlags(boolean repeat, boolean balloon) {
270            if (repeat) {
271                mIdAndFlags |= KEYMASK_REPEAT;
272            } else {
273                mIdAndFlags &= (~KEYMASK_REPEAT);
274            }
275
276            if (balloon) {
277                mIdAndFlags |= KEYMASK_BALLOON;
278            } else {
279                mIdAndFlags &= (~KEYMASK_BALLOON);
280            }
281        }
282    }
283}
284