package org.geogebra.web.geogebra3D.web.euclidian3D;
import java.util.HashMap;
import org.geogebra.common.awt.GDimension;
import org.geogebra.common.awt.GFont;
import org.geogebra.common.awt.GGraphics2D;
import org.geogebra.common.euclidian.EuclidianController;
import org.geogebra.common.euclidian.EuclidianStyleBar;
import org.geogebra.common.euclidian.EuclidianView;
import org.geogebra.common.euclidian.MyZoomer;
import org.geogebra.common.euclidian.event.PointerEventType;
import org.geogebra.common.geogebra3D.euclidian3D.EuclidianController3D;
import org.geogebra.common.geogebra3D.euclidian3D.EuclidianView3D;
import org.geogebra.common.geogebra3D.euclidian3D.openGL.Renderer;
import org.geogebra.common.javax.swing.GBox;
import org.geogebra.common.kernel.Kernel;
import org.geogebra.common.kernel.geos.GeoElement;
import org.geogebra.common.kernel.geos.GeoText;
import org.geogebra.common.main.Feature;
import org.geogebra.common.main.settings.EuclidianSettings;
import org.geogebra.common.util.debug.GeoGebraProfiler;
import org.geogebra.common.util.debug.Log;
import org.geogebra.web.geogebra3D.web.euclidian3D.openGL.RendererWInterface;
import org.geogebra.web.geogebra3D.web.euclidian3D.openGL.RendererWithImplW;
import org.geogebra.web.html5.Browser;
import org.geogebra.web.html5.awt.GGraphics2DW;
import org.geogebra.web.html5.euclidian.EuclidianPanelWAbstract;
import org.geogebra.web.html5.euclidian.EuclidianViewW;
import org.geogebra.web.html5.euclidian.EuclidianViewWInterface;
import org.geogebra.web.html5.euclidian.IsEuclidianController;
import org.geogebra.web.html5.euclidian.PointerEventHandler;
import org.geogebra.web.html5.euclidian.MyEuclidianViewPanel;
import org.geogebra.web.html5.gui.util.ClickStartHandler;
import org.geogebra.web.html5.javax.swing.GBoxW;
import org.geogebra.web.html5.main.AppW;
import org.geogebra.web.html5.main.GlobalKeyDispatcherW;
import org.geogebra.web.html5.main.TimerSystemW;
import com.google.gwt.animation.client.AnimationScheduler;
import com.google.gwt.canvas.client.Canvas;
import com.google.gwt.dom.client.Style;
import com.google.gwt.event.dom.client.BlurEvent;
import com.google.gwt.event.dom.client.BlurHandler;
import com.google.gwt.event.dom.client.FocusEvent;
import com.google.gwt.event.dom.client.FocusHandler;
import com.google.gwt.event.dom.client.GestureChangeEvent;
import com.google.gwt.event.dom.client.GestureEndEvent;
import com.google.gwt.event.dom.client.GestureStartEvent;
import com.google.gwt.event.dom.client.MouseDownEvent;
import com.google.gwt.event.dom.client.MouseMoveEvent;
import com.google.gwt.event.dom.client.MouseOutEvent;
import com.google.gwt.event.dom.client.MouseOverEvent;
import com.google.gwt.event.dom.client.MouseUpEvent;
import com.google.gwt.event.dom.client.MouseWheelEvent;
import com.google.gwt.event.dom.client.TouchCancelEvent;
import com.google.gwt.event.dom.client.TouchEndEvent;
import com.google.gwt.event.dom.client.TouchMoveEvent;
import com.google.gwt.event.dom.client.TouchStartEvent;
import com.google.gwt.event.logical.shared.AttachEvent;
import com.google.gwt.user.client.ui.RequiresResize;
import com.google.gwt.user.client.ui.Widget;
/**
* 3D view
*
* @author mathieu
*
*/
public class EuclidianView3DW extends EuclidianView3D implements
EuclidianViewWInterface {
private EuclidianPanelWAbstract EVPanel;
private boolean isInFocus = false;
/** graphics */
public GGraphics2DW g2p = null;
private PointerEventHandler pointerHandler;
/**
* constructor
*
* @param ec
* euclidian controller
* @param settings
* euclidian settings
*/
public EuclidianView3DW(EuclidianController3D ec, EuclidianSettings settings) {
super(ec, settings);
initBaseComponents(EVPanel, ec);
// initView(true);
getRenderer().init();
ClickStartHandler.init(g2p.getCanvas(), new ClickStartHandler() {
@Override
public void onClickStart(int x, int y, PointerEventType type) {
((AppW) getApplication()).closePopups();
}
});
}
private void initBaseComponents(EuclidianPanelWAbstract euclidianViewPanel,
EuclidianController euclidiancontroller) {
Canvas canvas = euclidianViewPanel.getCanvas();
setEvNo();
this.g2p = new GGraphics2DW(canvas);
g2p.setView(this);
updateFonts();
initView(true);
attachView();
((EuclidianController3DW) euclidiancontroller).setView(this);
registerKeyHandlers(canvas);
registerMouseTouchGestureHandlers(euclidianViewPanel,
(EuclidianController3DW) euclidiancontroller);
updateFirstAndLast(true, true);
canvas.addAttachHandler(new AttachEvent.Handler() {
@Override
public void onAttachOrDetach(AttachEvent ae) {
// see attach handler of EuclidianViewW
updateFirstAndLast(ae.isAttached(), false);
}
});
canvas.addBlurHandler(new BlurHandler() {
@Override
public void onBlur(BlurEvent be) {
focusLost();
EuclidianViewW.cycle(EuclidianView3DW.this);
}
});
canvas.addFocusHandler(new FocusHandler() {
@Override
public void onFocus(FocusEvent fe) {
focusGained();
EuclidianViewW.selectNextGeoOnTab(EuclidianView3DW.this);
}
});
EuclidianSettings es = this.app.getSettings().getEuclidian(3);
settingsChanged(es);
es.addListener(this);
}
@Override
public void updateFirstAndLast(boolean attach, boolean anyway) {
if (attach) {
EuclidianViewW.updateFirstAndLast(this, anyway);
} else {
// ?
}
}
private void setEvNo() {
this.evNo = EVNO_3D;
}
@Override
public void setEuclidianViewNo(int evNo) {
this.evNo = evNo;
// this.g2p.getCanvas().getElement().setId("View_"+App.VIEW_EUCLIDIAN3D);
}
private void registerKeyHandlers(Canvas canvas) {
GlobalKeyDispatcherW gkd = ((AppW) this.app).getGlobalKeyDispatcher();
canvas.addKeyDownHandler(gkd);
canvas.addKeyUpHandler(gkd);
canvas.addKeyPressHandler(gkd);
}
private void registerMouseTouchGestureHandlers(
EuclidianPanelWAbstract euclidianViewPanel,
EuclidianController3DW euclidiancontroller) {
Widget evPanel = euclidianViewPanel.getAbsolutePanel();
evPanel.addDomHandler(euclidiancontroller, MouseWheelEvent.getType());
if (!Browser.supportsPointerEvents(app.has(Feature.PEN_EVENTS))
|| !app.has(Feature.PEN_EVENTS)) {
evPanel.addDomHandler(euclidiancontroller,
MouseMoveEvent.getType());
evPanel.addDomHandler(euclidiancontroller,
MouseOverEvent.getType());
evPanel.addDomHandler(euclidiancontroller, MouseOutEvent.getType());
if (((AppW) app).getLAF() == null
|| !((AppW) app).getLAF().isSmart()) {
evPanel.addDomHandler(euclidiancontroller,
MouseDownEvent.getType());
}
evPanel.addDomHandler(euclidiancontroller, MouseUpEvent.getType());
}
if (Browser.supportsPointerEvents(app.has(Feature.PEN_EVENTS))) {
pointerHandler = new PointerEventHandler((IsEuclidianController) euclidianController,
euclidiancontroller.getOffsets());
PointerEventHandler.attachTo(evPanel.getElement(), pointerHandler,
app.has(Feature.PEN_EVENTS));
return;
}
evPanel.addDomHandler(euclidiancontroller, TouchStartEvent.getType());
evPanel.addDomHandler(euclidiancontroller, TouchEndEvent.getType());
evPanel.addDomHandler(euclidiancontroller, TouchMoveEvent.getType());
evPanel.addDomHandler(euclidiancontroller, TouchCancelEvent.getType());
evPanel.addDomHandler(euclidiancontroller, GestureStartEvent.getType());
evPanel.addDomHandler(euclidiancontroller, GestureChangeEvent.getType());
evPanel.addDomHandler(euclidiancontroller, GestureEndEvent.getType());
}
/**
* Callback for blur event
*/
public void focusLost() {
if (isInFocus) {
this.isInFocus = false;
if (getCanvas() != null) {
((AppW) this.app).focusLost(this, getCanvas().getElement());
}
}
}
/**
* Callback for focus event
*/
public void focusGained() {
if (!isInFocus) {
this.isInFocus = true;
if (getCanvas() != null) {
((AppW) this.app).focusGained(this, getCanvas().getElement());
}
}
}
@Override
public boolean isInFocus() {
return isInFocus;
}
/**
* @return panel component
*/
public Widget getComponent() {
return EVPanel.getAbsolutePanel();
}
// //////////////////////////////////////////////////////////
// MyEuclidianViewPanel
// //////////////////////////////////////////////////////////
/**
* @return EV panel
*/
protected MyEuclidianViewPanel newMyEuclidianViewPanel() {
return new MyEuclidianViewPanel3D(this);
}
/**
* panel for 3D
*
* @author mathieu
*
*/
private class MyEuclidianViewPanel3D extends MyEuclidianViewPanel implements
RequiresResize {
private Renderer pRenderer;
/**
* constructor
*
* @param ev
* euclidian view
*/
public MyEuclidianViewPanel3D(EuclidianView ev) {
super(ev);
}
@Override
protected void createCanvas() {
pRenderer = getRenderer();
canvas = (Canvas) pRenderer.getCanvas();
}
@Override
public void onResize() {
super.onResize();
getEuclidianController().calculateEnvironment();
}
}
private boolean readyToRender = false;
/**
* tells the view that all is ready for GL rendering
*/
public void setReadyToRender() {
readyToRender = true;
repaintView();
}
@Override
public void setToolTipText(String plainTooltip) {
// TODO Auto-generated method stub
}
@Override
public boolean hasFocus() {
// TODO Auto-generated method stub
return false;
}
@Override
public void requestFocus() {
// this may be really necessary preventing a tabbing away issue
// but the reasons of it are not well understood #5158
// after better understanding, this can probably be merged
// with the following method (requestFocusInWindow()):
requestFocusInWindow();
}
/**
* Gets the coordinate space width of the <canvas>.
*
* @return the logical width
*/
@Override
public int getWidth() {
return (int) (this.g2p.getCoordinateSpaceWidth() / getPixelRatio());
}
/**
* Gets the coordinate space height of the <canvas>.
*
* @return the logical height
*/
@Override
public int getHeight() {
return (int) (this.g2p.getCoordinateSpaceHeight() / getPixelRatio());
}
@Override
public final boolean isShowing() {
return g2p != null && g2p.getCanvas() != null
&& g2p.getCanvas().isAttached() && g2p.getCanvas().isVisible();
}
@Override
protected void createPanel() {
EVPanel = newMyEuclidianViewPanel();
}
@Override
protected Renderer createRenderer() {
return new RendererWithImplW(this);
}
@Override
protected boolean getShiftDown() {
// TODO Auto-generated method stub
return false;
}
@Override
protected void setDefault2DCursor() {
setCursorClass("cursor_hit");
}
@Override
public GGraphics2D getTempGraphics2D(GFont fontForGraphics) {
// TODO Auto-generated method stub
return null;
}
@Override
public GFont getFont() {
// TODO Auto-generated method stub
return null;
}
@Override
protected void setHeight(int h) {
// TODO: not clear what should we do
}
@Override
protected void setWidth(int h) {
// TODO: not clear what should we do
}
@Override
final protected void setStyleBarMode(int mode) {
if (hasStyleBar()) {
getStyleBar().setMode(mode);
}
}
@Override
protected void updateSizeKeepDrawables() {
// TODO Auto-generated method stub
}
@Override
public boolean requestFocusInWindow() {
g2p.getCanvas().getCanvasElement().focus();
focusGained();
return true;
}
@Override
public void setPreferredSize(GDimension preferredSize) {
if (renderer != null) {
((RendererWInterface) renderer).setPixelRatio(getPixelRatio());
renderer.setView(0, 0, preferredSize.getWidth(),
preferredSize.getHeight());
}
if (g2p != null && g2p.getContext() != null) {
g2p.setPreferredSize(preferredSize);
updateSize();
setReIniting(false);
}
}
@Override
public double getPixelRatio() {
if (((AppW) app).getArticleElement().disableHiRes3D()) {
return 1;
}
return ((AppW) app).getPixelRatio();
}
@Override
protected MyZoomer newZoomer() {
// TODO Auto-generated method stub
return null;
}
@Override
public void add(GBox box) {
if (EVPanel != null) {
EVPanel.getAbsolutePanel().add(GBoxW.getImpl(box),
(int) box.getBounds().getX(), (int) box.getBounds().getY());
}
}
@Override
public void remove(GBox box) {
if (EVPanel != null) {
EVPanel.getAbsolutePanel().remove(GBoxW.getImpl(box));
}
}
private void setCursorClass(String className) {
// IMPORTANT: do nothing if we already have the classname,
// app.resetCursor is VERY expensive in IE
Canvas canvas = (Canvas) this.getRenderer().getCanvas();
if (!canvas.getElement().hasClassName(className)) {
((AppW) this.app).resetCursor();
canvas.setStyleName("");
canvas.addStyleName(className);
}
}
@Override
public void setTransparentCursor() {
setCursorClass("cursor_transparent");
}
@Override
protected EuclidianStyleBar newEuclidianStyleBar() {
return new EuclidianStyleBar3DW(this);
}
@Override
public int getAbsoluteTop() {
return g2p.getAbsoluteTop();
}
@Override
public int getAbsoluteLeft() {
return g2p.getAbsoluteLeft();
}
@Override
public Canvas getCanvas() {
return g2p.getCanvas();
}
/**
* the file has been set by the App
*
* @param file
* file
*/
public void setCurrentFile(HashMap<String, String> file) {
// used only when no webGL
}
private AnimationScheduler.AnimationCallback repaintCallback = new AnimationScheduler.AnimationCallback() {
@Override
public void execute(double ts) {
doRepaint2();
}
};
private AnimationScheduler repaintScheduler = AnimationScheduler.get();
private long lastRepaint;
/**
* This doRepaint method should be used instead of repaintView in cases when
* the repaint should be done immediately
*/
public final void doRepaint2() {
long time = System.currentTimeMillis();
// ((DrawEquationWeb) this.app.getDrawEquation()).clearLaTeXes(this);
this.updateBackgroundIfNecessary();
// paint(this.g2p);
if (readyToRender) {
renderer.drawScene();
}
getEuclidianController().setCollectedRepaints(false);
lastRepaint = System.currentTimeMillis() - time;
GeoGebraProfiler.addRepaint(lastRepaint);
if (waitForNewRepaint) {
kernel.notifyControllersMoveIfWaiting();
waitForRepaint = TimerSystemW.EUCLIDIAN_LOOPS;
} else {
waitForRepaint = TimerSystemW.SLEEPING_FLAG;
}
}
@Override
public long getLastRepaintTime() {
return lastRepaint;
}
@Override
public void repaint() {
// if (readyToRender){
// renderer.drawScene();
// }
if (getEuclidianController().isCollectingRepaints()) {
getEuclidianController().setCollectedRepaints(true);
return;
}
getApplication().ensureTimerRunning();
if (waitForRepaint == TimerSystemW.SLEEPING_FLAG) {
waitForRepaint = TimerSystemW.EUCLIDIAN_LOOPS;
}
}
@Override
final public void waitForNewRepaint() {
waitForNewRepaint = true;
}
private int waitForRepaint = TimerSystemW.SLEEPING_FLAG;
private boolean waitForNewRepaint = false;
/**
* schedule a repaint
*/
public void doRepaint() {
repaintScheduler.requestAnimationFrame(repaintCallback);
}
/**
* timer system suggests a repaint
*/
@Override
public boolean suggestRepaint() {
if (waitForRepaint == TimerSystemW.SLEEPING_FLAG) {
return false;
}
if (waitForRepaint == TimerSystemW.REPAINT_FLAG) {
if (isShowing()) {
doRepaint();
}
return true;
}
waitForRepaint--;
return true;
}
@Override
public void exportPaintPre(GGraphics2D g2d, double scale,
boolean transparency) {
// TODO Auto-generated method stub
}
@Override
public GGraphics2DW getG2P() {
return g2p;
}
@Override
public void resetPointerEventHandler() {
// TODO Auto-generated method stub
}
@Override
public String getExportImageDataUrl(double scale, boolean b) {
((RendererWInterface) this.renderer).setBuffering(true);
this.doRepaint2();
String url = ((Canvas) renderer.getCanvas()).toDataUrl();
((RendererWInterface) this.renderer).setBuffering(false);
return url;
}
@Override
public String getCanvasBase64WithTypeString() {
((RendererWInterface) this.renderer).setBuffering(true);
this.doRepaint2();
String ret = EuclidianViewW.getCanvasBase64WithTypeString(
this.getWidth(), getHeight(), null,
(Canvas) renderer.getCanvas());
((RendererWInterface) this.renderer).setBuffering(false);
return ret;
}
@Override
public void setPixelRatio(double pixelRatio) {
if (((AppW) app).getArticleElement().disableHiRes3D()) {
return;
}
if (Kernel.isEqual(g2p.devicePixelRatio, pixelRatio)) {
return;
}
int realWidth = g2p.getOffsetWidth();
int realHeight = g2p.getOffsetHeight();
g2p.devicePixelRatio = pixelRatio;
if (realHeight > 0 && realWidth > 0) {
((AppW) app).ggwGraphicsView3DDimChanged(realWidth, realHeight);
}
}
/**
* @param width
* canvas width
* @param height
* canvas height
*/
public void setCoordinateSpaceSize(int width, int height) {
// no transform nor color set since it's a WebGL context
g2p.setCoordinateSpaceSizeNoTransformNoColor(width, height);
try {
// just resizing the AbsolutePanelSmart, not the whole of DockPanel
g2p.getCanvas().getElement().getParentElement().getStyle()
.setWidth(width, Style.Unit.PX);
g2p.getCanvas().getElement().getParentElement().getStyle()
.setHeight(height, Style.Unit.PX);
getEuclidianController().calculateEnvironment();
} catch (Exception exc) {
Log.debug("Problem with the parent element of the canvas");
}
}
@Override
public void setAltText() {
GeoElement alt = app.getKernel().lookupLabel("altText3D1");
if (alt == null) {
alt = app.getKernel().lookupLabel("altText3D");
}
if (alt == null) {
alt = app.getKernel().lookupLabel("altText");
}
if (alt instanceof GeoText) {
String altStr = ((GeoText) alt).getTextString();
if (renderer != null && renderer.getCanvas() != null) {
((Canvas) renderer.getCanvas()).getElement()
.setInnerText(altStr);
} else {
g2p.setAltText(altStr);
}
}
}
@Override
public void readText(String text) {
//String oldAltText = g2p.getAltText();
//g2p.setAltText(text);
//RootPanel.getBodyElement().focus();
//this.requestFocus();
}
@Override
protected void drawBackgroundImage(GGraphics2D g2d) {
// nothing to do here
}
@Override
protected EuclidianStyleBar newDynamicStyleBar() {
// TODO Auto-generated method stub
return null;
}
@Override
protected void addDynamicStylebarToEV(EuclidianStyleBar dynamicStylebar) {
// TODO Auto-generated method stub
}
}