package org.geogebra.keyboard.base.model.impl.factory;
import org.geogebra.keyboard.base.Accents;
import org.geogebra.keyboard.base.Action;
import org.geogebra.keyboard.base.Background;
import org.geogebra.keyboard.base.Resource;
import org.geogebra.keyboard.base.model.KeyboardModel;
import org.geogebra.keyboard.base.model.impl.KeyboardModelImpl;
import org.geogebra.keyboard.base.model.impl.RowImpl;
import static org.geogebra.keyboard.base.model.impl.factory.Characters.AMPERSAND;
import static org.geogebra.keyboard.base.model.impl.factory.Characters.HASHTAG;
import static org.geogebra.keyboard.base.model.impl.factory.Characters.NOT_SIGN;
import static org.geogebra.keyboard.base.model.impl.factory.Util.addButton;
import static org.geogebra.keyboard.base.model.impl.factory.Util.addConstantCustomButton;
import static org.geogebra.keyboard.base.model.impl.factory.Util.addCustomButton;
import static org.geogebra.keyboard.base.model.impl.factory.Util.addInputButton;
class LetterKeyboardFactory {
private static final double MIN_PADDING_WEIGHT = 1.e-4;
private static final String EXCEPTION_MESSAGE = "Deformed keyboard definition with long bottom row.";
KeyboardModel createLetterKeyboard(ButtonFactory buttonFactory, String topRow, String middleRow,
String bottomRow) {
return createLetterKeyboard(buttonFactory, topRow, middleRow, bottomRow, true);
}
KeyboardModel createLetterKeyboard(ButtonFactory buttonFactory, String topRow, String middleRow,
String bottomRow, boolean withSpecialSymbols) {
int topRowLength = topRow.length();
int middleRowLength = middleRow.length();
int bottomRowLength = bottomRow.length();
// sanity checks
if (bottomRowLength > topRowLength - 1 && bottomRowLength > middleRowLength - 1) {
throw new RuntimeException(EXCEPTION_MESSAGE);
}
int rowWeightSum;
if (topRowLength == middleRowLength && middleRowLength - 1 == bottomRowLength) {
rowWeightSum = middleRowLength + 1;
} else {
rowWeightSum = Math.max(topRowLength, middleRowLength);
}
float topRowPadding = (rowWeightSum - topRowLength) / 2.0f;
float middleRowPadding = (rowWeightSum - middleRowLength) / 2.0f;
float actionButtonSize;
float actionButtonMargin;
if (rowWeightSum - bottomRowLength == 2) {
actionButtonSize = 1.0f;
actionButtonMargin = 0.0f;
} else if (rowWeightSum - bottomRowLength > 2) {
actionButtonSize = 1.2f;
actionButtonMargin = (rowWeightSum - bottomRowLength - 2.4f) / 2.0f;
} else {
throw new RuntimeException(EXCEPTION_MESSAGE);
}
float spaceSize = rowWeightSum - 5;
StringBuilder builder = new StringBuilder();
KeyboardModelImpl letterKeyboard = new KeyboardModelImpl();
createRow(letterKeyboard, buttonFactory, topRow, rowWeightSum, topRowPadding);
createRow(letterKeyboard, buttonFactory, middleRow, rowWeightSum, middleRowPadding);
RowImpl bottomRowImpl = letterKeyboard.nextRow(rowWeightSum);
addConstantCustomButton(bottomRowImpl, buttonFactory, Resource.CAPS_LOCK, Action.CAPS_LOCK, actionButtonSize);
addButton(bottomRowImpl, buttonFactory.createEmptySpace(actionButtonMargin));
addButtons(bottomRowImpl, buttonFactory, bottomRow);
addButton(bottomRowImpl, buttonFactory.createEmptySpace(actionButtonMargin));
addConstantCustomButton(bottomRowImpl, buttonFactory, Resource.BACKSPACE_DELETE, Action.BACKSPACE_DELETE, actionButtonSize);
RowImpl controlRow = letterKeyboard.nextRow(rowWeightSum);
if (withSpecialSymbols) {
builder.append(HASHTAG);
builder.append(AMPERSAND);
builder.append(NOT_SIGN);
addCustomButton(controlRow, buttonFactory, builder.toString(), Action.SWITCH_TO_SPECIAL_SYMBOLS);
spaceSize -= 1;
}
addInputButton(controlRow, buttonFactory, ",");
addInputButton(controlRow, buttonFactory, "'");
addInputButton(controlRow, buttonFactory, " ", spaceSize);
addConstantCustomButton(controlRow, buttonFactory, Resource.LEFT_ARROW, Action.LEFT_CURSOR);
addConstantCustomButton(controlRow, buttonFactory, Resource.RIGHT_ARROW, Action.RIGHT_CURSOR);
addConstantCustomButton(controlRow, buttonFactory, Resource.RETURN_ENTER, Action.RETURN_ENTER);
return letterKeyboard;
}
private void createRow(KeyboardModelImpl keyboard, ButtonFactory buttonFactory, String definition, float rowWeightSum, float rowPadding) {
RowImpl rowImpl = keyboard.nextRow(rowWeightSum);
addPaddingIfNecessary(rowImpl, buttonFactory, rowPadding);
addButtons(rowImpl, buttonFactory, definition);
addPaddingIfNecessary(rowImpl, buttonFactory, rowPadding);
}
private void addButtons(RowImpl rowImpl, ButtonFactory buttonFactory, String definition) {
for (int i = 0; i < definition.length(); i++) {
addButtonCharacter(rowImpl, buttonFactory, definition.charAt(i));
}
}
private void addButtonCharacter(RowImpl rowImpl, ButtonFactory buttonFactory, char character) {
String resource = String.valueOf(character);
switch (resource) {
case Accents.ACCENT_ACUTE:
addCustomButton(rowImpl, buttonFactory, resource, Action.TOGGLE_ACCENT_ACUTE.name(), Background.STANDARD);
break;
case Accents.ACCENT_CARON:
addCustomButton(rowImpl, buttonFactory, resource, Action.TOGGLE_ACCENT_CARON.name(), Background.STANDARD);
break;
case Accents.ACCENT_CIRCUMFLEX:
addCustomButton(rowImpl, buttonFactory, resource, Action.TOGGLE_ACCENT_CIRCUMFLEX.name(), Background.STANDARD);
break;
case Accents.ACCENT_GRAVE:
addCustomButton(rowImpl, buttonFactory, resource, Action.TOGGLE_ACCENT_GRAVE.name(), Background.STANDARD);
break;
default:
addInputButton(rowImpl, buttonFactory, resource);
}
}
private void addPaddingIfNecessary(RowImpl rowImpl, ButtonFactory buttonFactory, float paddingWeight) {
if (paddingWeight > MIN_PADDING_WEIGHT) {
addButton(rowImpl, buttonFactory.createEmptySpace(paddingWeight));
}
}
}