// ========================================================================== // Project: Greenhouse.AnchorView // Copyright: ©2010 Mike Ball // ========================================================================== /*globals Greenhouse */
/**
(Document Your View Here) @extends SC.View
*/ Greenhouse.AnchorView = SC
.View.extend( /** @scope Greenhouse.AnchorView.prototype */ {
/** The anchor location to display */ anchorLocation: null, /** Enabled/disable */ isEnabled: YES, /** Set to YES while the mouse is pressed. */ isActive: NO, /** Proposed anchor location. Changes as mouse moves/drags */ proposedAnchorLocation: null, displayProperties: "anchorLocation isEnabled isActive proposedAnchorLocation".w(), render: function(context, firstTime) { if (firstTime) { var f = this.get('frame'); context.begin('canvas') .attr('width', f.width).attr('height', f.height) .end(); } }, didCreateLayer: function() { this.didUpdateLayer(); }, didUpdateLayer: function() { var elem = this.$('canvas'), ctx = elem[0].getContext("2d"), width = this.$().width(), height = this.$().height(), loc = this.get('anchorLocation'), ploc, color, x, y, tmp; // adjust size as needed... if (Number(elem.attr('width')) !== width) elem.attr('width', width); if (Number(elem.attr('height')) !== height) elem.attr('height', height); width--; height--; // adjust for being off 0.5 // do the drawr-ing! if (!this.get('isEnabled')) loc = null; color = loc ? 'black' : 'rgb(128,128,128)'; ctx.save(); ctx.lineWidth = 1; ctx.fillStyle = 'rgb(255,255,255)'; ctx.strokeStyle = color; ctx.fillRect(0.5, 0.5, width, height); ctx.strokeRect(0.5, 0.5, width, height); ctx.strokeStyle = color; ctx.strokeRect(20.5, 20.5, width-40, height-40); ctx.beginPath(); ctx.moveTo(Math.floor(width/2)+0.5, 20.5); ctx.lineTo(Math.floor(width/2)+0.5, Math.floor(height-20)+0.5); ctx.moveTo(20.5, Math.floor(height/2)+0.5); ctx.lineTo(Math.floor(width-20)+0.5, Math.floor(height/2)+0.5); ctx.stroke(); ctx.restore(); loc = this.get('anchorLocation'); ploc = this.get('proposedAnchorLocation'); if (ploc && ploc !== loc) { color = this.get('isActive') ? 'rgb(80,80,80)' : 'rgb(200,200,200)'; this._drawAnchorAt(ploc, ctx, color, width, height); } this._drawAnchorAt(loc, ctx, 'red', width, height); }, // .......................................................... // MOUSE EVENTS // mouseMoved: function(evt) { this._updateProposedAnchorLocation(evt); }, mouseExited: function(evt) { this.setIfChanged('proposedAnchorLocation', null); }, mouseDown: function(evt) { if (this.get('isEnabled') && this.get('anchorLocation')) { this.get('mouseDown'); this.set('isActive', YES); this._updateProposedAnchorLocation(evt); } return YES ; }, mouseDragged: function(evt) { if (this.get('isActive')) this._updateProposedAnchorLocation(evt); return YES ; }, mouseUp: function(evt) { var loc; if (this.get('isActive')) { this._updateProposedAnchorLocation(evt); loc = this.get('proposedAnchorLocation'); if (loc) this.setIfChanged('anchorLocation', loc); this.set('isActive', NO); } return YES ; }, // .......................................................... // PRIVATE // _updateProposedAnchorLocation: function(evt) { var loc = this.get('anchorLocation'), pnt = this.convertFrameFromView({ x: evt.pageX, y: evt.pageY },null), K = SC.ViewDesigner, rad, f, w, h, ret, centerAnchor, centerResize; if (!this.get('isEnabled') || !loc) ret = null; else { rad = 10; f = SC.copy(this.get('frame')); // calc outside rect f.x = f.y = 20; f.width -= 40 ; f.height -= 40; if (Math.abs(pnt.x - SC.minX(f))<=rad) w = K.ANCHOR_LEFT; else if (Math.abs(pnt.x - SC.midX(f))<=rad) w = K.ANCHOR_CENTERX; else if (Math.abs(pnt.x - SC.maxX(f))<=rad) w = K.ANCHOR_RIGHT; else w = 0; if (Math.abs(pnt.y - SC.minY(f))<=rad) h = K.ANCHOR_TOP; else if (Math.abs(pnt.y - SC.midY(f))<=rad) h = K.ANCHOR_CENTERY; else if (Math.abs(pnt.y - SC.maxY(f))<=rad) h = K.ANCHOR_BOTTOM; else h = 0; // not in a regular anchor zone; look for edges... if (w===0 || h===0) { rad /= 2; if (Math.abs(pnt.x - SC.minX(f))<=rad) { ret = K.ANCHOR_LEFT | K.ANCHOR_HEIGHT; } else if (Math.abs(pnt.x - SC.midX(f)) <= rad) { ret = K.ANCHOR_CENTERX | K.ANCHOR_HEIGHT; } else if (Math.abs(pnt.x - SC.maxX(f)) <= rad) { ret = K.ANCHOR_RIGHT | K.ANCHOR_HEIGHT; } else if (Math.abs(pnt.y - SC.minY(f)) <= rad) { ret = K.ANCHOR_WIDTH | K.ANCHOR_TOP; } else if (Math.abs(pnt.y - SC.midY(f)) <= rad) { ret = K.ANCHOR_WIDTH | K.ANCHOR_CENTERY; } else if (Math.abs(pnt.y - SC.maxY(f)) <= rad) { ret = K.ANCHOR_WIDTH | K.ANCHOR_BOTTOM; } } else ret = w|h; if (ret === 0) ret = null; } // alternate between center anchor/resize if options... centerAnchor = K.ANCHOR_CENTERX | K.ANCHOR_CENTERY; centerResize = K.ANCHOR_WIDTH | K.ANCHOR_HEIGHT; if (loc===ret) { if (ret===centerAnchor) ret = centerResize; else if (ret===centerResize) ret = centerAnchor; } this.setIfChanged('proposedAnchorLocation', ret); }, _drawAnchorAt: function(loc, ctx, color, width, height) { var x = this._xForAnchorLocation(loc, 20, width-40), y = this._yForAnchorLocation(loc, 20, height-40), tmp; // if either is zero - don't do anything if (x && y) { ctx.save(); ctx.strokeStyle = color; // if x|y < 0, then draw over lines to show height/width if (x<0) { tmp = Math.floor(Math.abs(y)); ctx.lineWidth = 2; ctx.beginPath(); ctx.arc(20.5, tmp, 3, 0, Math.PI*2, true); ctx.lineTo(Math.floor(width-20)-3.5, tmp); ctx.arc(Math.floor(width-20), tmp, 3, Math.PI, Math.PI*2, true); ctx.arc(Math.floor(width-20), tmp, 3, 0, Math.PI, true); ctx.stroke(); } if (y<0) { tmp = Math.floor(Math.abs(x)); ctx.lineWidth = 2; ctx.beginPath(); ctx.arc(tmp, 20.5, 3, 0, Math.PI*2, true); ctx.moveTo(tmp, 23.5); ctx.lineTo(tmp, Math.floor(height-20)-3.5); ctx.arc(tmp, Math.floor(height-20), 3, Math.PI*1.5, Math.PI*2, true); ctx.arc(tmp, Math.floor(height-20), 3, 0, Math.PI*1.5, true); ctx.stroke(); } if (x>0 && y>0) { ctx.beginPath(); ctx.lineWidth = 2; ctx.arc(x,y,10,0,Math.PI*2, true); ctx.stroke(); } ctx.restore(); } }, _xForAnchorLocation: function(loc, left, w) { var K = SC.ViewDesigner, ret ; if (loc & K.ANCHOR_LEFT) ret = left; else if (loc & K.ANCHOR_RIGHT) ret = left+w; else if (loc & K.ANCHOR_CENTERX) ret = left+Math.floor(w/2); else if (loc & K.ANCHOR_WIDTH) ret = 0-(left+Math.floor(w/2)) ; else ret = 0; return ret ; }, _yForAnchorLocation: function(loc, top, h) { var K = SC.ViewDesigner, ret ; if (loc & K.ANCHOR_TOP) ret = top; else if (loc & K.ANCHOR_BOTTOM) ret = top+h; else if (loc & K.ANCHOR_CENTERY) ret = top+Math.floor(h/2); else if (loc & K.ANCHOR_HEIGHT) ret = 0-(top+Math.floor(h/2)) ; else ret = 0; return ret ; }
});