mirror of
https://github.com/Helium314/HeliBoard.git
synced 2025-05-14 05:52:47 +00:00
prepare for splitting parsing and building of keyboards
one step towards #216
This commit is contained in:
parent
f3c52e9f6c
commit
b326011e0c
3 changed files with 403 additions and 259 deletions
|
@ -230,247 +230,6 @@ public class Key implements Comparable<Key> {
|
||||||
mHashCode = computeHashCode(this);
|
mHashCode = computeHashCode(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor for a key in a <GridRows/>.
|
|
||||||
*/
|
|
||||||
public Key(@Nullable final String label, final int code, @Nullable final String outputText,
|
|
||||||
@Nullable final String hintLabel, @Nullable final String moreKeySpecs,
|
|
||||||
final int labelFlags, final int backgroundType, final int x, final int y,
|
|
||||||
final int width, final int height, final KeyboardParams params) {
|
|
||||||
mWidth = width - params.mHorizontalGap;
|
|
||||||
mHeight = height - params.mVerticalGap;
|
|
||||||
mHorizontalGap = params.mHorizontalGap;
|
|
||||||
mVerticalGap = params.mVerticalGap;
|
|
||||||
mHintLabel = hintLabel;
|
|
||||||
mLabelFlags = labelFlags;
|
|
||||||
mBackgroundType = backgroundType;
|
|
||||||
|
|
||||||
if (moreKeySpecs != null) {
|
|
||||||
String[] moreKeys = MoreKeySpec.splitKeySpecs(moreKeySpecs);
|
|
||||||
// Get maximum column order number and set a relevant mode value.
|
|
||||||
int moreKeysColumnAndFlags = MORE_KEYS_MODE_MAX_COLUMN_WITH_AUTO_ORDER
|
|
||||||
| params.mMaxMoreKeysKeyboardColumn;
|
|
||||||
int value;
|
|
||||||
if ((value = MoreKeySpec.getIntValue(moreKeys, MORE_KEYS_AUTO_COLUMN_ORDER, -1)) > 0) {
|
|
||||||
// Override with fixed column order number and set a relevant mode value.
|
|
||||||
moreKeysColumnAndFlags = MORE_KEYS_MODE_FIXED_COLUMN_WITH_AUTO_ORDER
|
|
||||||
| (value & MORE_KEYS_COLUMN_NUMBER_MASK);
|
|
||||||
}
|
|
||||||
if ((value = MoreKeySpec.getIntValue(moreKeys, MORE_KEYS_FIXED_COLUMN_ORDER, -1)) > 0) {
|
|
||||||
// Override with fixed column order number and set a relevant mode value.
|
|
||||||
moreKeysColumnAndFlags = MORE_KEYS_MODE_FIXED_COLUMN_WITH_FIXED_ORDER
|
|
||||||
| (value & MORE_KEYS_COLUMN_NUMBER_MASK);
|
|
||||||
}
|
|
||||||
if (MoreKeySpec.getBooleanValue(moreKeys, MORE_KEYS_HAS_LABELS)) {
|
|
||||||
moreKeysColumnAndFlags |= MORE_KEYS_FLAGS_HAS_LABELS;
|
|
||||||
}
|
|
||||||
if (MoreKeySpec.getBooleanValue(moreKeys, MORE_KEYS_NEEDS_DIVIDERS)) {
|
|
||||||
moreKeysColumnAndFlags |= MORE_KEYS_FLAGS_NEEDS_DIVIDERS;
|
|
||||||
}
|
|
||||||
if (MoreKeySpec.getBooleanValue(moreKeys, MORE_KEYS_NO_PANEL_AUTO_MORE_KEY)) {
|
|
||||||
moreKeysColumnAndFlags |= MORE_KEYS_FLAGS_NO_PANEL_AUTO_MORE_KEY;
|
|
||||||
}
|
|
||||||
mMoreKeysColumnAndFlags = moreKeysColumnAndFlags;
|
|
||||||
|
|
||||||
moreKeys = MoreKeySpec.insertAdditionalMoreKeys(moreKeys, null);
|
|
||||||
int actionFlags = 0;
|
|
||||||
if (moreKeys != null) {
|
|
||||||
actionFlags |= ACTION_FLAGS_ENABLE_LONG_PRESS;
|
|
||||||
mMoreKeys = new MoreKeySpec[moreKeys.length];
|
|
||||||
for (int i = 0; i < moreKeys.length; i++) {
|
|
||||||
mMoreKeys[i] = new MoreKeySpec(moreKeys[i], false, Locale.getDefault());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
mMoreKeys = null;
|
|
||||||
}
|
|
||||||
mActionFlags = actionFlags;
|
|
||||||
} else {
|
|
||||||
// TODO: Pass keyActionFlags as an argument.
|
|
||||||
mActionFlags = ACTION_FLAGS_NO_KEY_PREVIEW;
|
|
||||||
mMoreKeys = null;
|
|
||||||
mMoreKeysColumnAndFlags = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
mLabel = label;
|
|
||||||
mOptionalAttributes = OptionalAttributes.newInstance(outputText, CODE_UNSPECIFIED,
|
|
||||||
ICON_UNDEFINED, 0 /* visualInsetsLeft */, 0 /* visualInsetsRight */);
|
|
||||||
mCode = code;
|
|
||||||
mEnabled = (code != CODE_UNSPECIFIED);
|
|
||||||
mIconId = KeyboardIconsSet.ICON_UNDEFINED;
|
|
||||||
// Horizontal gap is divided equally to both sides of the key.
|
|
||||||
mX = x + mHorizontalGap / 2;
|
|
||||||
mY = y;
|
|
||||||
mHitBox.set(x, y, x + width + 1, y + height);
|
|
||||||
mKeyVisualAttributes = null;
|
|
||||||
|
|
||||||
mHashCode = computeHashCode(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a key with the given top-left coordinate and extract its attributes from a key
|
|
||||||
* specification string, Key attribute array, key style, and etc.
|
|
||||||
*
|
|
||||||
* @param keySpec the key specification.
|
|
||||||
* @param keyAttr the Key XML attributes array.
|
|
||||||
* @param style the {@link KeyStyle} of this key.
|
|
||||||
* @param params the keyboard building parameters.
|
|
||||||
* @param row the row that this key belongs to. row's x-coordinate will be the right edge of
|
|
||||||
* this key.
|
|
||||||
*/
|
|
||||||
public Key(@Nullable final String keySpec, @NonNull final TypedArray keyAttr,
|
|
||||||
@NonNull final KeyStyle style, @NonNull final KeyboardParams params,
|
|
||||||
@NonNull final KeyboardRow row) {
|
|
||||||
mHorizontalGap = isSpacer() ? 0 : params.mHorizontalGap;
|
|
||||||
mVerticalGap = params.mVerticalGap;
|
|
||||||
|
|
||||||
final float horizontalGapFloat = mHorizontalGap;
|
|
||||||
final int rowHeight = row.getRowHeight();
|
|
||||||
mHeight = rowHeight - mVerticalGap;
|
|
||||||
|
|
||||||
final float keyXPos = row.getKeyX(keyAttr);
|
|
||||||
final float keyWidth = row.getKeyWidth(keyAttr, keyXPos);
|
|
||||||
final int keyYPos = row.getKeyY();
|
|
||||||
|
|
||||||
// Horizontal gap is divided equally to both sides of the key.
|
|
||||||
mX = Math.round(keyXPos + horizontalGapFloat / 2);
|
|
||||||
mY = keyYPos;
|
|
||||||
mWidth = Math.round(keyWidth - horizontalGapFloat);
|
|
||||||
mHitBox.set(Math.round(keyXPos), keyYPos, Math.round(keyXPos + keyWidth) + 1,
|
|
||||||
keyYPos + rowHeight);
|
|
||||||
// Update row to have current x coordinate.
|
|
||||||
row.setXPos(keyXPos + keyWidth);
|
|
||||||
|
|
||||||
mBackgroundType = style.getInt(keyAttr,
|
|
||||||
R.styleable.Keyboard_Key_backgroundType, row.getDefaultBackgroundType());
|
|
||||||
|
|
||||||
final int baseWidth = params.mBaseWidth;
|
|
||||||
final int visualInsetsLeft = Math.round(keyAttr.getFraction(
|
|
||||||
R.styleable.Keyboard_Key_visualInsetsLeft, baseWidth, baseWidth, 0));
|
|
||||||
final int visualInsetsRight = Math.round(keyAttr.getFraction(
|
|
||||||
R.styleable.Keyboard_Key_visualInsetsRight, baseWidth, baseWidth, 0));
|
|
||||||
|
|
||||||
mLabelFlags = style.getFlags(keyAttr, R.styleable.Keyboard_Key_keyLabelFlags)
|
|
||||||
| row.getDefaultKeyLabelFlags();
|
|
||||||
final boolean needsToUpcase = needsToUpcase(mLabelFlags, params.mId.mElementId);
|
|
||||||
final Locale localeForUpcasing = params.mId.getLocale();
|
|
||||||
int actionFlags = style.getFlags(keyAttr, R.styleable.Keyboard_Key_keyActionFlags);
|
|
||||||
String[] moreKeys = style.getStringArray(keyAttr, R.styleable.Keyboard_Key_moreKeys);
|
|
||||||
|
|
||||||
// Get maximum column order number and set a relevant mode value.
|
|
||||||
int moreKeysColumnAndFlags = MORE_KEYS_MODE_MAX_COLUMN_WITH_AUTO_ORDER
|
|
||||||
| style.getInt(keyAttr, R.styleable.Keyboard_Key_maxMoreKeysColumn,
|
|
||||||
params.mMaxMoreKeysKeyboardColumn);
|
|
||||||
int value;
|
|
||||||
if ((value = MoreKeySpec.getIntValue(moreKeys, MORE_KEYS_AUTO_COLUMN_ORDER, -1)) > 0) {
|
|
||||||
// Override with fixed column order number and set a relevant mode value.
|
|
||||||
moreKeysColumnAndFlags = MORE_KEYS_MODE_FIXED_COLUMN_WITH_AUTO_ORDER
|
|
||||||
| (value & MORE_KEYS_COLUMN_NUMBER_MASK);
|
|
||||||
}
|
|
||||||
if ((value = MoreKeySpec.getIntValue(moreKeys, MORE_KEYS_FIXED_COLUMN_ORDER, -1)) > 0) {
|
|
||||||
// Override with fixed column order number and set a relevant mode value.
|
|
||||||
moreKeysColumnAndFlags = MORE_KEYS_MODE_FIXED_COLUMN_WITH_FIXED_ORDER
|
|
||||||
| (value & MORE_KEYS_COLUMN_NUMBER_MASK);
|
|
||||||
}
|
|
||||||
if (MoreKeySpec.getBooleanValue(moreKeys, MORE_KEYS_HAS_LABELS)) {
|
|
||||||
moreKeysColumnAndFlags |= MORE_KEYS_FLAGS_HAS_LABELS;
|
|
||||||
}
|
|
||||||
if (MoreKeySpec.getBooleanValue(moreKeys, MORE_KEYS_NEEDS_DIVIDERS)) {
|
|
||||||
moreKeysColumnAndFlags |= MORE_KEYS_FLAGS_NEEDS_DIVIDERS;
|
|
||||||
}
|
|
||||||
if (MoreKeySpec.getBooleanValue(moreKeys, MORE_KEYS_NO_PANEL_AUTO_MORE_KEY)) {
|
|
||||||
moreKeysColumnAndFlags |= MORE_KEYS_FLAGS_NO_PANEL_AUTO_MORE_KEY;
|
|
||||||
}
|
|
||||||
mMoreKeysColumnAndFlags = moreKeysColumnAndFlags;
|
|
||||||
|
|
||||||
final String[] additionalMoreKeys;
|
|
||||||
if ((mLabelFlags & LABEL_FLAGS_DISABLE_ADDITIONAL_MORE_KEYS) != 0) {
|
|
||||||
additionalMoreKeys = null;
|
|
||||||
} else {
|
|
||||||
additionalMoreKeys = style.getStringArray(keyAttr,
|
|
||||||
R.styleable.Keyboard_Key_additionalMoreKeys);
|
|
||||||
}
|
|
||||||
moreKeys = MoreKeySpec.insertAdditionalMoreKeys(moreKeys, additionalMoreKeys);
|
|
||||||
if (moreKeys != null) {
|
|
||||||
actionFlags |= ACTION_FLAGS_ENABLE_LONG_PRESS;
|
|
||||||
mMoreKeys = new MoreKeySpec[moreKeys.length];
|
|
||||||
for (int i = 0; i < moreKeys.length; i++) {
|
|
||||||
mMoreKeys[i] = new MoreKeySpec(moreKeys[i], needsToUpcase, localeForUpcasing);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
mMoreKeys = null;
|
|
||||||
}
|
|
||||||
mActionFlags = actionFlags;
|
|
||||||
|
|
||||||
mIconId = KeySpecParser.getIconId(keySpec);
|
|
||||||
final int disabledIconId = KeySpecParser.getIconId(style.getString(keyAttr,
|
|
||||||
R.styleable.Keyboard_Key_keyIconDisabled));
|
|
||||||
|
|
||||||
final int code = KeySpecParser.getCode(keySpec);
|
|
||||||
if ((mLabelFlags & LABEL_FLAGS_FROM_CUSTOM_ACTION_LABEL) != 0) {
|
|
||||||
mLabel = params.mId.mCustomActionLabel;
|
|
||||||
} else if (code >= Character.MIN_SUPPLEMENTARY_CODE_POINT) {
|
|
||||||
// This is a workaround to have a key that has a supplementary code point in its label.
|
|
||||||
// Because we can put a string in resource neither as a XML entity of a supplementary
|
|
||||||
// code point nor as a surrogate pair.
|
|
||||||
mLabel = new StringBuilder().appendCodePoint(code).toString();
|
|
||||||
} else {
|
|
||||||
final String label = KeySpecParser.getLabel(keySpec);
|
|
||||||
mLabel = needsToUpcase
|
|
||||||
? StringUtils.toTitleCaseOfKeyLabel(label, localeForUpcasing)
|
|
||||||
: label;
|
|
||||||
}
|
|
||||||
if ((mLabelFlags & LABEL_FLAGS_DISABLE_HINT_LABEL) != 0) {
|
|
||||||
mHintLabel = null;
|
|
||||||
} else {
|
|
||||||
final String hintLabel = style.getString(
|
|
||||||
keyAttr, R.styleable.Keyboard_Key_keyHintLabel);
|
|
||||||
mHintLabel = needsToUpcase
|
|
||||||
? StringUtils.toTitleCaseOfKeyLabel(hintLabel, localeForUpcasing)
|
|
||||||
: hintLabel;
|
|
||||||
}
|
|
||||||
String outputText = KeySpecParser.getOutputText(keySpec);
|
|
||||||
if (needsToUpcase) {
|
|
||||||
outputText = StringUtils.toTitleCaseOfKeyLabel(outputText, localeForUpcasing);
|
|
||||||
}
|
|
||||||
// Choose the first letter of the label as primary code if not specified.
|
|
||||||
if (code == CODE_UNSPECIFIED && TextUtils.isEmpty(outputText)
|
|
||||||
&& !TextUtils.isEmpty(mLabel)) {
|
|
||||||
if (StringUtils.codePointCount(mLabel) == 1) {
|
|
||||||
// Use the first letter of the hint label if shiftedLetterActivated flag is
|
|
||||||
// specified.
|
|
||||||
if (hasShiftedLetterHint() && isShiftedLetterActivated()) {
|
|
||||||
mCode = mHintLabel.codePointAt(0);
|
|
||||||
} else {
|
|
||||||
mCode = mLabel.codePointAt(0);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// In some locale and case, the character might be represented by multiple code
|
|
||||||
// points, such as upper case Eszett of German alphabet.
|
|
||||||
outputText = mLabel;
|
|
||||||
mCode = CODE_OUTPUT_TEXT;
|
|
||||||
}
|
|
||||||
} else if (code == CODE_UNSPECIFIED && outputText != null) {
|
|
||||||
if (StringUtils.codePointCount(outputText) == 1) {
|
|
||||||
mCode = outputText.codePointAt(0);
|
|
||||||
outputText = null;
|
|
||||||
} else {
|
|
||||||
mCode = CODE_OUTPUT_TEXT;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
mCode = needsToUpcase ? StringUtils.toTitleCaseOfKeyCode(code, localeForUpcasing)
|
|
||||||
: code;
|
|
||||||
}
|
|
||||||
final int altCodeInAttr = KeySpecParser.parseCode(
|
|
||||||
style.getString(keyAttr, R.styleable.Keyboard_Key_altCode), CODE_UNSPECIFIED);
|
|
||||||
final int altCode = needsToUpcase
|
|
||||||
? StringUtils.toTitleCaseOfKeyCode(altCodeInAttr, localeForUpcasing)
|
|
||||||
: altCodeInAttr;
|
|
||||||
mOptionalAttributes = OptionalAttributes.newInstance(outputText, altCode,
|
|
||||||
disabledIconId, visualInsetsLeft, visualInsetsRight);
|
|
||||||
mKeyVisualAttributes = KeyVisualAttributes.newInstance(keyAttr);
|
|
||||||
mHashCode = computeHashCode(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copy constructor for DynamicGridKeyboard.GridKey.
|
* Copy constructor for DynamicGridKeyboard.GridKey.
|
||||||
*
|
*
|
||||||
|
@ -506,6 +265,38 @@ public class Key implements Comparable<Key> {
|
||||||
mEnabled = key.mEnabled;
|
mEnabled = key.mEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** constructor from KeyParams */
|
||||||
|
private Key(KeyParams keyParams) {
|
||||||
|
// stuff to copy
|
||||||
|
mCode = keyParams.mCode;
|
||||||
|
mLabel = keyParams.mLabel;
|
||||||
|
mHintLabel = keyParams.mHintLabel;
|
||||||
|
mLabelFlags = keyParams.mLabelFlags;
|
||||||
|
mIconId = keyParams.mIconId;
|
||||||
|
mMoreKeys = keyParams.mMoreKeys;
|
||||||
|
mMoreKeysColumnAndFlags = keyParams.mMoreKeysColumnAndFlags;
|
||||||
|
mBackgroundType = keyParams.mBackgroundType;
|
||||||
|
mActionFlags = keyParams.mActionFlags;
|
||||||
|
mKeyVisualAttributes = keyParams.mKeyVisualAttributes;
|
||||||
|
mOptionalAttributes = keyParams.mOptionalAttributes;
|
||||||
|
mEnabled = keyParams.mEnabled;
|
||||||
|
|
||||||
|
// stuff to create
|
||||||
|
mWidth = keyParams.mWidth;
|
||||||
|
mHeight = keyParams.mHeight;
|
||||||
|
if (!isSpacer() && (mWidth == 0 || mHeight == 0)) {
|
||||||
|
throw new IllegalStateException("key needs positive width and height");
|
||||||
|
}
|
||||||
|
mHorizontalGap = isSpacer() ? 0 : keyParams.mHorizontalGap;
|
||||||
|
mVerticalGap = keyParams.mVerticalGap;
|
||||||
|
// Horizontal gap is divided equally to both sides of the key.
|
||||||
|
mX = Math.round(keyParams.xPos + ((float) keyParams.mHorizontalGap) / 2);
|
||||||
|
mY = keyParams.yPos;
|
||||||
|
mHitBox.set(Math.round(keyParams.xPos), keyParams.yPos, Math.round(keyParams.xPos + mWidth + mHorizontalGap) + 1,
|
||||||
|
keyParams.yPos + mHeight + mHorizontalGap);
|
||||||
|
mHashCode = computeHashCode(this);
|
||||||
|
}
|
||||||
|
|
||||||
private Key(@NonNull final Key key, @Nullable final MoreKeySpec[] moreKeys) {
|
private Key(@NonNull final Key key, @Nullable final MoreKeySpec[] moreKeys) {
|
||||||
// Final attributes.
|
// Final attributes.
|
||||||
mCode = key.mCode;
|
mCode = key.mCode;
|
||||||
|
@ -1121,10 +912,15 @@ public class Key implements Comparable<Key> {
|
||||||
|| iconName.equals(KeyboardIconsSet.NAME_EMOJI_ACTION_KEY);
|
|| iconName.equals(KeyboardIconsSet.NAME_EMOJI_ACTION_KEY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isFunctional() {
|
||||||
|
return mBackgroundType == BACKGROUND_TYPE_FUNCTIONAL
|
||||||
|
|| mBackgroundType == BACKGROUND_TYPE_STICKY_OFF
|
||||||
|
|| mBackgroundType == BACKGROUND_TYPE_STICKY_ON;
|
||||||
|
}
|
||||||
|
|
||||||
public static class Spacer extends Key {
|
public static class Spacer extends Key {
|
||||||
public Spacer(final TypedArray keyAttr, final KeyStyle keyStyle,
|
private Spacer(KeyParams keyParams) {
|
||||||
final KeyboardParams params, final KeyboardRow row) {
|
super(keyParams);
|
||||||
super(null /* keySpec */, keyAttr, keyStyle, params, row);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1138,9 +934,303 @@ public class Key implements Comparable<Key> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isFunctional() {
|
// for creating keys that might get modified later
|
||||||
return mBackgroundType == BACKGROUND_TYPE_FUNCTIONAL
|
public static class KeyParams {
|
||||||
|| mBackgroundType == BACKGROUND_TYPE_STICKY_OFF
|
// params for building
|
||||||
|| mBackgroundType == BACKGROUND_TYPE_STICKY_ON;
|
boolean isSpacer;
|
||||||
|
// relative values and absolute keyboard dimensions for re-determining key dimensions (if necessary)
|
||||||
|
/*
|
||||||
|
// todo: currently commented because not used, but planned (see todo below)
|
||||||
|
public int keyboardWidth;
|
||||||
|
public int keyboardHeight;
|
||||||
|
// relative widths and heights may not add up to 100% when including gaps
|
||||||
|
// this is ok with fill right, but otherwise?
|
||||||
|
public float mRelativeWidth; // also allow -1f as value, this means "fill right"
|
||||||
|
public float mRelativeHeight;
|
||||||
|
public float mRelativeHorizontalGap;
|
||||||
|
public float mRelativeVerticalGap;
|
||||||
|
*/
|
||||||
|
// stuff that likely remains after constructor, maybe make final
|
||||||
|
final int mCode;
|
||||||
|
@Nullable final String mLabel;
|
||||||
|
@Nullable final String mHintLabel;
|
||||||
|
final int mLabelFlags;
|
||||||
|
final int mIconId;
|
||||||
|
public final MoreKeySpec[] mMoreKeys;
|
||||||
|
final int mMoreKeysColumnAndFlags;
|
||||||
|
final int mBackgroundType;
|
||||||
|
final int mActionFlags;
|
||||||
|
@Nullable final KeyVisualAttributes mKeyVisualAttributes;
|
||||||
|
@Nullable final OptionalAttributes mOptionalAttributes;
|
||||||
|
public boolean mEnabled = true;
|
||||||
|
|
||||||
|
// stuff that may very well change, or only be set just before it's needed
|
||||||
|
int mWidth;
|
||||||
|
int mHeight;
|
||||||
|
int mHorizontalGap;
|
||||||
|
int mVerticalGap;
|
||||||
|
float xPos;
|
||||||
|
int yPos;
|
||||||
|
|
||||||
|
public static KeyParams newSpacer(final TypedArray keyAttr, final KeyStyle keyStyle,
|
||||||
|
final KeyboardParams params, final KeyboardRow row) {
|
||||||
|
final KeyParams keyParams = new KeyParams(null, keyAttr, keyStyle, params, row);
|
||||||
|
keyParams.isSpacer = true;
|
||||||
|
return keyParams;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Key createKey() {
|
||||||
|
if (isSpacer) return new Spacer(this);
|
||||||
|
return new Key(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo:
|
||||||
|
// get relativeWidth and others when creating the params
|
||||||
|
// check how relative width could be adjusted
|
||||||
|
// there is the fillRight thing
|
||||||
|
// and not sure if there is a spacer on the left side if the key starts not directly at the edge
|
||||||
|
// then it should be possible to re-create the entire keyboard using the new dimensions
|
||||||
|
// can add keys (spacer) in a row, for split keyboard
|
||||||
|
/*
|
||||||
|
public void setDimensionsFromRelativeSize() {
|
||||||
|
if (keyboardHeight == 0 || keyboardWidth == 0 || mRelativeHeight == 0 || mRelativeWidth == 0)
|
||||||
|
throw new IllegalStateException("can't use setUsingRelativeHeight, not all fields are set");
|
||||||
|
float horizontalGap = isSpacer ? 0f : mRelativeHorizontalGap * keyboardWidth;
|
||||||
|
mHorizontalGap = (int) horizontalGap;
|
||||||
|
float verticalGap = mRelativeVerticalGap * mRelativeHeight;
|
||||||
|
mVerticalGap = (int) verticalGap;
|
||||||
|
float keyWidth = mRelativeWidth * keyboardWidth;
|
||||||
|
mWidth = Math.round(keyWidth - horizontalGap);
|
||||||
|
mHeight = (int) (mRelativeHeight * keyboardHeight - verticalGap);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* Create keyParams with the given top-left coordinate and extract its attributes from a key
|
||||||
|
* specification string, Key attribute array, key style, and etc.
|
||||||
|
*
|
||||||
|
* @param keySpec the key specification.
|
||||||
|
* @param keyAttr the Key XML attributes array.
|
||||||
|
* @param style the {@link KeyStyle} of this key.
|
||||||
|
* @param params the keyboard building parameters.
|
||||||
|
* @param row the row that this key belongs to. row's x-coordinate will be the right edge of
|
||||||
|
* this key.
|
||||||
|
*/
|
||||||
|
public KeyParams(@Nullable final String keySpec, @NonNull final TypedArray keyAttr,
|
||||||
|
@NonNull final KeyStyle style, @NonNull final KeyboardParams params,
|
||||||
|
@NonNull final KeyboardRow row) {
|
||||||
|
mHorizontalGap = params.mHorizontalGap;
|
||||||
|
mVerticalGap = params.mVerticalGap;
|
||||||
|
|
||||||
|
final float horizontalGapFloat = mHorizontalGap;
|
||||||
|
final int rowHeight = row.getRowHeight();
|
||||||
|
mHeight = rowHeight - mVerticalGap;
|
||||||
|
|
||||||
|
xPos = row.getKeyX(keyAttr);
|
||||||
|
final float keyWidth = row.getKeyWidth(keyAttr, xPos);
|
||||||
|
yPos = row.getKeyY();
|
||||||
|
|
||||||
|
mWidth = Math.round(keyWidth - horizontalGapFloat);
|
||||||
|
// Update row to have current x coordinate.
|
||||||
|
row.setXPos(xPos + keyWidth);
|
||||||
|
|
||||||
|
mBackgroundType = style.getInt(keyAttr,
|
||||||
|
R.styleable.Keyboard_Key_backgroundType, row.getDefaultBackgroundType());
|
||||||
|
|
||||||
|
final int baseWidth = params.mBaseWidth;
|
||||||
|
final int visualInsetsLeft = Math.round(keyAttr.getFraction(
|
||||||
|
R.styleable.Keyboard_Key_visualInsetsLeft, baseWidth, baseWidth, 0));
|
||||||
|
final int visualInsetsRight = Math.round(keyAttr.getFraction(
|
||||||
|
R.styleable.Keyboard_Key_visualInsetsRight, baseWidth, baseWidth, 0));
|
||||||
|
|
||||||
|
mLabelFlags = style.getFlags(keyAttr, R.styleable.Keyboard_Key_keyLabelFlags)
|
||||||
|
| row.getDefaultKeyLabelFlags();
|
||||||
|
final boolean needsToUpcase = needsToUpcase(mLabelFlags, params.mId.mElementId);
|
||||||
|
final Locale localeForUpcasing = params.mId.getLocale();
|
||||||
|
int actionFlags = style.getFlags(keyAttr, R.styleable.Keyboard_Key_keyActionFlags);
|
||||||
|
String[] moreKeys = style.getStringArray(keyAttr, R.styleable.Keyboard_Key_moreKeys);
|
||||||
|
|
||||||
|
// Get maximum column order number and set a relevant mode value.
|
||||||
|
int moreKeysColumnAndFlags = MORE_KEYS_MODE_MAX_COLUMN_WITH_AUTO_ORDER
|
||||||
|
| style.getInt(keyAttr, R.styleable.Keyboard_Key_maxMoreKeysColumn,
|
||||||
|
params.mMaxMoreKeysKeyboardColumn);
|
||||||
|
int value;
|
||||||
|
if ((value = MoreKeySpec.getIntValue(moreKeys, MORE_KEYS_AUTO_COLUMN_ORDER, -1)) > 0) {
|
||||||
|
// Override with fixed column order number and set a relevant mode value.
|
||||||
|
moreKeysColumnAndFlags = MORE_KEYS_MODE_FIXED_COLUMN_WITH_AUTO_ORDER
|
||||||
|
| (value & MORE_KEYS_COLUMN_NUMBER_MASK);
|
||||||
|
}
|
||||||
|
if ((value = MoreKeySpec.getIntValue(moreKeys, MORE_KEYS_FIXED_COLUMN_ORDER, -1)) > 0) {
|
||||||
|
// Override with fixed column order number and set a relevant mode value.
|
||||||
|
moreKeysColumnAndFlags = MORE_KEYS_MODE_FIXED_COLUMN_WITH_FIXED_ORDER
|
||||||
|
| (value & MORE_KEYS_COLUMN_NUMBER_MASK);
|
||||||
|
}
|
||||||
|
if (MoreKeySpec.getBooleanValue(moreKeys, MORE_KEYS_HAS_LABELS)) {
|
||||||
|
moreKeysColumnAndFlags |= MORE_KEYS_FLAGS_HAS_LABELS;
|
||||||
|
}
|
||||||
|
if (MoreKeySpec.getBooleanValue(moreKeys, MORE_KEYS_NEEDS_DIVIDERS)) {
|
||||||
|
moreKeysColumnAndFlags |= MORE_KEYS_FLAGS_NEEDS_DIVIDERS;
|
||||||
|
}
|
||||||
|
if (MoreKeySpec.getBooleanValue(moreKeys, MORE_KEYS_NO_PANEL_AUTO_MORE_KEY)) {
|
||||||
|
moreKeysColumnAndFlags |= MORE_KEYS_FLAGS_NO_PANEL_AUTO_MORE_KEY;
|
||||||
|
}
|
||||||
|
mMoreKeysColumnAndFlags = moreKeysColumnAndFlags;
|
||||||
|
|
||||||
|
final String[] additionalMoreKeys;
|
||||||
|
if ((mLabelFlags & LABEL_FLAGS_DISABLE_ADDITIONAL_MORE_KEYS) != 0) {
|
||||||
|
additionalMoreKeys = null;
|
||||||
|
} else {
|
||||||
|
additionalMoreKeys = style.getStringArray(keyAttr,
|
||||||
|
R.styleable.Keyboard_Key_additionalMoreKeys);
|
||||||
|
}
|
||||||
|
moreKeys = MoreKeySpec.insertAdditionalMoreKeys(moreKeys, additionalMoreKeys);
|
||||||
|
if (moreKeys != null) {
|
||||||
|
actionFlags |= ACTION_FLAGS_ENABLE_LONG_PRESS;
|
||||||
|
mMoreKeys = new MoreKeySpec[moreKeys.length];
|
||||||
|
for (int i = 0; i < moreKeys.length; i++) {
|
||||||
|
mMoreKeys[i] = new MoreKeySpec(moreKeys[i], needsToUpcase, localeForUpcasing);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mMoreKeys = null;
|
||||||
|
}
|
||||||
|
mActionFlags = actionFlags;
|
||||||
|
|
||||||
|
mIconId = KeySpecParser.getIconId(keySpec);
|
||||||
|
final int disabledIconId = KeySpecParser.getIconId(style.getString(keyAttr,
|
||||||
|
R.styleable.Keyboard_Key_keyIconDisabled));
|
||||||
|
|
||||||
|
final int code = KeySpecParser.getCode(keySpec);
|
||||||
|
if ((mLabelFlags & LABEL_FLAGS_FROM_CUSTOM_ACTION_LABEL) != 0) {
|
||||||
|
mLabel = params.mId.mCustomActionLabel;
|
||||||
|
} else if (code >= Character.MIN_SUPPLEMENTARY_CODE_POINT) {
|
||||||
|
// This is a workaround to have a key that has a supplementary code point in its label.
|
||||||
|
// Because we can put a string in resource neither as a XML entity of a supplementary
|
||||||
|
// code point nor as a surrogate pair.
|
||||||
|
mLabel = new StringBuilder().appendCodePoint(code).toString();
|
||||||
|
} else {
|
||||||
|
final String label = KeySpecParser.getLabel(keySpec);
|
||||||
|
mLabel = needsToUpcase
|
||||||
|
? StringUtils.toTitleCaseOfKeyLabel(label, localeForUpcasing)
|
||||||
|
: label;
|
||||||
|
}
|
||||||
|
if ((mLabelFlags & LABEL_FLAGS_DISABLE_HINT_LABEL) != 0) {
|
||||||
|
mHintLabel = null;
|
||||||
|
} else {
|
||||||
|
final String hintLabel = style.getString(
|
||||||
|
keyAttr, R.styleable.Keyboard_Key_keyHintLabel);
|
||||||
|
mHintLabel = needsToUpcase
|
||||||
|
? StringUtils.toTitleCaseOfKeyLabel(hintLabel, localeForUpcasing)
|
||||||
|
: hintLabel;
|
||||||
|
}
|
||||||
|
String outputText = KeySpecParser.getOutputText(keySpec);
|
||||||
|
if (needsToUpcase) {
|
||||||
|
outputText = StringUtils.toTitleCaseOfKeyLabel(outputText, localeForUpcasing);
|
||||||
|
}
|
||||||
|
// Choose the first letter of the label as primary code if not specified.
|
||||||
|
if (code == CODE_UNSPECIFIED && TextUtils.isEmpty(outputText)
|
||||||
|
&& !TextUtils.isEmpty(mLabel)) {
|
||||||
|
if (StringUtils.codePointCount(mLabel) == 1) {
|
||||||
|
// Use the first letter of the hint label if shiftedLetterActivated flag is
|
||||||
|
// specified.
|
||||||
|
if ((mLabelFlags & LABEL_FLAGS_HAS_SHIFTED_LETTER_HINT) != 0 && (mLabelFlags & LABEL_FLAGS_SHIFTED_LETTER_ACTIVATED) != 0 && !TextUtils.isEmpty(mHintLabel)) {
|
||||||
|
mCode = mHintLabel.codePointAt(0);
|
||||||
|
} else {
|
||||||
|
mCode = mLabel.codePointAt(0);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// In some locale and case, the character might be represented by multiple code
|
||||||
|
// points, such as upper case Eszett of German alphabet.
|
||||||
|
outputText = mLabel;
|
||||||
|
mCode = CODE_OUTPUT_TEXT;
|
||||||
|
}
|
||||||
|
} else if (code == CODE_UNSPECIFIED && outputText != null) {
|
||||||
|
if (StringUtils.codePointCount(outputText) == 1) {
|
||||||
|
mCode = outputText.codePointAt(0);
|
||||||
|
outputText = null;
|
||||||
|
} else {
|
||||||
|
mCode = CODE_OUTPUT_TEXT;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mCode = needsToUpcase ? StringUtils.toTitleCaseOfKeyCode(code, localeForUpcasing)
|
||||||
|
: code;
|
||||||
|
}
|
||||||
|
final int altCodeInAttr = KeySpecParser.parseCode(
|
||||||
|
style.getString(keyAttr, R.styleable.Keyboard_Key_altCode), CODE_UNSPECIFIED);
|
||||||
|
final int altCode = needsToUpcase
|
||||||
|
? StringUtils.toTitleCaseOfKeyCode(altCodeInAttr, localeForUpcasing)
|
||||||
|
: altCodeInAttr;
|
||||||
|
mOptionalAttributes = OptionalAttributes.newInstance(outputText, altCode,
|
||||||
|
disabledIconId, visualInsetsLeft, visualInsetsRight);
|
||||||
|
mKeyVisualAttributes = KeyVisualAttributes.newInstance(keyAttr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** for <GridRows/> */
|
||||||
|
public KeyParams(@Nullable final String label, final int code, @Nullable final String outputText,
|
||||||
|
@Nullable final String hintLabel, @Nullable final String moreKeySpecs,
|
||||||
|
final int labelFlags, final int backgroundType, final int x, final int y,
|
||||||
|
final int width, final int height, final KeyboardParams params) {
|
||||||
|
mWidth = width - params.mHorizontalGap;
|
||||||
|
mHeight = height - params.mVerticalGap;
|
||||||
|
mHorizontalGap = params.mHorizontalGap;
|
||||||
|
mVerticalGap = params.mVerticalGap;
|
||||||
|
mHintLabel = hintLabel;
|
||||||
|
mLabelFlags = labelFlags;
|
||||||
|
mBackgroundType = backgroundType;
|
||||||
|
xPos = x;
|
||||||
|
yPos = y;
|
||||||
|
|
||||||
|
if (moreKeySpecs != null) {
|
||||||
|
String[] moreKeys = MoreKeySpec.splitKeySpecs(moreKeySpecs);
|
||||||
|
// Get maximum column order number and set a relevant mode value.
|
||||||
|
int moreKeysColumnAndFlags = MORE_KEYS_MODE_MAX_COLUMN_WITH_AUTO_ORDER
|
||||||
|
| params.mMaxMoreKeysKeyboardColumn;
|
||||||
|
int value;
|
||||||
|
if ((value = MoreKeySpec.getIntValue(moreKeys, MORE_KEYS_AUTO_COLUMN_ORDER, -1)) > 0) {
|
||||||
|
// Override with fixed column order number and set a relevant mode value.
|
||||||
|
moreKeysColumnAndFlags = MORE_KEYS_MODE_FIXED_COLUMN_WITH_AUTO_ORDER
|
||||||
|
| (value & MORE_KEYS_COLUMN_NUMBER_MASK);
|
||||||
|
}
|
||||||
|
if ((value = MoreKeySpec.getIntValue(moreKeys, MORE_KEYS_FIXED_COLUMN_ORDER, -1)) > 0) {
|
||||||
|
// Override with fixed column order number and set a relevant mode value.
|
||||||
|
moreKeysColumnAndFlags = MORE_KEYS_MODE_FIXED_COLUMN_WITH_FIXED_ORDER
|
||||||
|
| (value & MORE_KEYS_COLUMN_NUMBER_MASK);
|
||||||
|
}
|
||||||
|
if (MoreKeySpec.getBooleanValue(moreKeys, MORE_KEYS_HAS_LABELS)) {
|
||||||
|
moreKeysColumnAndFlags |= MORE_KEYS_FLAGS_HAS_LABELS;
|
||||||
|
}
|
||||||
|
if (MoreKeySpec.getBooleanValue(moreKeys, MORE_KEYS_NEEDS_DIVIDERS)) {
|
||||||
|
moreKeysColumnAndFlags |= MORE_KEYS_FLAGS_NEEDS_DIVIDERS;
|
||||||
|
}
|
||||||
|
if (MoreKeySpec.getBooleanValue(moreKeys, MORE_KEYS_NO_PANEL_AUTO_MORE_KEY)) {
|
||||||
|
moreKeysColumnAndFlags |= MORE_KEYS_FLAGS_NO_PANEL_AUTO_MORE_KEY;
|
||||||
|
}
|
||||||
|
mMoreKeysColumnAndFlags = moreKeysColumnAndFlags;
|
||||||
|
|
||||||
|
moreKeys = MoreKeySpec.insertAdditionalMoreKeys(moreKeys, null);
|
||||||
|
int actionFlags = 0;
|
||||||
|
if (moreKeys != null) {
|
||||||
|
actionFlags |= ACTION_FLAGS_ENABLE_LONG_PRESS;
|
||||||
|
mMoreKeys = new MoreKeySpec[moreKeys.length];
|
||||||
|
for (int i = 0; i < moreKeys.length; i++) {
|
||||||
|
mMoreKeys[i] = new MoreKeySpec(moreKeys[i], false, Locale.getDefault());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mMoreKeys = null;
|
||||||
|
}
|
||||||
|
mActionFlags = actionFlags;
|
||||||
|
} else {
|
||||||
|
// TODO: Pass keyActionFlags as an argument.
|
||||||
|
mActionFlags = ACTION_FLAGS_NO_KEY_PREVIEW;
|
||||||
|
mMoreKeys = null;
|
||||||
|
mMoreKeysColumnAndFlags = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
mLabel = label;
|
||||||
|
mOptionalAttributes = OptionalAttributes.newInstance(outputText, CODE_UNSPECIFIED,
|
||||||
|
ICON_UNDEFINED, 0 /* visualInsetsLeft */, 0 /* visualInsetsRight */);
|
||||||
|
mCode = code;
|
||||||
|
mEnabled = (code != CODE_UNSPECIFIED);
|
||||||
|
mIconId = KeyboardIconsSet.ICON_UNDEFINED;
|
||||||
|
mKeyVisualAttributes = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,6 @@ import android.util.Xml;
|
||||||
import android.view.inputmethod.EditorInfo;
|
import android.view.inputmethod.EditorInfo;
|
||||||
import android.view.inputmethod.InputMethodSubtype;
|
import android.view.inputmethod.InputMethodSubtype;
|
||||||
|
|
||||||
import org.dslul.openboard.inputmethod.compat.EditorInfoCompatUtils;
|
|
||||||
import org.dslul.openboard.inputmethod.keyboard.internal.KeyboardBuilder;
|
import org.dslul.openboard.inputmethod.keyboard.internal.KeyboardBuilder;
|
||||||
import org.dslul.openboard.inputmethod.keyboard.internal.KeyboardParams;
|
import org.dslul.openboard.inputmethod.keyboard.internal.KeyboardParams;
|
||||||
import org.dslul.openboard.inputmethod.keyboard.internal.UniqueKeysCache;
|
import org.dslul.openboard.inputmethod.keyboard.internal.UniqueKeysCache;
|
||||||
|
@ -217,7 +216,7 @@ public final class KeyboardLayoutSet {
|
||||||
final KeyboardBuilder<KeyboardParams> builder =
|
final KeyboardBuilder<KeyboardParams> builder =
|
||||||
new KeyboardBuilder<>(mContext, new KeyboardParams(sUniqueKeysCache));
|
new KeyboardBuilder<>(mContext, new KeyboardParams(sUniqueKeysCache));
|
||||||
sUniqueKeysCache.setEnabled(id.isAlphabetKeyboard());
|
sUniqueKeysCache.setEnabled(id.isAlphabetKeyboard());
|
||||||
builder.setAllowRedundantMoreKes(elementParams.mAllowRedundantMoreKeys);
|
builder.setAllowRedundantMoreKeys(elementParams.mAllowRedundantMoreKeys);
|
||||||
final int keyboardXmlId = elementParams.mKeyboardXmlId;
|
final int keyboardXmlId = elementParams.mKeyboardXmlId;
|
||||||
builder.load(keyboardXmlId, id);
|
builder.load(keyboardXmlId, id);
|
||||||
if (mParams.mDisableTouchPositionCorrectionDataForTest) {
|
if (mParams.mDisableTouchPositionCorrectionDataForTest) {
|
||||||
|
|
|
@ -35,6 +35,7 @@ import org.xmlpull.v1.XmlPullParser;
|
||||||
import org.xmlpull.v1.XmlPullParserException;
|
import org.xmlpull.v1.XmlPullParserException;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
|
@ -135,10 +136,13 @@ public class KeyboardBuilder<KP extends KeyboardParams> {
|
||||||
protected final Resources mResources;
|
protected final Resources mResources;
|
||||||
|
|
||||||
private int mCurrentY = 0;
|
private int mCurrentY = 0;
|
||||||
|
// currently not used, but will be relevant when resizing a row or inserting a new key
|
||||||
|
private float mCurrentX = 0f;
|
||||||
private KeyboardRow mCurrentRow = null;
|
private KeyboardRow mCurrentRow = null;
|
||||||
private boolean mLeftEdge;
|
private boolean mLeftEdge;
|
||||||
private boolean mTopEdge;
|
private boolean mTopEdge;
|
||||||
private Key mRightEdgeKey = null;
|
private Key mRightEdgeKey = null;
|
||||||
|
private final ArrayList<ArrayList<Key.KeyParams>> keysInRows = new ArrayList<>();
|
||||||
|
|
||||||
public KeyboardBuilder(final Context context, @NonNull final KP params) {
|
public KeyboardBuilder(final Context context, @NonNull final KP params) {
|
||||||
mContext = context;
|
mContext = context;
|
||||||
|
@ -151,10 +155,15 @@ public class KeyboardBuilder<KP extends KeyboardParams> {
|
||||||
params.GRID_HEIGHT = res.getInteger(R.integer.config_keyboard_grid_height);
|
params.GRID_HEIGHT = res.getInteger(R.integer.config_keyboard_grid_height);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAllowRedundantMoreKes(final boolean enabled) {
|
public void setAllowRedundantMoreKeys(final boolean enabled) {
|
||||||
mParams.mAllowRedundantMoreKeys = enabled;
|
mParams.mAllowRedundantMoreKeys = enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// todo:
|
||||||
|
// split the parser from the builder
|
||||||
|
// parser should just setup the params (parseKeyboardAttributes)
|
||||||
|
// and return something like keysInRows
|
||||||
|
// then builder can nicely adjust the keyboard, maybe dimensions, maybe insert keys/spacers
|
||||||
public KeyboardBuilder<KP> load(final int xmlId, final KeyboardId id) {
|
public KeyboardBuilder<KP> load(final int xmlId, final KeyboardId id) {
|
||||||
mParams.mId = id;
|
mParams.mId = id;
|
||||||
try (XmlResourceParser parser = mResources.getXml(xmlId)) {
|
try (XmlResourceParser parser = mResources.getXml(xmlId)) {
|
||||||
|
@ -180,6 +189,7 @@ public class KeyboardBuilder<KP extends KeyboardParams> {
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public Keyboard build() {
|
public Keyboard build() {
|
||||||
|
addKeysToParams();
|
||||||
return new Keyboard(mParams);
|
return new Keyboard(mParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -402,6 +412,7 @@ public class KeyboardBuilder<KP extends KeyboardParams> {
|
||||||
R.styleable.Keyboard_GridRows_textsArray, 0);
|
R.styleable.Keyboard_GridRows_textsArray, 0);
|
||||||
final int moreCodesArrayId = gridRowAttr.getResourceId(
|
final int moreCodesArrayId = gridRowAttr.getResourceId(
|
||||||
R.styleable.Keyboard_GridRows_moreCodesArray, 0);
|
R.styleable.Keyboard_GridRows_moreCodesArray, 0);
|
||||||
|
// todo: read relative key width, key / row height and gaps (but they might also be absolute, see getDimensionOrFraction)
|
||||||
gridRowAttr.recycle();
|
gridRowAttr.recycle();
|
||||||
if (codesArrayId == 0 && textsArrayId == 0) {
|
if (codesArrayId == 0 && textsArrayId == 0) {
|
||||||
throw new XmlParseUtils.ParseException(
|
throw new XmlParseUtils.ParseException(
|
||||||
|
@ -429,6 +440,7 @@ public class KeyboardBuilder<KP extends KeyboardParams> {
|
||||||
for (int index = 0; index < counts; index += numColumns) {
|
for (int index = 0; index < counts; index += numColumns) {
|
||||||
final KeyboardRow row = new KeyboardRow(mResources, mParams, parser, mCurrentY);
|
final KeyboardRow row = new KeyboardRow(mResources, mParams, parser, mCurrentY);
|
||||||
startRow(row);
|
startRow(row);
|
||||||
|
final ArrayList<Key.KeyParams> keyParamsRow = keysInRows.get(keysInRows.size() - 1);
|
||||||
for (int c = 0; c < numColumns; c++) {
|
for (int c = 0; c < numColumns; c++) {
|
||||||
final int i = index + c;
|
final int i = index + c;
|
||||||
if (i >= counts) {
|
if (i >= counts) {
|
||||||
|
@ -468,9 +480,10 @@ public class KeyboardBuilder<KP extends KeyboardParams> {
|
||||||
final int width = (int)keyWidth;
|
final int width = (int)keyWidth;
|
||||||
final int height = row.getRowHeight();
|
final int height = row.getRowHeight();
|
||||||
final String hintLabel = moreKeySpecs != null ? "\u25E5" : null;
|
final String hintLabel = moreKeySpecs != null ? "\u25E5" : null;
|
||||||
final Key key = new Key(label, code, outputText, hintLabel, moreKeySpecs,
|
final Key.KeyParams key = new Key.KeyParams(label, code, outputText, hintLabel, moreKeySpecs,
|
||||||
labelFlags, backgroundType, x, y, width, height, mParams);
|
labelFlags, backgroundType, x, y, width, height, mParams);
|
||||||
endKey(key);
|
// todo: add relative width and others
|
||||||
|
keyParamsRow.add(key);
|
||||||
row.advanceXPos(keyWidth);
|
row.advanceXPos(keyWidth);
|
||||||
}
|
}
|
||||||
endRow(row);
|
endRow(row);
|
||||||
|
@ -493,14 +506,15 @@ public class KeyboardBuilder<KP extends KeyboardParams> {
|
||||||
if (TextUtils.isEmpty(keySpec)) {
|
if (TextUtils.isEmpty(keySpec)) {
|
||||||
throw new ParseException("Empty keySpec", parser);
|
throw new ParseException("Empty keySpec", parser);
|
||||||
}
|
}
|
||||||
final Key key = new Key(keySpec, keyAttr, keyStyle, mParams, row);
|
final Key.KeyParams key = new Key.KeyParams(keySpec, keyAttr, keyStyle, mParams, row);
|
||||||
keyAttr.recycle();
|
keyAttr.recycle();
|
||||||
|
// todo: add relative width and others
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
startEndTag("<%s%s %s moreKeys=%s />", TAG_KEY, (key.isEnabled() ? "" : " disabled"),
|
startEndTag("<%s%s %s moreKeys=%s />", TAG_KEY, (key.mEnabled ? "" : " disabled"),
|
||||||
key, Arrays.toString(key.getMoreKeys()));
|
key, Arrays.toString(key.mMoreKeys));
|
||||||
}
|
}
|
||||||
XmlParseUtils.checkEndTag(TAG_KEY, parser);
|
XmlParseUtils.checkEndTag(TAG_KEY, parser);
|
||||||
endKey(key);
|
keysInRows.get(keysInRows.size() - 1).add(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void parseSpacer(final XmlPullParser parser, final KeyboardRow row, final boolean skip)
|
private void parseSpacer(final XmlPullParser parser, final KeyboardRow row, final boolean skip)
|
||||||
|
@ -513,11 +527,12 @@ public class KeyboardBuilder<KP extends KeyboardParams> {
|
||||||
final TypedArray keyAttr = mResources.obtainAttributes(
|
final TypedArray keyAttr = mResources.obtainAttributes(
|
||||||
Xml.asAttributeSet(parser), R.styleable.Keyboard_Key);
|
Xml.asAttributeSet(parser), R.styleable.Keyboard_Key);
|
||||||
final KeyStyle keyStyle = mParams.mKeyStyles.getKeyStyle(keyAttr, parser);
|
final KeyStyle keyStyle = mParams.mKeyStyles.getKeyStyle(keyAttr, parser);
|
||||||
final Key spacer = new Key.Spacer(keyAttr, keyStyle, mParams, row);
|
final Key.KeyParams spacer = Key.KeyParams.newSpacer(keyAttr, keyStyle, mParams, row);
|
||||||
keyAttr.recycle();
|
keyAttr.recycle();
|
||||||
|
// todo: add relative width and others
|
||||||
|
keysInRows.get(keysInRows.size() - 1).add(spacer);
|
||||||
if (DEBUG) startEndTag("<%s />", TAG_SPACER);
|
if (DEBUG) startEndTag("<%s />", TAG_SPACER);
|
||||||
XmlParseUtils.checkEndTag(TAG_SPACER, parser);
|
XmlParseUtils.checkEndTag(TAG_SPACER, parser);
|
||||||
endKey(spacer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void parseIncludeKeyboardContent(final XmlPullParser parser, final boolean skip)
|
private void parseIncludeKeyboardContent(final XmlPullParser parser, final boolean skip)
|
||||||
|
@ -861,6 +876,13 @@ public class KeyboardBuilder<KP extends KeyboardParams> {
|
||||||
mCurrentRow = row;
|
mCurrentRow = row;
|
||||||
mLeftEdge = true;
|
mLeftEdge = true;
|
||||||
mRightEdgeKey = null;
|
mRightEdgeKey = null;
|
||||||
|
keysInRows.add(new ArrayList<>());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startRowNew() {
|
||||||
|
addEdgeSpaceNew(mParams.mLeftPadding);
|
||||||
|
mLeftEdge = true;
|
||||||
|
mRightEdgeKey = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void endRow(final KeyboardRow row) {
|
private void endRow(final KeyboardRow row) {
|
||||||
|
@ -877,6 +899,18 @@ public class KeyboardBuilder<KP extends KeyboardParams> {
|
||||||
mTopEdge = false;
|
mTopEdge = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void endRowNew() {
|
||||||
|
int lastKeyHeight = 0;
|
||||||
|
if (mRightEdgeKey != null) {
|
||||||
|
mRightEdgeKey.markAsRightEdge(mParams);
|
||||||
|
lastKeyHeight = mRightEdgeKey.getHeight() + mRightEdgeKey.getVerticalGap();
|
||||||
|
mRightEdgeKey = null;
|
||||||
|
}
|
||||||
|
addEdgeSpaceNew(mParams.mRightPadding);
|
||||||
|
mCurrentY += lastKeyHeight;
|
||||||
|
mTopEdge = false;
|
||||||
|
}
|
||||||
|
|
||||||
private void endKey(@NonNull final Key key) {
|
private void endKey(@NonNull final Key key) {
|
||||||
mParams.onAddKey(key);
|
mParams.onAddKey(key);
|
||||||
if (mLeftEdge) {
|
if (mLeftEdge) {
|
||||||
|
@ -897,12 +931,33 @@ public class KeyboardBuilder<KP extends KeyboardParams> {
|
||||||
mParams.mOccupiedHeight = Math.max(mParams.mOccupiedHeight, actualHeight);
|
mParams.mOccupiedHeight = Math.max(mParams.mOccupiedHeight, actualHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void addKeysToParams() {
|
||||||
|
// need to reset it, we need to sum it up to get the height nicely
|
||||||
|
// (though in the end we could just not touch it at all, final used value is the same as the one before resetting)
|
||||||
|
mCurrentY = 0;
|
||||||
|
startKeyboard();
|
||||||
|
for (ArrayList<Key.KeyParams> row : keysInRows) {
|
||||||
|
startRowNew();
|
||||||
|
for (Key.KeyParams keyParams : row) {
|
||||||
|
endKey(keyParams.createKey());
|
||||||
|
}
|
||||||
|
endRowNew();
|
||||||
|
}
|
||||||
|
endKeyboard();
|
||||||
|
}
|
||||||
|
|
||||||
private void addEdgeSpace(final float width, final KeyboardRow row) {
|
private void addEdgeSpace(final float width, final KeyboardRow row) {
|
||||||
row.advanceXPos(width);
|
row.advanceXPos(width);
|
||||||
mLeftEdge = false;
|
mLeftEdge = false;
|
||||||
mRightEdgeKey = null;
|
mRightEdgeKey = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void addEdgeSpaceNew(final float width) {
|
||||||
|
mCurrentX += width;
|
||||||
|
mLeftEdge = false;
|
||||||
|
mRightEdgeKey = null;
|
||||||
|
}
|
||||||
|
|
||||||
private static String textAttr(final String value, final String name) {
|
private static String textAttr(final String value, final String name) {
|
||||||
return value != null ? String.format(" %s=%s", name, value) : "";
|
return value != null ? String.format(" %s=%s", name, value) : "";
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue