diff --git a/examplesForWebDemo/examplesForWebDemo.iml b/examplesForWebDemo/examplesForWebDemo.iml
new file mode 100644
index 00000000000..dd784a152e2
--- /dev/null
+++ b/examplesForWebDemo/examplesForWebDemo.iml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examplesForWebDemo/src/html5/interactive/interactive.js b/examplesForWebDemo/src/html5/interactive/interactive.js
new file mode 100644
index 00000000000..7903b8b8ecf
--- /dev/null
+++ b/examplesForWebDemo/src/html5/interactive/interactive.js
@@ -0,0 +1,323 @@
+{
+ var classes = function () {
+ var Vector = Kotlin.Class.create({initialize:function (x, y) {
+ this.$x = x;
+ this.$y = y;
+ }, get_x:function () {
+ return this.$x;
+ }, set_x:function (tmp$0) {
+ this.$x = tmp$0;
+ }, get_y:function () {
+ return this.$y;
+ }, set_y:function (tmp$0) {
+ this.$y = tmp$0;
+ }, plus:function (v) {
+ {
+ return interactive.v_0(this.get_x() + v.get_x(), this.get_y() + v.get_y());
+ }
+ }, minus:function (v) {
+ {
+ return interactive.v_0(this.get_x() - v.get_x(), this.get_y() - v.get_y());
+ }
+ }, times:function (coef) {
+ {
+ return interactive.v_0(this.get_x() * coef, this.get_y() * coef);
+ }
+ }, distanceTo:function (v) {
+ {
+ return Math.sqrt(this.minus(v).get_sqr());
+ }
+ }, isInRect:function (topLeft, size) {
+ {
+ return this.get_x() >= topLeft.get_x() && this.get_x() <= topLeft.get_x() + size.get_x() && this.get_y() >= topLeft.get_y() && this.get_y() <= topLeft.get_y() + size.get_y();
+ }
+ }, get_sqr:function () {
+ {
+ return this.get_x() * this.get_x() + this.get_y() * this.get_y();
+ }
+ }
+ });
+ var CanvasState = Kotlin.Class.create({initialize:function (canvas) {
+ this.$canvas = canvas;
+ this.$width = this.get_canvas().width;
+ this.$height = this.get_canvas().height;
+ this.$context = getContext();
+ this.$valid = false;
+ this.$shapes = new Kotlin.ArrayList;
+ this.$selection = null;
+ this.$dragOff = new interactive.Vector_0(0, 0);
+ this.$interval = 1000 / 30;
+ this.$size = 20;
+ {
+ var tmp$4;
+ var tmp$3;
+ var tmp$2;
+ var tmp$1;
+ var tmp$0_0;
+ $(this.get_canvas()).mousedown((tmp$0_0 = this , function (it) {
+ {
+ var tmp$0;
+ tmp$0_0.set_valid(false);
+ tmp$0_0.set_selection(null);
+ var mousePos = tmp$0_0.mousePos_0(it);
+ {
+ tmp$0 = tmp$0_0.get_shapes().iterator();
+ while (tmp$0.hasNext()) {
+ var shape = tmp$0.next();
+ {
+ if (shape.contains(mousePos)) {
+ tmp$0_0.set_dragOff(mousePos.minus(shape.get_pos()));
+ shape.set_selected(true);
+ tmp$0_0.set_selection(shape);
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ ));
+ $(this.get_canvas()).mousemove((tmp$1 = this , function (it) {
+ {
+ if (tmp$1.get_selection() != null) {
+ Kotlin.sure(tmp$1.get_selection()).set_pos(tmp$1.mousePos_0(it).minus(tmp$1.get_dragOff()));
+ tmp$1.set_valid(false);
+ }
+ }
+ }
+ ));
+ $(this.get_canvas()).mouseup((tmp$2 = this , function (it) {
+ {
+ if (tmp$2.get_selection() != null) {
+ Kotlin.sure(tmp$2.get_selection()).set_selected(false);
+ }
+ tmp$2.set_selection(null);
+ tmp$2.set_valid(false);
+ }
+ }
+ ));
+ $(this.get_canvas()).dblclick((tmp$3 = this , function (it) {
+ {
+ var redTransparentCircle = new interactive.Circle_0(tmp$3.mousePos_0(it), tmp$3.get_size(), 'rgba(200, 100, 100, 0.3)');
+ tmp$3.addShape(redTransparentCircle);
+ tmp$3.set_valid(false);
+ }
+ }
+ ));
+ interactive.doWithPeriod(this.get_interval(), (tmp$4 = this , function () {
+ {
+ tmp$4.draw();
+ }
+ }
+ ));
+ }
+ }, get_canvas:function () {
+ return this.$canvas;
+ }, get_width:function () {
+ return this.$width;
+ }, get_height:function () {
+ return this.$height;
+ }, get_context:function () {
+ return this.$context;
+ }, get_valid:function () {
+ return this.$valid;
+ }, set_valid:function (tmp$0) {
+ this.$valid = tmp$0;
+ }, get_shapes:function () {
+ return this.$shapes;
+ }, set_shapes:function (tmp$0) {
+ this.$shapes = tmp$0;
+ }, get_selection:function () {
+ return this.$selection;
+ }, set_selection:function (tmp$0) {
+ this.$selection = tmp$0;
+ }, get_dragOff:function () {
+ return this.$dragOff;
+ }, set_dragOff:function (tmp$0) {
+ this.$dragOff = tmp$0;
+ }, get_interval:function () {
+ return this.$interval;
+ }, get_size:function () {
+ return this.$size;
+ }, mousePos_0:function (e) {
+ {
+ var offset = new interactive.Vector_0(0, 0);
+ var element = this.get_canvas();
+ while (element != null) {
+ var el = Kotlin.sure(element);
+ offset = offset.plus(new interactive.Vector_0(el.offsetLeft, el.offsetTop));
+ element = el.offsetParent;
+ }
+ return (new interactive.Vector_0(e.pageX, e.pageY)).minus(offset);
+ }
+ }, addShape:function (shape) {
+ {
+ this.get_shapes().add(shape);
+ this.set_valid(false);
+ }
+ }, clear:function () {
+ {
+ this.get_context().fillStyle = '#FFFFFF';
+ this.get_context().fillRect(0, 0, this.get_width(), this.get_height());
+ this.get_context().strokeStyle = '#000000';
+ this.get_context().lineWidth = 4;
+ this.get_context().strokeRect(0, 0, this.get_width(), this.get_height());
+ }
+ }, draw:function () {
+ {
+ var tmp$0;
+ if (this.get_valid())
+ return;
+ this.clear();
+ {
+ tmp$0 = this.get_shapes().iterator();
+ while (tmp$0.hasNext()) {
+ var shape = tmp$0.next();
+ {
+ shape.draw(this);
+ }
+ }
+ }
+ this.set_valid(true);
+ }
+ }
+ });
+ var Shape = Kotlin.Class.create({initialize:function () {
+ this.$selected = false;
+ }, draw:function (state) {
+ }, contains:function (mousePos) {
+ }, get_pos:function () {
+ return this.$pos;
+ }, set_pos:function (tmp$0) {
+ this.$pos = tmp$0;
+ }, get_selected:function () {
+ return this.$selected;
+ }, set_selected:function (tmp$0) {
+ this.$selected = tmp$0;
+ }
+ });
+ var JB = Kotlin.Class.create(Shape, {initialize:function (pos, relSize) {
+ this.$pos = pos;
+ this.$relSize = relSize;
+ this.super_init();
+ this.$imageSize = interactive.v_0(704, 254);
+ this.$canvasSize = this.get_imageSize().times(this.get_relSize());
+ }, get_pos:function () {
+ return this.$pos;
+ }, set_pos:function (tmp$0) {
+ this.$pos = tmp$0;
+ }, get_relSize:function () {
+ return this.$relSize;
+ }, set_relSize:function (tmp$0) {
+ this.$relSize = tmp$0;
+ }, get_imageSize:function () {
+ return this.$imageSize;
+ }, get_canvasSize:function () {
+ return this.$canvasSize;
+ }, draw:function (state) {
+ {
+ var context = state.get_context();
+ context.drawImage(getJBLogo(), 0, 0, this.get_imageSize().get_x(), this.get_imageSize().get_y(), this.get_pos().get_x(), this.get_pos().get_y(), this.get_canvasSize().get_x(), this.get_canvasSize().get_y());
+ }
+ }, contains:function (mousePos) {
+ {
+ return mousePos.isInRect(this.get_pos(), this.get_canvasSize());
+ }
+ }
+ });
+ var Rectangle = Kotlin.Class.create(Shape, {initialize:function (pos, size) {
+ this.$pos = pos;
+ this.$size = size;
+ this.super_init();
+ }, get_pos:function () {
+ return this.$pos;
+ }, set_pos:function (tmp$0) {
+ this.$pos = tmp$0;
+ }, get_size:function () {
+ return this.$size;
+ }, set_size:function (tmp$0) {
+ this.$size = tmp$0;
+ }, draw:function (state) {
+ {
+ var context = state.get_context();
+ context.fillStyle = 'rgba(0,255,0,.6)';
+ context.fillRect(this.get_pos().get_x(), this.get_pos().get_y(), this.get_size().get_x(), this.get_size().get_y());
+ if (this.get_selected()) {
+ context.strokeStyle = '#FF0000';
+ context.lineWidth = 2;
+ context.strokeRect(this.get_pos().get_x(), this.get_pos().get_y(), this.get_size().get_x(), this.get_size().get_y());
+ }
+ }
+ }, contains:function (mousePos) {
+ {
+ return mousePos.isInRect(this.get_pos(), this.get_size());
+ }
+ }
+ });
+ var Circle = Kotlin.Class.create(Shape, {initialize:function (pos, radius, fillColor) {
+ this.$pos = pos;
+ this.$radius = radius;
+ this.$fillColor = fillColor;
+ this.super_init();
+ }, get_pos:function () {
+ return this.$pos;
+ }, set_pos:function (tmp$0) {
+ this.$pos = tmp$0;
+ }, get_radius:function () {
+ return this.$radius;
+ }, set_radius:function (tmp$0) {
+ this.$radius = tmp$0;
+ }, get_fillColor:function () {
+ return this.$fillColor;
+ }, set_fillColor:function (tmp$0) {
+ this.$fillColor = tmp$0;
+ }, draw:function (state) {
+ {
+ var context = state.get_context();
+ context.shadowColor = 'white';
+ context.shadowBlur = 10;
+ context.fillStyle = this.get_fillColor();
+ context.beginPath();
+ context.arc(this.get_pos().get_x(), this.get_pos().get_y(), this.get_radius(), 0, 2 * Math.PI, false);
+ context.closePath();
+ context.fill();
+ }
+ }, contains:function (mousePos) {
+ {
+ return this.get_pos().distanceTo(mousePos) < this.get_radius();
+ }
+ }
+ });
+ return {Shape_0:Shape, JB_0:JB, Rectangle_0:Rectangle, Circle_0:Circle, CanvasState_0:CanvasState, Vector_0:Vector};
+ }
+ ();
+ var interactive = Kotlin.Namespace.create({initialize:function () {
+ interactive.$state = new interactive.CanvasState_0(getCanvas());
+ }, get_state:function () {
+ return interactive.$state;
+ }, doWithPeriod:function (period, f) {
+ {
+ setInterval(f, period);
+ }
+ }, v_0:function (x, y) {
+ {
+ return new interactive.Vector_0(x, y);
+ }
+ }, main:function () {
+ {
+ var state = new interactive.CanvasState_0(getCanvas());
+ state.addShape(new interactive.JB_0(interactive.v_0(1, 1), 0.3));
+ setTimeout(function () {
+ {
+ state.set_valid(false);
+ }
+ }
+ );
+ }
+ }
+ }, classes);
+ interactive.initialize();
+}
+
+var args = [];
+interactive.main(args);
diff --git a/examplesForWebDemo/src/html5/interactive/jbLogo.png b/examplesForWebDemo/src/html5/interactive/jbLogo.png
new file mode 100644
index 00000000000..759aa8ae05a
Binary files /dev/null and b/examplesForWebDemo/src/html5/interactive/jbLogo.png differ
diff --git a/examplesForWebDemo/src/html5/interactive/main.kt b/examplesForWebDemo/src/html5/interactive/main.kt
new file mode 100644
index 00000000000..ae53ad652d1
--- /dev/null
+++ b/examplesForWebDemo/src/html5/interactive/main.kt
@@ -0,0 +1,183 @@
+package interactive;
+
+import jquery.*;
+import html5.*;
+import java.util.ArrayList;
+import js.*;
+import js.Math;
+import js.setInterval
+import html5.getCanvas
+import html5.getJBLogo
+import jquery.jq
+import js.setTimeout
+
+val state = CanvasState(getCanvas());
+
+fun doWithPeriod(period : Int, f : ()->Unit) {
+ setInterval(f, period);
+}
+
+abstract class Shape() {
+ abstract fun draw(state : CanvasState);
+ abstract fun contains(mousePos : Vector) : Boolean;
+ abstract var pos : Vector;
+ var selected : Boolean = false;
+}
+
+class Circle(override var pos : Vector,
+ var radius : Double = 1.0,
+ var fillColor : String = "#AAAAAA") : Shape() {
+
+ override fun draw(state : CanvasState) {
+ val context = state.context;
+ context.shadowColor = "white";
+ context.shadowBlur = 10.0;
+ context.fillStyle = fillColor;
+ context.beginPath();
+ context.arc(pos.x, pos.y, radius, 0.0, 2 * Math.PI, false);
+ context.closePath();
+ context.fill();
+ }
+
+ override fun contains(mousePos : Vector) = pos.distanceTo(mousePos) < radius;
+}
+
+class Rectangle(override var pos : Vector,
+ var size : Vector) : Shape()
+{
+ override fun draw(state : CanvasState) {
+ val context = state.context;
+ context.fillStyle = "rgba(0,255,0,.6)";
+ context.fillRect(pos.x, pos.y, size.x, size.y);
+ if (selected) {
+ context.strokeStyle = "#FF0000"
+ context.lineWidth = 2.0;
+ context.strokeRect(pos.x, pos.y, size.x, size.y)
+ }
+ }
+
+ override fun contains(mousePos : Vector) = mousePos.isInRect(pos, size);
+}
+
+class JB(override var pos : Vector,
+ var relSize : Double = 0.3) : Shape()
+{
+
+ val imageSize = v(704.0, 254.0)
+ val canvasSize = imageSize * relSize
+
+ override fun draw(state : CanvasState) {
+ val context = state.context;
+ context.drawImage(getJBLogo(), 0.0, 0.0, imageSize.x, imageSize.y, pos.x, pos.y, canvasSize.x, canvasSize.y)
+ }
+
+ override fun contains(mousePos: Vector): Boolean = mousePos.isInRect(pos, canvasSize)
+}
+
+class CanvasState(val canvas : Canvas) {
+ val width = canvas.width;
+ val height = canvas.height;
+ val context = getContext();
+ var valid = false;
+ var shapes = ArrayList();
+ var selection : Shape? = null;
+ var dragOff = Vector();
+ val interval = 1000 / 30;
+ val size = 20.0;
+
+ {
+ jq(canvas).mousedown {
+ valid = false;
+ selection = null;
+ val mousePos = mousePos(it);
+ for (shape in shapes) {
+ if (mousePos in shape) {
+ dragOff = mousePos - shape.pos;
+ shape.selected = true;
+ selection = shape;
+ break;
+ }
+ }
+ }
+
+ jq(canvas).mousemove {
+ if (selection != null) {
+ selection.sure().pos = mousePos(it) - dragOff;
+ valid = false;
+ }
+ }
+
+ jq(canvas).mouseup {
+ if (selection != null) {
+ selection.sure().selected = false;
+ }
+ selection = null;
+ valid = false;
+ }
+
+ jq(canvas).dblclick {
+ val redTransparentCircle = Circle(mousePos(it), size, "rgba(200, 100, 100, 0.3)");
+ addShape(redTransparentCircle);
+ valid = false;
+ }
+
+ doWithPeriod(interval) {
+ draw();
+ }
+ }
+
+ fun mousePos(e : MouseEvent) : Vector {
+ var offset = Vector();
+ var element : DomElement? = canvas;
+ while (element != null) {
+ val el : DomElement = element.sure();
+ offset += Vector(el.offsetLeft, el.offsetTop);
+ element = el.offsetParent;
+ }
+ return Vector(e.pageX, e.pageY) - offset;
+ }
+
+ fun addShape(shape : Shape) {
+ shapes.add(shape);
+ valid = false;
+ }
+
+ fun clear() {
+ context.fillStyle = "#FFFFFF"
+ context.fillRect(0.0, 0.0, width, height)
+ context.strokeStyle = "#000000"
+ context.lineWidth = 4.0;
+ context.strokeRect(0.0, 0.0, width, height)
+ }
+
+ fun draw() {
+ if (valid) return
+
+ clear();
+ for (shape in shapes) {
+ shape.draw(this);
+ }
+ valid = true;
+ }
+}
+
+fun v(x : Double, y : Double) = Vector(x, y);
+
+class Vector(var x : Double = 0.0, var y : Double = 0.0) {
+ fun plus(v : Vector) = v(x + v.x, y + v.y);
+ fun minus(v : Vector) = v(x - v.x, y - v.y);
+ fun times(coef : Double) = v(x * coef, y * coef);
+ fun distanceTo(v : Vector) = Math.sqrt((this - v).sqr);
+ fun isInRect(topLeft : Vector, size : Vector) = (x >= topLeft.x) && (x <= topLeft.x + size.x) &&
+ (y >= topLeft.y) && (y <= topLeft.y + size.y)
+ val sqr : Double
+ get() = x * x + y * y;
+}
+
+fun main() {
+ val state = CanvasState(getCanvas());
+ state.addShape(JB(v(1.0, 1.0)));
+ setTimeout({
+ state.valid = false
+ })
+}
\ No newline at end of file
diff --git a/examplesForWebDemo/src/html5/interactive/template.html b/examplesForWebDemo/src/html5/interactive/template.html
new file mode 100644
index 00000000000..c629242e8ee
--- /dev/null
+++ b/examplesForWebDemo/src/html5/interactive/template.html
@@ -0,0 +1,15 @@
+
+
+
+ Canvas demo
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examplesForWebDemo/src/html5/interactive/template_copy.html b/examplesForWebDemo/src/html5/interactive/template_copy.html
new file mode 100644
index 00000000000..7994eac67a3
--- /dev/null
+++ b/examplesForWebDemo/src/html5/interactive/template_copy.html
@@ -0,0 +1,14 @@
+
+
+
+ Canvas demo
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examplesForWebDemo/src/html5/interactive/tutorial.js b/examplesForWebDemo/src/html5/interactive/tutorial.js
new file mode 100644
index 00000000000..9306f52d6bb
--- /dev/null
+++ b/examplesForWebDemo/src/html5/interactive/tutorial.js
@@ -0,0 +1,222 @@
+// By Simon Sarris
+// www.simonsarris.com
+// sarris@acm.org
+//
+// Last update December 2011
+//
+// Free to use and distribute at will
+// So long as you are nice to people, etc
+
+// Constructor for Shape objects to hold data for all drawn objects.
+// For now they will just be defined as rectangles.
+function Shape(x, y, w, h, fill) {
+ // This is a very simple and unsafe constructor. All we're doing is checking if the values exist.
+ // "x || 0" just means "if there is a value for x, use that. Otherwise use 0."
+ // But we aren't checking anything else! We could put "Lalala" for the value of x
+ this.x = x || 0;
+ this.y = y || 0;
+ this.w = w || 1;
+ this.h = h || 1;
+ this.fill = fill || '#AAAAAA';
+}
+
+// Draws this shape to a given context
+Shape.prototype.draw = function (ctx) {
+ ctx.fillStyle = this.fill;
+ ctx.fillRect(this.x, this.y, this.w, this.h);
+}
+
+// Determine if a point is inside the shape's bounds
+Shape.prototype.contains = function (mx, my) {
+ // All we have to do is make sure the Mouse X,Y fall in the area between
+ // the shape's X and (X + Height) and its Y and (Y + Height)
+ return (this.x <= mx) && (this.x + this.w >= mx) &&
+ (this.y <= my) && (this.y + this.h >= my);
+}
+
+function CanvasState(canvas) {
+ // **** First some setup! ****
+
+ this.canvas = canvas;
+ this.width = canvas.width;
+ this.height = canvas.height;
+ this.ctx = canvas.getContext('2d');
+ // This complicates things a little but but fixes mouse co-ordinate problems
+ // when there's a border or padding. See getMouse for more detail
+// if (document.defaultView && document.defaultView.getComputedStyle) {
+// this.stylePaddingLeft = parseInt(document.defaultView.getComputedStyle(canvas, null)['paddingLeft'], 10) || 0;
+// this.stylePaddingTop = parseInt(document.defaultView.getComputedStyle(canvas, null)['paddingTop'], 10) || 0;
+// this.styleBorderLeft = parseInt(document.defaultView.getComputedStyle(canvas, null)['borderLeftWidth'], 10) || 0;
+// this.styleBorderTop = parseInt(document.defaultView.getComputedStyle(canvas, null)['borderTopWidth'], 10) || 0;
+// }
+ // Some pages have fixed-position bars (like the stumbleupon bar) at the top or left of the page
+ // They will mess up mouse coordinates and this fixes that
+ var html = document.body.parentNode;
+ this.htmlTop = html.offsetTop;
+ this.htmlLeft = html.offsetLeft;
+
+ // **** Keep track of state! ****
+
+ this.valid = false; // when set to false, the canvas will redraw everything
+ this.shapes = []; // the collection of things to be drawn
+ this.dragging = false; // Keep track of when we are dragging
+ // the current selected object. In the future we could turn this into an array for multiple selection
+ this.selection = null;
+ this.dragoffx = 0; // See mousedown and mousemove events for explanation
+ this.dragoffy = 0;
+
+ // **** Then events! ****
+
+ // This is an example of a closure!
+ // Right here "this" means the CanvasState. But we are making events on the Canvas itself,
+ // and when the events are fired on the canvas the variable "this" is going to mean the canvas!
+ // Since we still want to use this particular CanvasState in the events we have to save a reference to it.
+ // This is our reference!
+ var myState = this;
+
+ //fixes a problem where double clicking causes text to get selected on the canvas
+ canvas.addEventListener('selectstart', function (e) {
+ e.preventDefault();
+ return false;
+ }, false);
+ // Up, down, and move are for dragging
+ canvas.addEventListener('mousedown', function (e) {
+ var mouse = myState.getMouse(e);
+ var mx = mouse.x;
+ var my = mouse.y;
+ var shapes = myState.shapes;
+ var l = shapes.length;
+ for (var i = l - 1; i >= 0; i--) {
+ if (shapes[i].contains(mx, my)) {
+ var mySel = shapes[i];
+ // Keep track of where in the object we clicked
+ // so we can move it smoothly (see mousemove)
+ myState.dragoffx = mx - mySel.x;
+ myState.dragoffy = my - mySel.y;
+ myState.dragging = true;
+ myState.selection = mySel;
+ myState.valid = false;
+ return;
+ }
+ }
+ // havent returned means we have failed to select anything.
+ // If there was an object selected, we deselect it
+ if (myState.selection) {
+ myState.selection = null;
+ myState.valid = false; // Need to clear the old selection border
+ }
+ }, true);
+ canvas.addEventListener('mousemove', function (e) {
+ if (myState.dragging) {
+ var mouse = myState.getMouse(e);
+ // We don't want to drag the object by its top-left corner, we want to drag it
+ // from where we clicked. Thats why we saved the offset and use it here
+ myState.selection.x = mouse.x - myState.dragoffx;
+ myState.selection.y = mouse.y - myState.dragoffy;
+ myState.valid = false; // Something's dragging so we must redraw
+ }
+ }, true);
+ canvas.addEventListener('mouseup', function (e) {
+ myState.dragging = false;
+ }, true);
+ // double click for making new shapes
+ canvas.addEventListener('dblclick', function (e) {
+ var mouse = myState.getMouse(e);
+ myState.addShape(new Shape(mouse.x - 10, mouse.y - 10, 20, 20, 'rgba(0,255,0,.6)'));
+ }, true);
+
+ // **** Options! ****
+
+ this.selectionColor = '#CC0000';
+ this.selectionWidth = 2;
+ this.interval = 30;
+ setInterval(function () {
+ myState.draw();
+ }, myState.interval);
+}
+
+CanvasState.prototype.addShape = function (shape) {
+ this.shapes.push(shape);
+ this.valid = false;
+}
+
+CanvasState.prototype.clear = function () {
+ this.ctx.clearRect(0, 0, this.width, this.height);
+}
+
+// While draw is called as often as the INTERVAL variable demands,
+// It only ever does something if the canvas gets invalidated by our code
+CanvasState.prototype.draw = function () {
+ // if our state is invalid, redraw and validate!
+ if (!this.valid) {
+ var ctx = this.ctx;
+ var shapes = this.shapes;
+ this.clear();
+
+ // ** Add stuff you want drawn in the background all the time here **
+
+ // draw all shapes
+ var l = shapes.length;
+ for (var i = 0; i < l; i++) {
+ var shape = shapes[i];
+ // We can skip the drawing of elements that have moved off the screen:
+ if (shape.x > this.width || shape.y > this.height ||
+ shape.x + shape.w < 0 || shape.y + shape.h < 0) continue;
+ shapes[i].draw(ctx);
+ }
+
+ // draw selection
+ // right now this is just a stroke along the edge of the selected Shape
+ if (this.selection != null) {
+ ctx.strokeStyle = this.selectionColor;
+ ctx.lineWidth = this.selectionWidth;
+ var mySel = this.selection;
+ ctx.strokeRect(mySel.x, mySel.y, mySel.w, mySel.h);
+ }
+
+ // ** Add stuff you want drawn on top all the time here **
+
+ this.valid = true;
+ }
+}
+
+
+// Creates an object with x and y defined, set to the mouse position relative to the state's canvas
+// If you wanna be super-correct this can be tricky, we have to worry about padding and borders
+CanvasState.prototype.getMouse = function (e) {
+ var element = this.canvas, offsetX = 0, offsetY = 0, mx, my;
+
+ // Compute the total offset
+ if (element.offsetParent !== undefined) {
+ do {
+ offsetX += element.offsetLeft;
+ offsetY += element.offsetTop;
+ } while ((element = element.offsetParent));
+ }
+
+ // Add padding and border style widths to offset
+ // Also add the offsets in case there's a position:fixed bar
+// offsetX += this.stylePaddingLeft + this.styleBorderLeft + this.htmlLeft;
+ // offsetY += this.stylePaddingTop + this.styleBorderTop + this.htmlTop;
+
+ mx = e.pageX - offsetX;
+ my = e.pageY - offsetY;
+
+ // We return a simple javascript object (a hash) with x and y defined
+ return {x:mx, y:my};
+}
+
+// If you dont want to use
+// You could uncomment this init() reference and place the script reference inside the body tag
+init();
+
+function init() {
+ var s = new CanvasState(getCanvas());
+ s.addShape(new Shape(40, 40, 50, 50)); // The default is gray
+ s.addShape(new Shape(60, 140, 40, 60, 'lightskyblue'));
+ // Lets make some partially transparent
+ s.addShape(new Shape(80, 150, 60, 30, 'rgba(127, 255, 212, .5)'));
+ s.addShape(new Shape(125, 80, 30, 80, 'rgba(245, 222, 179, .7)'));
+}
+
+// Now go make something amazing!
\ No newline at end of file
diff --git a/examplesForWebDemo/src/html5/moving/moving.js b/examplesForWebDemo/src/html5/moving/moving.js
new file mode 100644
index 00000000000..75bf92d60bf
--- /dev/null
+++ b/examplesForWebDemo/src/html5/moving/moving.js
@@ -0,0 +1,145 @@
+{
+ var classes = function () {
+ var Moving = Kotlin.Class.create({initialize:function () {
+ this.$context = getContext();
+ this.$height = getCanvas().height;
+ this.$width = getCanvas().width;
+ this.$relX = 0.5;
+ this.$relY = 0.5;
+ this.$relXVelocity = this.randomVelocity();
+ this.$relYVelocity = this.randomVelocity();
+ this.$message = 'Hello Kotlin';
+ this.$textHeightInPixels = 60;
+ {
+ this.get_context().font = 'bold ' + this.get_textHeightInPixels() + 'px Georgia, serif';
+ }
+ this.$textWidthInPixels = this.get_context().measureText(this.get_message()).width;
+ }, get_context:function () {
+ return this.$context;
+ }, get_height:function () {
+ return this.$height;
+ }, get_width:function () {
+ return this.$width;
+ }, get_relX:function () {
+ return this.$relX;
+ }, set_relX:function (tmp$0) {
+ this.$relX = tmp$0;
+ }, get_relY:function () {
+ return this.$relY;
+ }, set_relY:function (tmp$0) {
+ this.$relY = tmp$0;
+ }, get_absX:function () {
+ {
+ return this.get_relX() * this.get_width();
+ }
+ }, get_absY:function () {
+ {
+ return this.get_relY() * this.get_height();
+ }
+ }, get_relXVelocity:function () {
+ return this.$relXVelocity;
+ }, set_relXVelocity:function (tmp$0) {
+ this.$relXVelocity = tmp$0;
+ }, get_relYVelocity:function () {
+ return this.$relYVelocity;
+ }, set_relYVelocity:function (tmp$0) {
+ this.$relYVelocity = tmp$0;
+ }, get_message:function () {
+ return this.$message;
+ }, get_textHeightInPixels:function () {
+ return this.$textHeightInPixels;
+ }, get_textWidthInPixels:function () {
+ return this.$textWidthInPixels;
+ }, renderText:function () {
+ {
+ this.get_context().save();
+ this.move();
+ this.get_context().shadowColor = 'white';
+ this.get_context().shadowBlur = 10;
+ this.get_context().fillStyle = 'rgba(100,200,0,0.7)';
+ this.get_context().fillText(this.get_message(), this.get_absX(), this.get_absY());
+ this.get_context().restore();
+ }
+ }, move:function () {
+ {
+ var relTextWidth = this.get_textWidthInPixels() / this.get_width();
+ if (this.get_relX() > 1 - relTextWidth - this.get_abs(this.get_relXVelocity()) || this.get_relX() < this.get_abs(this.get_relXVelocity())) {
+ this.set_relXVelocity(this.get_relXVelocity() * -1);
+ }
+ var relTextHeight = this.get_textHeightInPixels() / this.get_height();
+ if (this.get_relY() > 1 - this.get_abs(this.get_relYVelocity()) || this.get_relY() < this.get_abs(this.get_relYVelocity()) + relTextHeight) {
+ this.set_relYVelocity(this.get_relYVelocity() * -1);
+ }
+ this.set_relX(this.get_relX() + this.get_relXVelocity());
+ this.set_relY(this.get_relY() + this.get_relYVelocity());
+ }
+ }, changeDirection:function () {
+ {
+ this.set_relYVelocity(this.randomVelocity());
+ this.set_relXVelocity(this.randomVelocity());
+ }
+ }, renderBackground:function () {
+ {
+ this.get_context().save();
+ this.get_context().fillStyle = 'rgba(255,255,1,0.2)';
+ this.get_context().fillRect(0, 0, this.get_width(), this.get_height());
+ this.get_context().restore();
+ }
+ }, randomVelocity:function () {
+ var tmp$0;
+ if (Math.random() < 0.5)
+ tmp$0 = 1;
+ else
+ tmp$0 = -1;
+ {
+ return 0.01 * Math.random() * tmp$0;
+ }
+ }, run:function () {
+ {
+ var tmp$1;
+ var tmp$0;
+ setInterval((tmp$0 = this , function () {
+ {
+ tmp$0.renderBackground();
+ tmp$0.renderText();
+ }
+ }
+ ), 10);
+ setInterval((tmp$1 = this , function () {
+ {
+ tmp$1.changeDirection();
+ }
+ }
+ ), 3000);
+ }
+ }, get_abs:function (receiver) {
+ var tmp$0;
+ if (receiver > 0)
+ tmp$0 = receiver;
+ else
+ tmp$0 = -receiver;
+ {
+ return tmp$0;
+ }
+ }
+ });
+ return {Moving_0:Moving};
+ }
+ ();
+ var moving = Kotlin.Namespace.create({initialize:function () {
+ }, main:function () {
+ {
+ $(function () {
+ {
+ (new moving.Moving_0).run();
+ }
+ }
+ );
+ }
+ }
+ }, classes);
+ moving.initialize();
+}
+
+var args = [];
+moving.main(args);
diff --git a/examplesForWebDemo/src/html5/moving/template.html b/examplesForWebDemo/src/html5/moving/template.html
new file mode 100644
index 00000000000..5043894d83f
--- /dev/null
+++ b/examplesForWebDemo/src/html5/moving/template.html
@@ -0,0 +1,14 @@
+
+
+
+ Canvas demo
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examplesForWebDemo/src/html5/moving/test.kt b/examplesForWebDemo/src/html5/moving/test.kt
new file mode 100644
index 00000000000..db0ae95bb40
--- /dev/null
+++ b/examplesForWebDemo/src/html5/moving/test.kt
@@ -0,0 +1,92 @@
+package moving;
+
+import js.*;
+import html5.*;
+import jquery.*;
+
+fun main() {
+ jq {
+ Moving().run();
+ }
+}
+
+
+class Moving() {
+
+ val context = getContext();
+ val height = getCanvas().height;
+ val width = getCanvas().width;
+
+ var relX = 0.5;
+ var relY = 0.5;
+
+ val absX : Double
+ get() = (relX * width);
+ val absY : Double
+ get() = (relY * height);
+
+ var relXVelocity = randomVelocity();
+ var relYVelocity = randomVelocity();
+
+
+ val message = "Hello Kotlin";
+ val textHeightInPixels = 60;
+ {
+ context.font = "bold ${textHeightInPixels}px Georgia, serif"
+ }
+ val textWidthInPixels = context.measureText(message).width;
+
+ fun renderText() {
+ context.save();
+ move();
+ context.shadowColor = "white";
+ context.shadowBlur = 10.0;
+ context.fillStyle = "rgba(100,200,0,0.7)";
+ context.fillText(message, absX, absY);
+ context.restore();
+ }
+
+ fun move() {
+ val relTextWidth = textWidthInPixels / width;
+ if (relX > (1.0 - relTextWidth - relXVelocity.abs) || relX < relXVelocity.abs) {
+ relXVelocity *= -1;
+ }
+ val relTextHeight = textHeightInPixels / height;
+ if (relY > (1.0 - relYVelocity.abs) || relY < relYVelocity.abs + relTextHeight) {
+ relYVelocity *= -1;
+ }
+ relX += relXVelocity;
+ relY += relYVelocity;
+ }
+
+ fun changeDirection() {
+ relYVelocity = randomVelocity();
+ relXVelocity = randomVelocity();
+ }
+
+
+ fun renderBackground() {
+ context.save();
+ context.fillStyle = "rgba(255,255,1,0.2)";
+ context.fillRect(0.0, 0.0, width, height);
+ context.restore();
+ }
+
+ fun randomVelocity() = 0.01 * Math.random() *
+ if (Math.random() < 0.5) 1 else -1;
+
+ fun run() {
+ setInterval({
+ renderBackground();
+ renderText();
+ }, 10);
+ setInterval({
+ changeDirection();
+ }, 3000);
+ }
+
+ val Double.abs : Double
+ get() = if (this > 0) this else -this
+
+}
+
diff --git a/examplesForWebDemo/src/html5/test/template.html b/examplesForWebDemo/src/html5/test/template.html
new file mode 100644
index 00000000000..38521fe3248
--- /dev/null
+++ b/examplesForWebDemo/src/html5/test/template.html
@@ -0,0 +1,14 @@
+
+
+
+ Canvas demo
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examplesForWebDemo/src/html5/test/test.kt b/examplesForWebDemo/src/html5/test/test.kt
new file mode 100644
index 00000000000..e4fdcae638d
--- /dev/null
+++ b/examplesForWebDemo/src/html5/test/test.kt
@@ -0,0 +1,77 @@
+package testhtml;
+
+import js.*;
+import html5.*;
+import jquery.*;
+
+fun main() {
+ jq {
+ Test().run();
+ HelloKotlin().run();
+ }
+}
+
+
+class Test() {
+ val context = getContext();
+ val height = getCanvas().height;
+ val width = getCanvas().width;
+ var x = width * Math.random();
+ var y = height * Math.random();
+ var hue = 0;
+
+ fun line() {
+ context.save();
+ context.beginPath();
+ context.lineWidth = 20.0 * Math.random();
+ context.moveTo(x, y);
+
+ x = width * Math.random();
+ y = height * Math.random();
+
+ context.bezierCurveTo(width * Math.random(), height * Math.random(),
+ width * Math.random(), height * Math.random(), x, y);
+
+ hue += Math.random() * 10;
+ context.strokeStyle = "hsl($hue, 50%, 50%)";
+
+ context.shadowColor = "white";
+ context.shadowBlur = 10.0;
+
+ context.stroke();
+ context.restore();
+ }
+
+ fun blank() {
+ context.fillStyle = "rgba(255,255,1,0.1)";
+ context.fillRect(0.0, 0.0, width, height);
+ }
+
+ fun run() {
+ setInterval({line()}, 40);
+ setInterval({blank()}, 100);
+ }
+}
+
+class HelloKotlin() {
+ val context = getContext();
+ val height = getCanvas().height;
+ val width = getCanvas().width;
+
+ fun run() {
+ setInterval({
+ greet();
+ }, 2000);
+ }
+
+ fun greet() {
+ context.save();
+ val message = "Hello Kotlin";
+ context.font = "bold 20px Georgia, serif";
+ context.scale(5.0, 5.0);
+ context.strokeStyle = "rgba(0,0,0, 0.8)";
+ context.strokeText(message, /*(width / 3) + */ (width / 7) * Math.random(),
+ /*(height / 3) + */ (height / 7) * Math.random());
+ context.restore();
+ }
+}
diff --git a/examplesForWebDemo/src/html5/test/testhtml.js b/examplesForWebDemo/src/html5/test/testhtml.js
new file mode 100644
index 00000000000..8312453d084
--- /dev/null
+++ b/examplesForWebDemo/src/html5/test/testhtml.js
@@ -0,0 +1,120 @@
+{
+ var classes = function () {
+ var HelloKotlin = Kotlin.Class.create({initialize:function () {
+ this.$context = getContext();
+ this.$height = getCanvas().height;
+ this.$width = getCanvas().width;
+ }, get_context:function () {
+ return this.$context;
+ }, get_height:function () {
+ return this.$height;
+ }, get_width:function () {
+ return this.$width;
+ }, run:function () {
+ {
+ var tmp$0;
+ setInterval((tmp$0 = this , function () {
+ {
+ tmp$0.greet();
+ }
+ }
+ ), 2000);
+ }
+ }, greet:function () {
+ {
+ this.get_context().save();
+ var message = 'Hello Kotlin';
+ this.get_context().font = 'bold 20px Georgia, serif';
+ this.get_context().scale(5, 5);
+ this.get_context().strokeStyle = 'rgba(0,0,0, 0.8)';
+ this.get_context().strokeText(message, this.get_width() / 7 * Math.random(), this.get_height() / 7 * Math.random());
+ this.get_context().restore();
+ }
+ }
+ });
+ var Test = Kotlin.Class.create({initialize:function () {
+ this.$context = getContext();
+ this.$height = getCanvas().height;
+ this.$width = getCanvas().width;
+ this.$x = this.get_width() * Math.random();
+ this.$y = this.get_height() * Math.random();
+ this.$hue = 0;
+ }, get_context:function () {
+ return this.$context;
+ }, get_height:function () {
+ return this.$height;
+ }, get_width:function () {
+ return this.$width;
+ }, get_x:function () {
+ return this.$x;
+ }, set_x:function (tmp$0) {
+ this.$x = tmp$0;
+ }, get_y:function () {
+ return this.$y;
+ }, set_y:function (tmp$0) {
+ this.$y = tmp$0;
+ }, get_hue:function () {
+ return this.$hue;
+ }, set_hue:function (tmp$0) {
+ this.$hue = tmp$0;
+ }, line:function () {
+ {
+ this.get_context().save();
+ this.get_context().beginPath();
+ this.get_context().lineWidth = 20 * Math.random();
+ this.get_context().moveTo(this.get_x(), this.get_y());
+ this.set_x(this.get_width() * Math.random());
+ this.set_y(this.get_height() * Math.random());
+ this.get_context().bezierCurveTo(this.get_width() * Math.random(), this.get_height() * Math.random(), this.get_width() * Math.random(), this.get_height() * Math.random(), this.get_x(), this.get_y());
+ this.set_hue(this.get_hue() + Math.random() * 10);
+ this.get_context().strokeStyle = 'hsl(' + this.get_hue() + ', 50%, 50%)';
+ this.get_context().shadowColor = 'white';
+ this.get_context().shadowBlur = 10;
+ this.get_context().stroke();
+ this.get_context().restore();
+ }
+ }, blank:function () {
+ {
+ this.get_context().fillStyle = 'rgba(255,255,1,0.1)';
+ this.get_context().fillRect(0, 0, this.get_width(), this.get_height());
+ }
+ }, run:function () {
+ {
+ var tmp$1;
+ var tmp$0;
+ setInterval((tmp$0 = this , function () {
+ {
+ tmp$0.line();
+ }
+ }
+ ), 40);
+ setInterval((tmp$1 = this , function () {
+ {
+ tmp$1.blank();
+ }
+ }
+ ), 100);
+ }
+ }
+ });
+ return {Test_0:Test, HelloKotlin_0:HelloKotlin};
+ }
+ ();
+ var testhtml = Kotlin.Namespace.create({initialize:function () {
+ }, main:function () {
+ {
+ $(function () {
+ {
+ (new testhtml.Test_0).run();
+ (new testhtml.HelloKotlin_0).run();
+ }
+ }
+ );
+ }
+ }
+ }, classes);
+ testhtml.initialize();
+}
+
+var args = [];
+testhtml.main(args);
diff --git a/jslib/src/html5/core.kt b/jslib/src/html5/core.kt
index 6e14f794a4e..ac64a472188 100644
--- a/jslib/src/html5/core.kt
+++ b/jslib/src/html5/core.kt
@@ -34,7 +34,7 @@ class Context() {
fun quadraticCurveTo(cpx : Double, cpy : Double, x : Double, y : Double) {}
fun bezierCurveTo(cp1x : Double, cp1y : Double, cp2x : Double, cp2y : Double, x : Double, y : Double) {}
fun arcTo(x1 : Double, y1 : Double, x2 : Double, y2 : Double, radius : Double) {}
- fun arc(x : Double, y : Double, radius : Double, startAngle : Double, endAngle : Double, anticlockwise : Boolean= false) {}
+ fun arc(x : Double, y : Double, radius : Double, startAngle : Double, endAngle : Double, anticlockwise : Boolean) {}
fun rect(x : Double, y : Double, w : Double, h : Double) {}
fun fill() {}
@@ -46,8 +46,16 @@ class Context() {
fun strokeText(text : String, x : Double, y : Double, maxWidth : Double) {}
fun measureText(text : String) : TextMetrics = TextMetrics();
+
+ fun drawImage(image : HTMLImageElement, dx : Double, dy : Double) {}
+ fun drawImage(image : HTMLImageElement, dx: Double, dy: Double, dw: Double, dh: Double) {}
+ fun drawImage(image : HTMLImageElement, sx: Double, sy: Double,
+ sw: Double, sh: Double, dx: Double, dy: Double, dw: Double, dh: Double) {}
}
+native
+class HTMLImageElement() : DomElement() {}
+
native
class Canvas() : DomElement() {
val width = 0.0;
@@ -63,4 +71,6 @@ class TextMetrics() {
native
fun getContext() : Context = Context();
native
-fun getCanvas() : Canvas = Canvas();
\ No newline at end of file
+fun getCanvas() : Canvas = Canvas();
+native
+fun getJBLogo() : HTMLImageElement = HTMLImageElement();
\ No newline at end of file
diff --git a/translator/src/org/jetbrains/k2js/translate/expression/QualifiedExpressionTranslator.java b/translator/src/org/jetbrains/k2js/translate/expression/QualifiedExpressionTranslator.java
index dc9be6cb630..57a7078560c 100644
--- a/translator/src/org/jetbrains/k2js/translate/expression/QualifiedExpressionTranslator.java
+++ b/translator/src/org/jetbrains/k2js/translate/expression/QualifiedExpressionTranslator.java
@@ -28,11 +28,18 @@ public final class QualifiedExpressionTranslator {
@NotNull
public static AccessTranslator getAccessTranslator(@NotNull JetQualifiedExpression expression,
@NotNull TranslationContext context) {
- if (expression instanceof JetDotQualifiedExpression) {
- JsExpression receiver = translateReceiver(expression, context);
- return PropertyAccessTranslator.newInstance(getNotNullSimpleNameSelector(expression), receiver, context);
+
+ JsExpression receiver = translateReceiver(expression, context);
+ PropertyAccessTranslator result =
+ PropertyAccessTranslator.newInstance(getNotNullSimpleNameSelector(expression), receiver, context);
+ //TODO: util if this code duplicates
+ if (expression instanceof JetSafeQualifiedExpression) {
+ result.setCallType(PropertyAccessTranslator.CallType.SAFE);
}
- throw new UnsupportedOperationException();
+ if (expression instanceof JetDotQualifiedExpression) {
+ result.setCallType(PropertyAccessTranslator.CallType.NORMAL);
+ }
+ return result;
}
@NotNull
diff --git a/translator/src/org/jetbrains/k2js/translate/reference/PropertyAccessTranslator.java b/translator/src/org/jetbrains/k2js/translate/reference/PropertyAccessTranslator.java
index f9940af4f37..5547746f769 100644
--- a/translator/src/org/jetbrains/k2js/translate/reference/PropertyAccessTranslator.java
+++ b/translator/src/org/jetbrains/k2js/translate/reference/PropertyAccessTranslator.java
@@ -105,8 +105,27 @@ public abstract class PropertyAccessTranslator extends AccessTranslator {
return canBePropertyGetterCall(expression, context);
}
+ public enum CallType {
+ SAFE,
+ //TODO: bang qualifier is not implemented in frontend for now
+ BANG,
+ NORMAL
+ }
+
+ //TODO: we use normal by default but may cause bugs
+ private /*var*/ CallType callType = CallType.NORMAL;
+
protected PropertyAccessTranslator(@NotNull TranslationContext context) {
super(context);
}
+ public void setCallType(@NotNull CallType callType) {
+ this.callType = callType;
+ }
+
+ @NotNull
+ protected CallType getCallType() {
+ assert callType != null : "CallType not set";
+ return callType;
+ }
}
\ No newline at end of file
diff --git a/translator/testFiles/canvas_helper.js b/translator/testFiles/canvas_helper.js
index 4544e7456ef..0931cd4b484 100644
--- a/translator/testFiles/canvas_helper.js
+++ b/translator/testFiles/canvas_helper.js
@@ -4,4 +4,8 @@ function getContext() {
function getCanvas() {
return document.getElementsByTagName('canvas')[0];
+}
+
+function getJBLogo() {
+ return document.getElementsByTagName('img')[0];
}
\ No newline at end of file
diff --git a/translator/translator.iml b/translator/translator.iml
index 700837a9777..e22aa76dd49 100644
--- a/translator/translator.iml
+++ b/translator/translator.iml
@@ -4,8 +4,6 @@
-
-