diff --git a/.idea/.name b/.idea/.name
new file mode 100644
index 00000000000..09b0cd3eaf8
--- /dev/null
+++ b/.idea/.name
@@ -0,0 +1 @@
+k2js
\ No newline at end of file
diff --git a/.idea/ant.xml b/.idea/ant.xml
new file mode 100644
index 00000000000..2581ca3fe84
--- /dev/null
+++ b/.idea/ant.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/.idea/artifacts/k2js_jar.xml b/.idea/artifacts/k2js_jar.xml
new file mode 100644
index 00000000000..a4f2e6c0057
--- /dev/null
+++ b/.idea/artifacts/k2js_jar.xml
@@ -0,0 +1,16 @@
+
+
+ $PROJECT_DIR$/out/artifacts/k2js_jar
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
new file mode 100644
index 00000000000..00e9e1b79cb
--- /dev/null
+++ b/.idea/compiler.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.idea/copyright/apache.xml b/.idea/copyright/apache.xml
new file mode 100644
index 00000000000..647fcdb02ef
--- /dev/null
+++ b/.idea/copyright/apache.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml
new file mode 100644
index 00000000000..ace2e994924
--- /dev/null
+++ b/.idea/copyright/profiles_settings.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/encodings.xml b/.idea/encodings.xml
new file mode 100644
index 00000000000..e206d70d859
--- /dev/null
+++ b/.idea/encodings.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
new file mode 100644
index 00000000000..a76f2aecef0
--- /dev/null
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml
new file mode 100644
index 00000000000..3b312839bf2
--- /dev/null
+++ b/.idea/inspectionProfiles/profiles_settings.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 00000000000..d10b9ab7f7b
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ http://www.w3.org/1999/xhtml
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 00000000000..07c88da7dbd
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.idea/scopes/scope_settings.xml b/.idea/scopes/scope_settings.xml
new file mode 100644
index 00000000000..922003b8433
--- /dev/null
+++ b/.idea/scopes/scope_settings.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml
new file mode 100644
index 00000000000..3b000203088
--- /dev/null
+++ b/.idea/uiDesigner.xml
@@ -0,0 +1,125 @@
+
+
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+
+
+
+
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 00000000000..21cbaa607b2
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
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/creatures/creatures.js b/examplesForWebDemo/src/html5/creatures/creatures.js
new file mode 100644
index 00000000000..a83e29d65ad
--- /dev/null
+++ b/examplesForWebDemo/src/html5/creatures/creatures.js
@@ -0,0 +1,545 @@
+/*
+ * Copyright 2000-2012 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+{
+ var classes = function () {
+ var Vector = Kotlin.Class.create({initialize:function (x, y) {
+ this.$x = x;
+ this.$y = y;
+ }, get_x:function () {
+ return this.$x;
+ }, get_y:function () {
+ return this.$y;
+ }, plus:function (v) {
+ {
+ return creatures.v_0(this.get_x() + v.get_x(), this.get_y() + v.get_y());
+ }
+ }, minus:function () {
+ {
+ return creatures.v_0(-this.get_x(), -this.get_y());
+ }
+ }, minus$0:function (v) {
+ {
+ return creatures.v_0(this.get_x() - v.get_x(), this.get_y() - v.get_y());
+ }
+ }, times:function (koef) {
+ {
+ return creatures.v_0(this.get_x() * koef, this.get_y() * koef);
+ }
+ }, distanceTo:function (v) {
+ {
+ return Math.sqrt(this.minus$0(v).get_sqr());
+ }
+ }, rotatedBy:function (theta) {
+ {
+ var sin = Math.sin(theta);
+ var cos = Math.cos(theta);
+ return creatures.v_0(this.get_x() * cos - this.get_y() * sin, this.get_x() * sin + this.get_y() * cos);
+ }
+ }, 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();
+ }
+ }, get_normalized:function () {
+ {
+ return this.times(1 / Math.sqrt(this.get_sqr()));
+ }
+ }
+ });
+ var RadialGradientGenerator = Kotlin.Class.create({initialize:function (context) {
+ this.$context = context;
+ this.$gradients = new Kotlin.ArrayList;
+ this.$current = 0;
+ {
+ this.newColorStops([
+ [0, '#F59898'],
+ [0.5, '#F57373'],
+ [1, '#DB6B6B']
+ ]);
+ this.newColorStops([
+ [0.39, 'rgb(140,167,209)'],
+ [0.7, 'rgb(104,139,209)'],
+ [0.85, 'rgb(67,122,217)']
+ ]);
+ this.newColorStops([
+ [0, 'rgb(255,222,255)'],
+ [0.5, 'rgb(255,185,222)'],
+ [1, 'rgb(230,154,185)']
+ ]);
+ this.newColorStops([
+ [0, 'rgb(255,209,114)'],
+ [0.5, 'rgb(255,174,81)'],
+ [1, 'rgb(241,145,54)']
+ ]);
+ this.newColorStops([
+ [0, 'rgb(132,240,135)'],
+ [0.5, 'rgb(91,240,96)'],
+ [1, 'rgb(27,245,41)']
+ ]);
+ this.newColorStops([
+ [0, 'rgb(250,147,250)'],
+ [0.5, 'rgb(255,80,255)'],
+ [1, 'rgb(250,0,217)']
+ ]);
+ }
+ }, get_context:function () {
+ return this.$context;
+ }, get_gradients:function () {
+ return this.$gradients;
+ }, get_current:function () {
+ return this.$current;
+ }, set_current:function (tmp$0) {
+ this.$current = tmp$0;
+ }, newColorStops:function (colorStops) {
+ {
+ this.get_gradients().add(colorStops);
+ }
+ }, getNext:function () {
+ {
+ var result = this.get_gradients().get(this.get_current());
+ this.set_current((this.get_current() + 1) % this.get_gradients().size());
+ return result;
+ }
+ }
+ });
+ 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 creatures.Vector_0(0, 0);
+ this.$interval = 1000 / 30;
+ {
+ 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$0(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$0(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 newCreature = new creatures.Creature_0(tmp$3.mousePos_0(it), tmp$3);
+ tmp$3.addShape(newCreature);
+ tmp$3.set_valid(false);
+ }
+ }
+ ));
+ setInterval((tmp$4 = this , function () {
+ {
+ tmp$4.draw();
+ }
+ }
+ ), this.get_interval());
+ }
+ }, get_canvas:function () {
+ return this.$canvas;
+ }, get_width:function () {
+ return this.$width;
+ }, set_width:function (tmp$0) {
+ this.$width = tmp$0;
+ }, get_height:function () {
+ return this.$height;
+ }, set_height:function (tmp$0) {
+ this.$height = tmp$0;
+ }, get_size:function () {
+ {
+ return creatures.v_0(this.get_width(), this.get_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;
+ }, mousePos_0:function (e) {
+ {
+ var offset = new creatures.Vector_0(0, 0);
+ var element = this.get_canvas();
+ while (element != null) {
+ var el = Kotlin.sure(element);
+ offset = offset.plus(new creatures.Vector_0(el.offsetLeft, el.offsetTop));
+ element = el.offsetParent;
+ }
+ return (new creatures.Vector_0(e.pageX, e.pageY)).minus$0(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 = creatures.reversed(this.get_shapes()).iterator();
+ while (tmp$0.hasNext()) {
+ var shape = tmp$0.next();
+ {
+ shape.draw(this);
+ }
+ }
+ }
+ creatures.get_Kotlin().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;
+ }, shadowed:function (receiver, shadowOffset, alpha, render) {
+ {
+ receiver.save();
+ receiver.shadowColor = 'rgba(100, 100, 100, ' + alpha + ')';
+ receiver.shadowBlur = 5;
+ receiver.shadowOffsetX = shadowOffset.get_x();
+ receiver.shadowOffsetY = shadowOffset.get_y();
+ render.call(receiver);
+ receiver.restore();
+ }
+ }, fillPath:function (receiver, constructPath) {
+ {
+ receiver.beginPath();
+ constructPath.call(receiver);
+ receiver.closePath();
+ receiver.fill();
+ }
+ }
+ });
+ var Creature = Kotlin.Class.create(Shape, {initialize:function (pos, state) {
+ this.$pos = pos;
+ this.$state = state;
+ this.super_init();
+ this.$shadowOffset = creatures.v_0(-5, 5);
+ this.$colorStops = creatures.get_gradientGenerator().getNext();
+ this.$relSize = 0.05;
+ }, get_pos:function () {
+ return this.$pos;
+ }, set_pos:function (tmp$0) {
+ this.$pos = tmp$0;
+ }, get_state:function () {
+ return this.$state;
+ }, get_shadowOffset:function () {
+ return this.$shadowOffset;
+ }, get_colorStops:function () {
+ return this.$colorStops;
+ }, get_relSize:function () {
+ return this.$relSize;
+ }, get_radius:function () {
+ {
+ return this.get_state().get_width() * this.get_relSize();
+ }
+ }, get_position:function () {
+ var tmp$0;
+ if (this.get_selected())
+ tmp$0 = this.get_pos().minus$0(this.get_shadowOffset());
+ else
+ tmp$0 = this.get_pos();
+ {
+ return tmp$0;
+ }
+ }, get_directionToLogo:function () {
+ {
+ return creatures.get_Kotlin().get_centre().minus$0(this.get_position()).get_normalized();
+ }
+ }, contains:function (mousePos) {
+ {
+ return this.get_pos().distanceTo(mousePos) < this.get_radius();
+ }
+ }, circlePath:function (receiver, position, rad) {
+ {
+ receiver.arc(position.get_x(), position.get_y(), rad, 0, 2 * Math.PI, false);
+ }
+ }, fillCircle:function (receiver, position, rad) {
+ {
+ var tmp$0;
+ this.fillPath(receiver, (tmp$0 = this , function () {
+ {
+ tmp$0.circlePath(receiver, position, rad);
+ }
+ }
+ ));
+ }
+ }, draw:function (state) {
+ {
+ var context = state.get_context();
+ if (!this.get_selected()) {
+ this.drawCreature(context);
+ }
+ else {
+ this.drawCreatureWithShadow(context);
+ }
+ }
+ }, drawCreature:function (context) {
+ {
+ var tmp$0;
+ context.fillStyle = this.getGradient(context);
+ this.fillPath(context, (tmp$0 = this , function () {
+ {
+ tmp$0.tailPath(context);
+ tmp$0.circlePath(this, tmp$0.get_position(), tmp$0.get_radius());
+ }
+ }
+ ));
+ this.drawEye(context);
+ }
+ }, getGradient:function (context) {
+ {
+ var tmp$0;
+ var gradientCentre = this.get_position().plus(this.get_directionToLogo().times(this.get_radius() / 4));
+ var gradient = context.createRadialGradient(gradientCentre.get_x(), gradientCentre.get_y(), 1, gradientCentre.get_x(), gradientCentre.get_y(), 2 * this.get_radius());
+ {
+ tmp$0 = Kotlin.arrayIterator(this.get_colorStops());
+ while (tmp$0.hasNext()) {
+ var colorStop = tmp$0.next();
+ {
+ gradient.addColorStop(colorStop[0], colorStop[1]);
+ }
+ }
+ }
+ return gradient;
+ }
+ }, tailPath:function (context) {
+ {
+ var tailDirection = this.get_directionToLogo().minus();
+ var tailPos = this.get_position().plus(tailDirection.times(this.get_radius()).times(1));
+ var tailSize = this.get_radius() * 1.6;
+ var angle = Math.PI / 6;
+ var p1 = tailPos.plus(tailDirection.rotatedBy(angle).times(tailSize));
+ var p2 = tailPos.plus(tailDirection.rotatedBy(-angle).times(tailSize));
+ var middlePoint = this.get_position().plus(tailDirection.times(this.get_radius()).times(1));
+ context.moveTo(tailPos.get_x(), tailPos.get_y());
+ context.lineTo(p1.get_x(), p1.get_y());
+ context.quadraticCurveTo(middlePoint.get_x(), middlePoint.get_y(), p2.get_x(), p2.get_y());
+ context.lineTo(tailPos.get_x(), tailPos.get_y());
+ }
+ }, drawEye:function (context) {
+ {
+ var eyePos = this.get_directionToLogo().times(this.get_radius()).times(0.6).plus(this.get_position());
+ var eyeRadius = this.get_radius() / 3;
+ var eyeLidRadius = eyeRadius / 2;
+ context.fillStyle = '#FFFFFF';
+ this.fillCircle(context, eyePos, eyeRadius);
+ context.fillStyle = '#000000';
+ this.fillCircle(context, eyePos, eyeLidRadius);
+ }
+ }, drawCreatureWithShadow:function (context) {
+ {
+ var tmp$0_0;
+ this.shadowed(context, this.get_shadowOffset(), 0.7, (tmp$0_0 = this , function () {
+ {
+ var tmp$0;
+ context.fillStyle = tmp$0_0.getGradient(context);
+ tmp$0_0.fillPath(this, (tmp$0 = tmp$0_0 , function () {
+ {
+ tmp$0.tailPath(context);
+ tmp$0.circlePath(context, tmp$0.get_position(), tmp$0.get_radius());
+ }
+ }
+ ));
+ }
+ }
+ ));
+ this.drawEye(context);
+ }
+ }
+ });
+ var Logo = Kotlin.Class.create(Shape, {initialize:function (pos) {
+ this.$pos = pos;
+ this.super_init();
+ this.$relSize = 0.25;
+ this.$shadowOffset = creatures.v_0(-3, 3);
+ this.$imageSize = creatures.v_0(377, 393);
+ this.$size = 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;
+ }, get_shadowOffset:function () {
+ return this.$shadowOffset;
+ }, get_imageSize:function () {
+ return this.$imageSize;
+ }, get_size:function () {
+ return this.$size;
+ }, set_size:function (tmp$0) {
+ this.$size = tmp$0;
+ }, get_position:function () {
+ var tmp$0;
+ if (this.get_selected())
+ tmp$0 = this.get_pos().minus$0(this.get_shadowOffset());
+ else
+ tmp$0 = this.get_pos();
+ {
+ return tmp$0;
+ }
+ }, drawLogo:function (state) {
+ {
+ this.set_size(this.get_imageSize().times(state.get_size().get_x() / this.get_imageSize().get_x()).times(this.get_relSize()));
+ state.get_context().drawImage(getKotlinLogo(), 0, 0, this.get_imageSize().get_x(), this.get_imageSize().get_y(), this.get_position().get_x(), this.get_position().get_y(), this.get_size().get_x(), this.get_size().get_y());
+ }
+ }, draw:function (state) {
+ {
+ var context = state.get_context();
+ if (this.get_selected()) {
+ var tmp$0;
+ this.shadowed(context, this.get_shadowOffset(), 0.2, (tmp$0 = this , function () {
+ {
+ tmp$0.drawLogo(state);
+ }
+ }
+ ));
+ }
+ else {
+ this.drawLogo(state);
+ }
+ }
+ }, contains:function (mousePos) {
+ {
+ return mousePos.isInRect(this.get_pos(), this.get_size());
+ }
+ }, get_centre:function () {
+ {
+ return this.get_pos().plus(this.get_size().times(0.5));
+ }
+ }
+ });
+ return {Shape_0:Shape, Logo_0:Logo, Creature_0:Creature, RadialGradientGenerator_0:RadialGradientGenerator, CanvasState_0:CanvasState, Vector_0:Vector};
+ }
+ ();
+ var creatures = Kotlin.Namespace.create({initialize:function () {
+ creatures.$Kotlin = new creatures.Logo_0(creatures.v_0(300, 100));
+ creatures.$gradientGenerator = new creatures.RadialGradientGenerator_0(getContext());
+ }, get_Kotlin:function () {
+ return creatures.$Kotlin;
+ }, get_gradientGenerator:function () {
+ return creatures.$gradientGenerator;
+ }, v_0:function (x, y) {
+ {
+ return new creatures.Vector_0(x, y);
+ }
+ }, main:function () {
+ {
+ var state = new creatures.CanvasState_0(getCanvas());
+ state.addShape(creatures.get_Kotlin());
+ state.addShape(new creatures.Creature_0(state.get_size().times(0.25), state));
+ state.addShape(new creatures.Creature_0(state.get_size().times(0.75), state));
+ setTimeout(function () {
+ {
+ state.set_valid(false);
+ }
+ }
+ );
+ }
+ }, reversed:function (receiver) {
+ {
+ var result = new Kotlin.ArrayList;
+ var i = receiver.size();
+ while (i > 0) {
+ result.add(receiver.get(--i));
+ }
+ return result;
+ }
+ }
+ }, classes);
+ creatures.initialize();
+}
+
+var args = [];
+creatures.main(args);
diff --git a/examplesForWebDemo/src/html5/creatures/kotlinlogo.png b/examplesForWebDemo/src/html5/creatures/kotlinlogo.png
new file mode 100644
index 00000000000..5394223b3d6
Binary files /dev/null and b/examplesForWebDemo/src/html5/creatures/kotlinlogo.png differ
diff --git a/examplesForWebDemo/src/html5/creatures/main.kt b/examplesForWebDemo/src/html5/creatures/main.kt
new file mode 100644
index 00000000000..46e0d92b8c2
--- /dev/null
+++ b/examplesForWebDemo/src/html5/creatures/main.kt
@@ -0,0 +1,331 @@
+/*
+In this example strange creatures are watching the kotlin logo. You can drag'n'drop them as well as the logo.
+Doubleclick to add more creatures but be careful. They may be watching you!
+*/
+package creatures
+// importing some of the API defined
+import jquery.*
+import html5.*
+import java.util.ArrayList
+import js.*
+import js.Math
+import js.setInterval
+import html5.getCanvas
+import html5.getKotlinLogo
+import jquery.jq
+import js.setTimeout
+import java.util.List
+
+
+abstract class Shape() {
+
+ abstract fun draw(state : CanvasState)
+ // these two abstract methods defines that our shapes can be dragged
+ abstract fun contains(mousePos : Vector) : Boolean
+ abstract var pos : Vector
+
+ var selected : Boolean = false
+
+ // a couple of helper extension methods we'll be using in the derived classes
+ fun Context.shadowed(shadowOffset : Vector, alpha : Double, render : Context.() -> Unit) {
+ save()
+ shadowColor = "rgba(100, 100, 100, $alpha)"
+ shadowBlur = 5.0
+ shadowOffsetX = shadowOffset.x
+ shadowOffsetY = shadowOffset.y
+ render()
+ restore()
+ }
+
+ fun Context.fillPath(constructPath : Context.() -> Unit) {
+ beginPath()
+ constructPath()
+ closePath()
+ fill()
+ }
+}
+
+val Kotlin = Logo(v(300.0, 100.0))
+
+class Logo(override var pos : Vector) : Shape()
+{
+ val relSize : Double = 0.25
+ val shadowOffset = v(-3.0, 3.0)
+ val imageSize = v(377.0, 393.0)
+ var size : Vector = imageSize * relSize
+ // get-only properties like this saves you lots of typing and are very expressive
+ val position : Vector
+ get() = if (selected) pos - shadowOffset else pos
+
+
+ fun drawLogo(state : CanvasState) {
+ size = imageSize * (state.size.x / imageSize.x) * relSize
+ // getKotlinLogo() is a 'magic' function here defined only for purposes of demonstration but in fact it just find an element containing the logo
+ state.context.drawImage(getKotlinLogo(), 0.0, 0.0, imageSize.x, imageSize.y, position.x, position.y, size.x, size.y)
+ }
+
+ override fun draw(state : CanvasState) {
+ val context = state.context
+ if (selected) {
+ // using helper we defined in Shape class
+ context.shadowed(shadowOffset, 0.2) {
+ drawLogo(state)
+ }
+ } else {
+ drawLogo(state)
+ }
+ }
+
+ override fun contains(mousePos: Vector): Boolean = mousePos.isInRect(pos, size)
+
+ val centre : Vector
+ get() = pos + size * 0.5
+}
+
+val gradientGenerator = RadialGradientGenerator(getContext())
+
+class Creature(override var pos : Vector, val state : CanvasState) : Shape() {
+
+ val shadowOffset = v(-5.0, 5.0)
+ val colorStops = gradientGenerator.getNext()
+ val relSize = 0.05
+ // these properties have no backing fields and in java/javascript they could be represented as little helper functions
+ val radius : Double
+ get() = state.width * relSize
+ val position : Vector
+ get() = if (selected) pos - shadowOffset else pos
+ val directionToLogo : Vector
+ get() = (Kotlin.centre - position).normalized
+
+ //notice how the infix call can make some expressions extremely expressive
+ override fun contains(mousePos : Vector) = pos distanceTo mousePos < radius
+
+ // defining more nice extension functions
+ fun Context.circlePath(position : Vector, rad : Double) {
+ arc(position.x, position.y, rad, 0.0, 2 * Math.PI, false)
+ }
+
+ //notice we can use an extension function we just defined inside another extension function
+ fun Context.fillCircle(position : Vector, rad : Double) {
+ fillPath {
+ circlePath(position, rad)
+ }
+ }
+
+ override fun draw(state : CanvasState) {
+ val context = state.context
+ if (!selected) {
+ drawCreature(context)
+ } else {
+ drawCreatureWithShadow(context)
+ }
+ }
+
+ fun drawCreature(context : Context) {
+ context.fillStyle = getGradient(context)
+ context.fillPath {
+ tailPath(context)
+ circlePath(position, radius)
+ }
+ drawEye(context)
+ }
+
+ fun getGradient(context : Context) : CanvasGradient {
+ val gradientCentre = position + directionToLogo * (radius / 4)
+ val gradient = context.createRadialGradient(gradientCentre.x, gradientCentre.y, 1.0, gradientCentre.x, gradientCentre.y, 2 * radius)
+ for (colorStop in colorStops) {
+ gradient.addColorStop(colorStop._1, colorStop._2)
+ }
+ return gradient
+ }
+
+ fun tailPath(context : Context) {
+ val tailDirection = -directionToLogo
+ val tailPos = position + tailDirection * radius * 1.0
+ val tailSize = radius * 1.6
+ val angle = Math.PI / 6.0
+ val p1 = tailPos + tailDirection.rotatedBy(angle) * tailSize
+ val p2 = tailPos + tailDirection.rotatedBy(-angle) * tailSize
+ val middlePoint = position + tailDirection * radius * 1.0
+ context.moveTo(tailPos.x, tailPos.y)
+ context.lineTo(p1.x, p1.y)
+ context.quadraticCurveTo(middlePoint.x, middlePoint.y, p2.x, p2.y)
+ context.lineTo(tailPos.x, tailPos.y)
+ }
+
+ fun drawEye(context : Context) {
+ val eyePos = directionToLogo * radius * 0.6 + position
+ val eyeRadius = radius / 3
+ val eyeLidRadius = eyeRadius / 2
+ context.fillStyle = "#FFFFFF"
+ context.fillCircle(eyePos, eyeRadius)
+ context.fillStyle = "#000000"
+ context.fillCircle(eyePos, eyeLidRadius)
+ }
+
+ fun drawCreatureWithShadow(context : Context) {
+ context.shadowed(shadowOffset, 0.7) {
+ context.fillStyle = getGradient(context)
+ fillPath {
+ tailPath(context)
+ context.circlePath(position, radius)
+ }
+ }
+ drawEye(context)
+ }
+}
+
+class CanvasState(val canvas : Canvas) {
+ var width = canvas.width
+ var height = canvas.height
+ val size : Vector
+ get() = v(width, height)
+ val context = getContext()
+ var valid = false
+ var shapes = ArrayList()
+ var selection : Shape? = null
+ var dragOff = Vector()
+ val interval = 1000 / 30
+
+ {
+ 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 newCreature = Creature(mousePos(it), this @CanvasState)
+ addShape(newCreature)
+ valid = false
+ }
+
+ setInterval({
+ draw()
+ }, interval)
+ }
+
+ 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.reversed()) {
+ shape.draw(this)
+ }
+ Kotlin.draw(this)
+ valid = true
+ }
+}
+
+class RadialGradientGenerator(val context : Context) {
+ val gradients = ArrayList>()
+ var current = 0
+
+ fun newColorStops(vararg colorStops : #(Double, String)) {
+ gradients.add(colorStops)
+ }
+
+ {
+ newColorStops(#(0.0, "#F59898"), #(0.5, "#F57373"), #(1.0, "#DB6B6B"))
+ newColorStops(#(0.39, "rgb(140,167,209)"), #(0.7, "rgb(104,139,209)"), #(0.85, "rgb(67,122,217)"))
+ newColorStops(#(0.0, "rgb(255,222,255)"), #(0.5, "rgb(255,185,222)"), #(1.0, "rgb(230,154,185)"))
+ newColorStops(#(0.0, "rgb(255,209,114)"), #(0.5, "rgb(255,174,81)"), #(1.0, "rgb(241,145,54)"))
+ newColorStops(#(0.0, "rgb(132,240,135)"), #(0.5, "rgb(91,240,96)"), #(1.0, "rgb(27,245,41)"))
+ newColorStops(#(0.0, "rgb(250,147,250)"), #(0.5, "rgb(255,80,255)"), #(1.0, "rgb(250,0,217)"))
+ }
+
+ fun getNext() : Array<#(Double, String)> {
+ val result = gradients.get(current)
+ current = (current + 1) % gradients.size()
+ return result
+ }
+}
+
+fun v(x : Double, y : Double) = Vector(x, y)
+
+class Vector(val x : Double = 0.0, val y : Double = 0.0) {
+ fun plus(v : Vector) = v(x + v.x, y + v.y)
+ fun minus() = v(-x, -y)
+ fun minus(v : Vector) = v(x - v.x, y - v.y)
+ fun times(koef : Double) = v(x * koef, y * koef)
+ fun distanceTo(v : Vector) = Math.sqrt((this - v).sqr)
+ fun rotatedBy(theta : Double) : Vector {
+ val sin = Math.sin(theta)
+ val cos = Math.cos(theta)
+ return v(x * cos - y * sin, x * sin + y * cos)
+ }
+
+ 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
+ val normalized : Vector
+ get() = this * (1.0 / Math.sqrt(sqr))
+}
+
+fun main() {
+ val state = CanvasState(getCanvas())
+ state.addShape(Kotlin)
+ state.addShape(Creature(state.size * 0.25, state))
+ state.addShape(Creature(state.size * 0.75, state))
+ setTimeout({
+ state.valid = false
+ })
+}
+
+fun List.reversed() : List {
+ val result = ArrayList()
+ var i = size()
+ while (i > 0) {
+ result.add(get(--i))
+ }
+ return result
+}
\ No newline at end of file
diff --git a/examplesForWebDemo/src/html5/creatures/template.html b/examplesForWebDemo/src/html5/creatures/template.html
new file mode 100644
index 00000000000..466bfa8168f
--- /dev/null
+++ b/examplesForWebDemo/src/html5/creatures/template.html
@@ -0,0 +1,32 @@
+
+
+
+
+
+ Canvas demo
+
+
+
+
+
+
+
+
+
+
+