/* This file contains proprietary software owned by Motorola Mobility, Inc.
No rights, expressed or implied, whatsoever to this software are provided by Motorola Mobility, Inc. hereunder.
(c) Copyright 2011 Motorola Mobility, Inc. All Rights Reserved.
*/ /** @module js/document/documentManager @requires montage/core/core @requires montage/ui/component */ var Montage = require("montage/core/core").Montage, Component = require("montage/ui/component").Component, viewUtils = require("js/helper-classes/3D/view-utils").ViewUtils, drawUtils = require("js/helper-classes/3D/draw-utils").DrawUtils, vecUtils = require("js/helper-classes/3D/vec-utils").VecUtils; exports.Layout = Montage.create(Component, { canvas: { value: null }, ctx: { value: null }, drawFillColor: { value: 'rgba(255,255,255,1)' }, ctxLineWidth: { value: 0.2 }, _layoutView: { value: "layoutAll" }, layoutView: { get: function() { return this._layoutView; }, set: function(value) { if(this._layoutView !== value) { this._layoutView = value; this.draw(); } } }, domTree: { value: [] }, elementsToDraw: { value: [] }, deserializedFromTemplate: { value: function() { this.ctx = this.canvas.getContext("2d"); this.ctx.lineWidth = this.ctxLineWidth; this.ctx.fillStyle = this.drawFillColor; this.eventManager.addEventListener("elementAdded", this, false); this.eventManager.addEventListener("elementDeleted", this, false); this.eventManager.addEventListener("selectionChange", this, false); this.eventManager.addEventListener("deleteSelection", this, true); // this.addEventListener("change@stage.appModel.layoutView", this.handleLayoutView, false); } }, handleLayoutView: { value: function() { console.log(this.stage.appModel.layoutView); } }, handleElementAdded: { value: function(event) { this.domTree.push(event.detail); } }, handleElementDeleted: { value: function(event) { this.domTree.splice(this.domTree.indexOf(event.detail), 1); this.draw(); } }, captureDeleteSelection: { value: function(event) { //this.redrawDocument(); var len = event.detail.length; for(var i = 0; i < len ; i++) { this.domTree.splice(this.domTree.indexOf(event.detail[i]),1); } } }, handleSelectionChange: { value: function(event) { this.elementsToDraw = []; if(!event.detail.isDocument) { var tmp = event.detail.elements.map(function(element){ return element._element}); this.elementsToDraw = this.domTree.filter(function(value) { return (tmp.indexOf(value) === -1); }); } else { this.elementsToDraw = this.domTree; } this.draw(); // Not a reel yet :) } }, draw: { value: function() { this.clearCanvas(); var els = this.elementsToDraw.length; for(var i = 0, el; i < els; i++){ this.drawTagOutline(this.elementsToDraw[i]); } } }, draw3DInfo: { value: function() { drawUtils.updatePlanes(); if(this.stage.appModel.show3dGrid) drawUtils.drawWorkingPlane(); drawUtils.draw3DCompass(); } }, clearCanvas: { value: function() { this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); } }, drawTagOutline: { value: function (item) { if(!item) return; // TODO Bind the layoutview mode to the current document // var mode = this.application.ninja.currentDocument.layoutMode; if(this.layoutView === "layoutOff") return; // Don't draw outlines for shapes. // TODO Use the element mediator/controller/model to see if its a shape /* if (utilsModule.utils.isElementAShape(item)) { return; } */ /** * New Drawing layout code using 3D calculations */ viewUtils.setViewportObj( item ); var bounds3D = viewUtils.getElementViewBounds3D( item ); var tmpMat = viewUtils.getLocalToGlobalMatrix( item ); var zoomFactor = 1; if (this.stage._viewport.style && this.stage._viewport.style.zoom) { zoomFactor = Number(this.stage._viewport.style.zoom); } var sSL = this.stage._scrollLeft; var sST = this.stage._scrollTop; for (var j=0; j<4; j++) { var localPt = bounds3D[j]; var tmpPt = viewUtils.localToGlobal2(localPt, tmpMat); if(zoomFactor !== 1) { tmpPt = vecUtils.vecScale(3, tmpPt, zoomFactor); tmpPt[0] += sSL*(zoomFactor - 1); tmpPt[1] += sST*(zoomFactor - 1); } bounds3D[j] = tmpPt; } // Draw the Item ouline this._dashedLine(bounds3D[3][0] - 0.5,bounds3D[3][1]- 0.5,bounds3D[0][0] + 2.5, bounds3D[0][1] - 0.5,[5,5]); this._dashedLine(bounds3D[0][0] - 0.5, bounds3D[0][1] - 0.5, bounds3D[1][0]- 0.5, bounds3D[1][1] + 0.5, [5,5] ); this._dashedLine(bounds3D[1][0] - 0.5 , bounds3D[1][1] + 0.5, bounds3D[2][0]+ 0.5, bounds3D[2][1] + 0.5, [5,5] ); this._dashedLine(bounds3D[2][0] + 0.5, bounds3D[2][1] + 0.5, bounds3D[3][0] + 0.5, bounds3D[3][1] - 0.5, [5,5] ); // Draw the Label is all mode if(this.layoutView === "layoutAll") { this.ctx.strokeStyle = 'rgba(0,0,0,1)'; // Black Stroke this.ctx.strokeRect(bounds3D[0][0]+5.5, bounds3D[0][1]-15.5, 70, 11); this.ctx.fillStyle = 'rgba(255,255,255,1)' // White Fill this.ctx.fillRect(bounds3D[0][0]+6, bounds3D[0][1]-15, 69, 10); this.ctx.fillStyle = 'rgba(0,0,0,1)'; this.ctx.font = "9px Droid Sans"; this.ctx.fillText(this._elementName(item), bounds3D[0][0] + 8, bounds3D[0][1] - 7); } } }, /** * redrawDocument: Redraws the outline for the entire document */ redrawDocument: { value: function() { if(this.application.ninja.currentDocument) { this.clearCanvas(); this.WalkDOM(this.application.ninja.currentDocument.documentRoot); //drawUtils.updatePlanes(); //if(this.application.ninja.currentDocument.draw3DGrid) drawUtils.drawWorkingPlane(); //drawUtils.draw3DCompass(); } } }, drawElementsOutline: { value: function(elements) { this.clearCanvas(); this.WalkDOM(this.application.ninja.currentDocument.documentRoot, elements); //drawUtils.updatePlanes(); if(this.application.ninja.currentDocument.draw3DGrid) { //drawUtils.drawWorkingPlane(); } //drawUtils.draw3DCompass(); } }, WalkDOM: { value: function(element, excludeArray) { if(!element) { return; } try { if(element.nodeType == 1 && this.application.ninja.currentDocument.inExclusion(element) === -1 ) { if(excludeArray) { var found = false; for(var j=0, elt; elt = excludeArray[j]; j++) { if(elt.uuid === element.uuid) { found = true; } } if(!found) { this.drawTagOutline(element); } } else { this.drawTagOutline(element); } } if(element.elementModel && element.elementModel.isComponent) { this.WalkDOM(element.nextSibling, excludeArray); } else { this.WalkDOM(element.firstChild, excludeArray); this.WalkDOM(element.nextSibling, excludeArray); } } catch (err) { console.log(err); } } }, // Alternate dashed line method. ___dashedLine: { value: function(x, y, x2, y2, dashArray) { this.ctx.lineCap = "square"; this.ctx.beginPath(); if(! dashArray) dashArray=[10,5]; var dashCount = dashArray.length; var dx = (x2 - x); var dy = (y2 - y); var xSlope = (Math.abs(dx) > Math.abs(dy)); var slope = (xSlope) ? dy / dx : dx / dy; this.ctx.moveTo(x, y); var distRemaining = Math.sqrt(dx * dx + dy * dy); var dashIndex = 0; while(distRemaining >= 0.1){ var dashLength = Math.min(distRemaining, dashArray[dashIndex % dashCount]); var step = Math.sqrt(dashLength * dashLength / (1 + slope * slope)); if(xSlope){ if(dx < 0) step = -step; x += step y += slope * step; }else{ if(dy < 0) step = -step; x += slope * step; y += step; } this.ctx[(dashIndex % 2 == 0) ? 'lineTo' : 'moveTo'](x, y); distRemaining -= dashLength; dashIndex++; } this.ctx.closePath(); this.ctx.stroke(); } }, _dashedLine: { value: function (fromX, fromY, toX, toY, pattern){ this.ctx.beginPath(); // Our growth rate for our line can be one of the following: // (+,+), (+,-), (-,+), (-,-) // Because of this, our algorithm needs to understand if the x-coord and // y-coord should be getting smaller or larger and properly cap the values // based on (x,y). var lt = function (a, b) { return a <= b; }; var gt = function (a, b) { return a >= b; }; var capmin = function (a, b) { return Math.min(a, b); }; var capmax = function (a, b) { return Math.max(a, b); }; var checkX = { thereYet: gt, cap: capmin }; var checkY = { thereYet: gt, cap: capmin }; if (fromY - toY > 0) { checkY.thereYet = lt; checkY.cap = capmax; } if (fromX - toX > 0) { checkX.thereYet = lt; checkX.cap = capmax; } this.ctx.moveTo(fromX, fromY); var offsetX = fromX; var offsetY = fromY; var idx = 0, dash = true; while (!(checkX.thereYet(offsetX, toX) && checkY.thereYet(offsetY, toY))) { var ang = Math.atan2(toY - fromY, toX - fromX); var len = pattern[idx]; offsetX = checkX.cap(toX, offsetX + (Math.cos(ang) * len)); offsetY = checkY.cap(toY, offsetY + (Math.sin(ang) * len)); if (dash) this.ctx.lineTo(offsetX, offsetY); else this.ctx.moveTo(offsetX, offsetY); idx = (idx + 1) % pattern.length; dash = !dash; } this.ctx.stroke(); } }, _elementName: { value: function(item) { return this.application.ninja.elementMediator.getNJProperty(item, "selection"); } } });