package com.xenoage.zong.webapp;
import com.google.gwt.canvas.client.Canvas;
import com.google.gwt.canvas.dom.client.Context2d;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.dom.client.Element;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RootPanel;
import com.xenoage.utils.async.AsyncCallback;
import com.xenoage.utils.error.Err;
import com.xenoage.utils.gwt.error.GwtErrorProcessing;
import com.xenoage.utils.gwt.log.GwtLogProcessing;
import com.xenoage.utils.log.Log;
import com.xenoage.utils.math.geom.Size2f;
import com.xenoage.utils.math.geom.Size2i;
import com.xenoage.zong.Zong;
import com.xenoage.zong.documents.ScoreDoc;
import com.xenoage.zong.io.musiclayout.LayoutSettingsReader;
import com.xenoage.zong.io.musicxml.in.MusicXmlScoreDocFileReader;
import com.xenoage.zong.musiclayout.layouter.Context;
import com.xenoage.zong.musiclayout.layouter.ScoreLayoutArea;
import com.xenoage.zong.musiclayout.layouter.Target;
import com.xenoage.zong.musiclayout.settings.LayoutSettings;
import com.xenoage.zong.renderer.gwtcanvas.GwtCanvasLayoutRenderer;
import com.xenoage.zong.symbols.SymbolPool;
import com.xenoage.zong.webapp.utils.GwtZongPlatformUtils;
import java.io.IOException;
import static com.google.gwt.dom.client.Style.Display.BLOCK;
import static com.google.gwt.dom.client.Style.Display.NONE;
import static com.google.gwt.dom.client.Style.Unit.PX;
import static com.xenoage.utils.PlatformUtils.platformUtils;
import static com.xenoage.utils.gwt.GwtPlatformUtils.consoleLog;
import static com.xenoage.utils.log.Log.log;
import static com.xenoage.utils.log.Report.fatal;
import static com.xenoage.utils.math.MathUtils.clamp;
import static com.xenoage.zong.util.ZongPlatformUtils.zongPlatformUtils;
/**
* HTML5/JS based version of a Zong! score viewer, based on GWT.
*
* TODO: ZONG-106: SVG output in webapp
*
* @author Andreas Wenger
*/
public class WebApp
implements EntryPoint {
public static final String appFirstName = "WebApp";
public static WebApp instance;
private RootPanel container;
private Element loadingPanel;
private Canvas canvas;
private Context2d context;
private ScoreDoc scoreDoc;
private float zoom = 1;
/**
* This is the entry point method.
*/
@Override public void onModuleLoad() {
instance = this;
//init logging
Log.init(new GwtLogProcessing(Zong.getNameAndVersion(appFirstName)));
//init error handler
Err.init(new GwtErrorProcessing());
//init utils
GwtZongPlatformUtils.init(new AsyncCallback() {
@Override public void onSuccess() {
step1_setup();
}
@Override public void onFailure(Exception ex) {
log(fatal("Could not init platform utils", ex));
}
});
}
private void step1_setup() {
//find the container and loading panel
container = RootPanel.get("ZongView");
loadingPanel = DOM.getElementById("ZongLoading");
//create and add canvas
canvas = Canvas.createIfSupported();
if (canvas == null) {
container.add(new Label("Error: canvas not supported!"));
return;
}
canvas.setWidth("800px");
canvas.setHeight("600px");
Window.addResizeHandler(e -> {
paintLayout();
});
container.add(canvas);
//load and layout MusicXML file
openDemo(1);
}
private void openFile(String filePath) {
//show loading, hide score
if (loadingPanel != null) loadingPanel.getStyle().setDisplay(BLOCK);
canvas.setVisible(false);
//load score
platformUtils().openFileAsync(filePath)
.thenAsync(scoreStream -> new MusicXmlScoreDocFileReader(scoreStream, null).read())
.thenAsync(scoreDoc -> {
WebApp.this.scoreDoc = scoreDoc;
return platformUtils().openFileAsync("data/layout/default.xml");
})
.thenDo(testXmlStream -> {
LayoutSettings layoutSettings;
try {
layoutSettings = LayoutSettingsReader.read(testXmlStream);
} catch (IOException ex) {
throw new RuntimeException(ex);
}
Size2f areaSize = new Size2f(150, 10000);
SymbolPool symbolPool = zongPlatformUtils().getSymbolPool();
Context context = new Context(scoreDoc.getScore(), symbolPool, layoutSettings);
Target target = Target.completeLayoutTarget(new ScoreLayoutArea(areaSize));
paintLayout();
//show score, hide loading
canvas.setVisible(true);
if (loadingPanel != null) loadingPanel.getStyle().setDisplay(NONE);
})
.onError(ex -> consoleLog("Error: " + ex.toString()));
}
private void paintLayout() {
if (scoreDoc != null) {
Size2i size = GwtCanvasLayoutRenderer.paintToCanvas(scoreDoc.getLayout(), 0, zoom, canvas);
//also resize the loading panel to the size of the score
if (loadingPanel != null) {
loadingPanel.getStyle().setWidth(size.width, PX);
loadingPanel.getStyle().setHeight(size.height, PX);
}
}
}
public void openDemo(int id) {
String file = null;
if (id == 1) file = "data/test/scores/musicxml20/BeetAnGeSample.xml";
if (id == 2) file = "data/test/scores/musicxml20/BrahWiMeSample.xml";
if (id == 3) file = "data/test/scores/musicxml20/MahlFaGe4Sample.xml";
if (file != null)
openFile(file);
}
public void zoomIn() {
zoom(1.3f);
}
public void zoomOut() {
zoom(1 / 1.3f);
}
private void zoom(float factor) {
zoom = clamp(zoom * factor, 0.2f, 4f);
paintLayout();
}
}