package org.geogebra.web.keyboard;
import org.geogebra.common.euclidian.event.PointerEventType;
import org.geogebra.keyboard.web.ButtonHandler;
import org.geogebra.keyboard.web.HasKeyboard;
import org.geogebra.keyboard.web.KeyBoardButtonBase;
import org.geogebra.keyboard.web.KeyBoardButtonFunctionalBase;
import org.geogebra.keyboard.web.KeyboardListener;
import org.geogebra.keyboard.web.KeyboardListener.ArrowType;
import org.geogebra.keyboard.web.TabbedKeyboard;
import org.geogebra.web.html5.gui.GPopupPanel;
import org.geogebra.web.html5.gui.GuiManagerInterfaceW;
import org.geogebra.web.html5.gui.tooltip.ToolTipManagerW;
import org.geogebra.web.html5.gui.util.ClickStartHandler;
import org.geogebra.web.html5.main.AppW;
import org.geogebra.web.web.gui.inputbar.InputBarHelpPanelW;
import org.geogebra.web.web.gui.inputbar.InputBarHelpPopup;
import org.geogebra.web.web.gui.util.VirtualKeyboardGUI;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.event.logical.shared.CloseEvent;
import com.google.gwt.event.logical.shared.CloseHandler;
/**
* Web implementation of onscreen keyboard
*
* @author Zbynek, based on Balaz's cross-platform model
*/
public class OnscreenTabbedKeyboard extends TabbedKeyboard
implements VirtualKeyboardGUI, ButtonHandler {
private KeyboardListener processField;
private InputBarHelpPopup helpPopup=null;
/**
* @param app
* keyboard context
*/
public OnscreenTabbedKeyboard(HasKeyboard app) {
buildGUI(this, app);
ClickStartHandler.init(this, new ClickStartHandler(true, true) {
@Override
public void onClickStart(int x, int y, PointerEventType type) {
// just stop propagation
}
});
}
private void createHelpPopup() {
if (helpPopup != null) {
return;
}
helpPopup = new InputBarHelpPopup((AppW)app, null,
"helpPopupAV");
helpPopup.addAutoHidePartner(this.getElement());
helpPopup.addCloseHandler(new CloseHandler<GPopupPanel>() {
@Override
public void onClose(CloseEvent<GPopupPanel> event) {
// TODO handle closing?
}
});
}
public void show() {
this.keyboardWanted = true;
checkLanguage();
setVisible(true);
}
public void resetKeyboardState() {
// TODO Auto-generated method stub
}
public void setStyleName() {
// TODO Auto-generated method stub
}
public void endEditing() {
if (processField != null) {
processField.endEditing();
}
}
public void setProcessing(KeyboardListener field) {
if (processField != null && processField.getField() != null) {
if (field == null || processField.getField() != field.getField()) {
endEditing();
}
}
this.processField = field;
}
@Override
public void onClick(KeyBoardButtonBase btn, PointerEventType type) {
ToolTipManagerW.hideAllToolTips();
if (processField == null) {
return;
}
if (btn instanceof KeyBoardButtonFunctionalBase
&& ((KeyBoardButtonFunctionalBase) btn).getAction() != null) {
KeyBoardButtonFunctionalBase button = (KeyBoardButtonFunctionalBase) btn;
switch (button.getAction()) {
case CAPS_LOCK:
// removeAccents();
processShift();
break;
case BACKSPACE_DELETE:
processField.onBackSpace();
break;
case RETURN_ENTER:
// make sure enter is processed correctly
processField.onEnter();
if (processField.resetAfterEnter()) {
getUpdateKeyBoardListener().keyBoardNeeded(false, null);
}
break;
case LEFT_CURSOR:
processField.onArrow(ArrowType.left);
break;
case RIGHT_CURSOR:
processField.onArrow(ArrowType.right);
break;
case SWITCH_TO_SPECIAL_SYMBOLS:
selectSpecial();
break;
case SWITCH_TO_ABC:
selectAbc();
break;
case SWITCH_KEYBOARD:
// String caption = button.getCaption();
// if (caption.equals(GREEK)) {
// setToGreekLetters();
// } else if (caption.equals(NUMBER)) {
// setKeyboardMode(KeyboardMode.NUMBER);
// } else if (caption.equals(TEXT)) {
// if (greekActive) {
// greekActive = false;
// switchABCGreek.setCaption(GREEK);
// updateKeys("lowerCase", this.keyboardLocale);
// setStyleName();
// }
// if (shiftIsDown) {
// processShift();
// }
// if (accentDown) {
// removeAccents();
// }
// setKeyboardMode(KeyboardMode.TEXT);
// } else if (caption.equals(SPECIAL_CHARS)) {
// setKeyboardMode(KeyboardMode.SPECIAL_CHARS);
// } else if (caption.equals(PAGE_ONE_OF_TWO)) {
// showSecondPage();
// } else if (caption.equals(PAGE_TWO_OF_TWO)) {
// showFirstPage();
// }
}
} else {
String text = btn.getFeedback();
if (isAccent(text)) {
processAccent(text);
} else {
processField
.insertString(app.getLocalization().getCommand(text)); // TODO
processAccent(null);
disableCapsLock();
}
// if (isAccent(text)) {
// processAccent(text, btn);
// } else {
// processField.insertString(text);
// if (accentDown) {
// removeAccents();
// }
// }
//
// if (shiftIsDown && !isAccent(text)) {
// processShift();
// }
processField.setFocus(true);
}
Scheduler.get().scheduleDeferred(new Scheduler.ScheduledCommand() {
@Override
public void execute() {
Scheduler.get()
.scheduleDeferred(new Scheduler.ScheduledCommand() {
@Override
public void execute() {
scrollCursorIntoView();
}
});
}
});
}
/**
* Scroll cursor of selected textfield into view
*/
protected void scrollCursorIntoView() {
processField.scrollCursorIntoView();
}
public void afterShown(final Runnable runnable) {
runOnAnimation(runnable, getElement());
}
private native void runOnAnimation(Runnable runnable,
com.google.gwt.dom.client.Element root) /*-{
var callback = function() {
root.className = root.className.replace(/animating/, "");
runnable.@java.lang.Runnable::run()();
};
if ((root.style.animation || root.style.animation === "")
&& root.className.match(/animating/)) {
root.addEventListener("animationend", callback);
return;
}
window.setTimeout(callback, 0);
}-*/;
public void prepareShow(boolean animated) {
if (animated) {
addStyleName("animating");
}
show();
}
public void remove(final Runnable runnable) {
app.updateCenterPanelAndViews();
this.addStyleName("animatingOut");
runOnAnimation(new Runnable() {
public void run() {
removeFromParent();
runnable.run();
}
}, getElement());
}
public boolean hasTouchFeedback() {
return true;
}
@Override
protected void showHelp(int x, int y) {
boolean show = helpPopup != null && helpPopup.isShowing();
if (!show) {
createHelpPopup();
GuiManagerInterfaceW gm = ((AppW)app).getGuiManager();
InputBarHelpPanelW helpPanel = (InputBarHelpPanelW)(gm.getInputHelpPanel());
updateHelpPosition(helpPanel, x, y);
} else if (helpPopup != null) {
helpPopup.hide();
}
}
private void updateHelpPosition(final InputBarHelpPanelW helpPanel,
final int x, final int y) {
helpPopup.setPopupPositionAndShow(new GPopupPanel.PositionCallback() {
@Override
public void setPosition(int offsetWidth, int offsetHeight) {
doUpdateHelpPosition(helpPanel, x, y, offsetWidth,
offsetHeight);
}
});
}
/**
* @param helpPanel
* help panel
* @param x
* popup x-coord
* @param y
* popup y-coord
* @param offsetWidth
* panel width
* @param offsetHeight
* panel height
*/
protected void doUpdateHelpPosition(final InputBarHelpPanelW helpPanel,
final int x, final int y, int offsetWidth, int offsetHeight) {
AppW appw = (AppW) app;
double scale = appw.getArticleElement().getScaleX();
double renderScale = appw.getArticleElement().getDataParamApp() ? scale
: 1;
double left = x - appw.getAbsLeft()
- helpPanel.getPreferredWidth(scale);
helpPopup.getElement().getStyle().setProperty("left",
left * renderScale + "px");
int maxOffsetHeight;
int totalHeight = (int) appw.getHeight();
int toggleButtonTop = (int) ((y - (int) appw.getAbsTop()) / scale);
if (toggleButtonTop < totalHeight / 2) {
int top = (toggleButtonTop);
maxOffsetHeight = totalHeight - top;
helpPopup.getElement().getStyle().setProperty("top",
top * renderScale + "px");
helpPopup.getElement().getStyle().setProperty("bottom", "auto");
helpPopup.removeStyleName("helpPopupAVBottom");
helpPopup.addStyleName("helpPopupAV");
} else {
int minBottom = appw.isApplet() ? 0 : 10;
int bottom = (totalHeight - toggleButtonTop);
maxOffsetHeight = bottom > 0 ? totalHeight - bottom
: totalHeight - minBottom;
helpPopup.getElement().getStyle().setProperty("bottom",
(bottom > 0 ? bottom : minBottom) * renderScale + "px");
helpPopup.getElement().getStyle().setProperty("top", "auto");
helpPopup.removeStyleName("helpPopupAV");
helpPopup.addStyleName("helpPopupAVBottom");
}
helpPanel.updateGUI(maxOffsetHeight, 1);
helpPopup.show();
}
}