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 @@ - -