
registerType('appdoo', (function () { function Manipulator() {} var __super = setSupertypeFromDomain(Manipulator, 'BasicObject', 'Core');

// role BasicObject (Core) 
	
Manipulator.prototype.initFromData = function Manipulator_initFromData(data) {
		
			this.registeredItems = [];
	
			['frameView', 'contentWrapper', 'delegate', 'contentScale', 'overlayView', 'editedView', 'observableItemsController', 'showGuidelines', 'useKeyEvents', 'scrollWhenSelecting', 'useContextMenu', 'delegateIsOverview'].every(function (option) {
				this[option] = data[option];return true; }, this);
			
	
			this.registerEvents();
			this.observeObject(this.observableItemsController);
	
			if (data.showGuidelines) {
				this.guidelineController = createComponentFromDomain("GuidelineController", "appdoo.Editor", this.context, {
					overlayView: this.overlayView,
					manipulator: this})
				;
			}
	
			return this;
	};
		
		
Manipulator.prototype.destroy = function Manipulator_destroy() {
		
			if (this.editedView) {
	
				this.unselectAll(this);
				this.editedView = null;
				this.unregisterEvents();
			
			}
			
			if (this.guidelineController)
				this.guidelineController.destroy();
				
			__super.prototype.destroy.call(this);
			};
		
		
	


	
	
Manipulator.prototype.registerEvents = function Manipulator__registerEvents() {

		if (this._onMouseDownRef !== undefined) return;
	
		this._onMouseDownRef = this.mouseDownInFrame.bind(this);
		this.frameView.DOMNode.addEventListener('mousedown', this._onMouseDownRef);
	
		if (this.useKeyEvents) {
			this._onKeyDownRef = this.keyDownInFrame.bind(this);
			window.addEventListener('keydown', this._onKeyDownRef);
	
			this._onKeyUpRef = this.keyUpInFrame.bind(this);
			window.addEventListener('keyup', this._onKeyUpRef);
		}
		
		this.mouseDownInWindowHandler = function () {
			this.mouseIsDown = true;
		}.bind(this);
		window.addEventListener('mousedown', this.mouseDownInWindowHandler);


		this.mouseUpInWindowHandler = function () {
			if (this.mouseUpTimer) clearTimeout(this.mouseUpTimer);
			this.mouseIsDown = false;
		}.bind(this);
		window.addEventListener('mouseup', this.mouseUpInWindowHandler);

		Object.defineProperty(this, "_didChangeMainCbk", {
			configurable: true, 
			value: function (e) {
				this.windowFocusDidChange();
			}.bind(this)});
		

		window.addEventListener("didBecomeMain", this._didChangeMainCbk);
		window.addEventListener("didResignMain", this._didChangeMainCbk);
};
	

Manipulator.prototype.unregisterEvents = function Manipulator__unregisterEvents() {

		this.frameView.DOMNode.removeEventListener('mousedown', this._onMouseDownRef);
		window.removeEventListener('keydown', this._onKeyDownRef);
		window.removeEventListener('keyup', this._onKeyUpRef);
		window.removeEventListener('mousedown', this.mouseDownInWindowHandler);
		window.removeEventListener('mouseup', this.mouseUpInWindowHandler);
		window.removeEventListener("didBecomeMain", this._didChangeMainCbk);
		window.removeEventListener("didResignMain", this._didChangeMainCbk);

		delete this._onMouseDownRef;
		delete this._onKeyDownRef;
		delete this._onKeyUpRef;
		delete this.mouseDownInWindowHandler;
		delete this.mouseUpInWindowHandler;
};
	
	
Manipulator.prototype.windowFocusDidChange = function Manipulator__windowFocusDidChange() {
		this.isInActionMode = false;};
	


	

// role EditorListener 

		

Manipulator.prototype.viewDidAppear = function Manipulator_viewDidAppear(view) {
			this.registerEvents();};
		
	
Manipulator.prototype.viewDidDisappear = function Manipulator_viewDidDisappear(view) {
			this.unregisterEvents();};
		
		
Manipulator.prototype.hide = function Manipulator_hide() {
			this.overlayView.hidden = true;};
		

Manipulator.prototype.show = function Manipulator_show() {
			this.overlayView.hidden = false;};
		
	
	


	
	
	Object.defineProperty(Manipulator.prototype, "editedView", {
	synthesized: true, 
		set: function (v) {if (!Object.hasOwnProperty(this, "_editedView")) Object.defineProperty(this, "_editedView", { writable: true, configurable: true });
		
			if (this._editedView && this.editedViews) {

				this.isPerformingViewChange = true;

				if (Array.isArray(this.editedViews)) this.editedViews.every(function (item) {
					this.unregister(item, true);return true; }, this);
				
				
				if (this.observableItemsController.valueIsSelected(this._editedView)) {
					this.prepareForBeingEditable(this._editedView);
				}
				delete this._editedView;
			}
			
			if (v) {
				this._editedView = v;
				this.unregister(v);
				if (this.itemHasModifierButtons(v))
					this.removeModifierButtonsForItem(v);

				if (this.editedViews)
				if (Array.isArray(this.editedViews)) this.editedViews.every(function (item) {
					this.register(item);return true; }, this);
				
			}
			
			this.isPerformingViewChange = false;
			this.isFirstSelectionSinceEditedViewChange = true;
		}, get:function () { return this._editedView; }});
	


	

Manipulator.prototype.register = function Manipulator__register(item) {

		if (!this.itemIsSelectable(item)) return;
	
		if (!item || !item.DOMNode) {
			console.log('Invalid item:', item);
			console.trace();
			return;
		}
	
		if (this.registeredItems.indexOf(item.identify()) !== -1)
			return;
		
		
		Object.defineProperty(item, '_startX', { writable:true });
		Object.defineProperty(item, '_startY', { writable:true });
		Object.defineProperty(item, '_noresize', { writable:true });

		this.registeredItems.push(item.identify());

		Object.defineProperty(item, '_manipulatorOnMouseDown',
			{ value: this.mouseDownInNodeHandler.bind({
					item: item,
					self: this
				}), configurable: true });
			
		Object.defineProperty(item, '_manipulatorOnContextMenu',
			{ value: this.onContextMenuForNodeHandler.bind({ self: this, item: item }), configurable: true });

		var node = item.DOMNode;
		node.addEventListener('mousedown', item._manipulatorOnMouseDown);
		node.addEventListener('contextmenu', item._manipulatorOnContextMenu);
		node.className += ' canMove'
};
	

Manipulator.prototype.unregister = function Manipulator__unregister(item) {
	
		if (!item || !item.identify) {
			return;
		}
		
		var index = this.registeredItems.indexOf(item.identify());
		
		if (index === -1)
			return;
			
		this.registeredItems.splice(index, 1);

		delete item._startX;
		delete item._startY;
		delete item._noresize;
		
		item.DOMNode.removeEventListener('mousedown', item._manipulatorOnMouseDown);
		item.DOMNode.removeEventListener('contextmenu', item._manipulatorOnContextMenu);
		item.DOMNode.className = item.DOMNode.className.replace(/ canMove/, '');
		
		delete item._manipulatorOnMouseDown;
		delete item._manipulatorOnContextMenu;
	};
	

Manipulator.prototype.unregisterAll = function Manipulator__unregisterAll() {

		this.unselectAll();

		if (Array.isArray(this.editedViews)) this.editedViews.every(function (item) {
			this.unregister(item);return true; }, this);
		
	};
	


	
	
Manipulator.prototype.removeItem = function Manipulator__removeItem(item) {
		this.observableItemsController.removeValue(item, this);};
	

Manipulator.prototype.removeSelection = function Manipulator__removeSelection() {
	
		var selection = clone(this.observableItemsController.selectedValues);
		
		if (Array.isArray(selection)) selection.every(function (item) {
			this.removeItem(item);return true; }, this);
		
	};
	


	
	
Manipulator.prototype.beginSelecting = function Manipulator__beginSelecting() {
		this.observableItemsController.beginSelectionChange();};
	
	
Manipulator.prototype.endSelecting = function Manipulator__endSelecting() {
		this.observableItemsController.commitSelectionChange(this);};
	

Manipulator.prototype.isSelecting = function Manipulator__isSelecting() {
		return this.observableItemsController.isChangingSelection;};
	
	
Manipulator.prototype.itemIsSelectable = function Manipulator__itemIsSelectable(item) {
		if (!item) return false;
		if (item.locked) return false;
		return true;};
	

Manipulator.prototype.select = function Manipulator__select(item, sender) {
	
		if (!this.itemIsSelectable(item)) return;
	
		if (this.itemHasModifierButtons(item) === true) return;

		this.prepareForBeingEditable(item);
		
		if (sender === this) {
			this.beginSelecting();
			if (this.delegate.isInSubviewEditingMode &&
				this.observableItemsController.selectedValues.indexOf(this.editedView) !== -1)
				this.observableItemsController.unselectValue(this.editedView, this);
			this.observableItemsController.selectValue(item, this);
			this.endSelecting();
		}

		if (this.scrollWhenSelecting && !this.isSelecting())
			this.frameView.scrollToShowView(item);
		
		this.isFirstSelectionSinceEditedViewChange = false;
	};
	
	
Manipulator.prototype.prepareForBeingEditable = function Manipulator__prepareForBeingEditable(item) {
		this.addModifierButtonsForItem(item);
		if (item.selectForEditor) item.selectForEditor(this.delegate);};
	
	
Manipulator.prototype.prepareForBeingNotEditable = function Manipulator__prepareForBeingNotEditable(item) {
		if (!item) return;
		this.removeModifierButtonsForItem(item);
		if (item.unselectForEditor) item.unselectForEditor(this.delegate);};
	
	
Manipulator.prototype.unselect = function Manipulator__unselect(item, sender) {

		if (sender === this) {
			this.observableItemsController.unselectValue(item, this);
		}

		this.prepareForBeingNotEditable(item);
};
	

Manipulator.prototype.selectAll = function Manipulator__selectAll() {

		this.beginSelecting();

		if (Array.isArray(this.editedViews)) this.editedViews.every(function (item) {
			this.select(item, this);return true; }, this);
		

		this.endSelecting();
		};
	
	
Manipulator.prototype.unselectAll = function Manipulator__unselectAll() {
	
		this.beginSelecting();
	
		if (!this.observableItemsController)
			console.trace();
		
		var selection = clone(this.observableItemsController.selectedValues);
		if (!selection) return;
		if (Array.isArray(selection)) selection.every(function (item) {
			this.unselect(item, this);return true; }, this);
		
		
		this.endSelecting();
};
	
	
Manipulator.prototype.rotateSelection = function Manipulator__rotateSelection(backwards) {
	
		var selectedItem, itemToSelect, subviews = this.editedViews;
		
		if (backwards) subviews.reverse();

		if (Array.isArray(subviews)) subviews.every(function (subview) {
			if (this.observableItemsController.valueIsSelected(subview)) {
				selectedItem = subview;
				return false;
			}return true; }, this);
		

		if (selectedItem) {
			var index = subviews.indexOf(selectedItem);
			if (index < subviews.length-1) {
				itemToSelect = subviews[index+1];
			}
			else {
				itemToSelect = subviews[0];
			}
		}
		else {
			itemToSelect = subviews[0];
		}
		
		if (!itemToSelect) return;
		if (this.observableItemsController)
	 		this.observableItemsController.unselectAll();
		this.select(itemToSelect, this);
};
	


	
	
	var viewPrototype;
Manipulator.prototype.addModifierButtonsForItem = function Manipulator__addModifierButtonsForItem(item) {
	
		if (!viewPrototype) viewPrototype = getType('Core.UI.View');
		if (!(item instanceof viewPrototype)) return false;
	
		if (this.itemHasModifierButtons(item) === true)
			return;


		var sizeModifierButtons = [];
		for (var i = 0, c = 8; i !== c; i++) {
			var button = createComponentFromDomain("SpriteButton", "Core.UI", this.context, {
					size: { width: 13, height: 13 },
					sprite: this.context.pathForResource('SizeModifierButton.png'),
					keepHighlightedOnMouseOut: true,
					position: {left:0,top:-1000},
					style: {
						zIndex: 2,
						pointerEvents: 'all'
					},
					hidden: !item.sizeIsEditable})
				;

			button.tag = i;
			button.item = item;
			button.manipulator = this;
			button.DOMNode.onmousedown =
				this.mouseDownInModifierButton.bind(button);
			
			sizeModifierButtons.push(button);
			this.overlayView.addSubview(button);
		}
		
		var outlineStyle = item.displaysNoOutlineOnSelection ? '' : '1px solid rgba(180,180,180,.4)';
		
		var borderView = createComponentFromDomain("View", "Core.UI", this.context, {
					style: { zIndex: 1,
							 outline: outlineStyle,
							 pointerEvents: 'none'
							 }})
				;

		this.overlayView.addSubview(borderView);


		var coordinatesView = createComponentFromDomain("View", "Core.UI", this.context, {
			style: { backgroundColor: '#fffed4', borderRadius: '0px', padding: '1px 4px', paddingBottom: '3px', color: '#000', font: '10px "Lucida Grande"', whiteSpace: 'nowrap', webkitFontSmoothing: 'subpixel-antialiased',
				boxShadow: '0 3px 7px rgba(0,0,0,.3)', zIndex:2 },
			hidden: true})
		;
		this.overlayView.addSubview(coordinatesView);
	
		

		var sizeModifierButtonsController = createComponentFromDomain("SizeModifierButtonsController", "appdoo.Editor", this.context, {
			item: item,
			sizeModifierButtons: sizeModifierButtons,
			borderView: borderView,
			coordinatesView: coordinatesView,
			context: this.context,
			manipulator: this,
			contentWrapper: this.contentWrapper})
		;
		
		sizeModifierButtonsController.observeObject(item.dataController);
		
		if (0&&this.isFirstSelectionSinceEditedViewChange) {
			setTimeout(function () {
				sizeModifierButtonsController.positionButtons();
			},0);
		} else {
			sizeModifierButtonsController.positionButtons();
		}

		Object.defineProperty(item, '_sizeModifierButtonsController', {
			value: sizeModifierButtonsController,
			configurable: true
		});
	};
	
	
Manipulator.prototype.removeModifierButtonsForItem = function Manipulator__removeModifierButtonsForItem(item) {

		if (!this.itemHasModifierButtons(item))
			return;

		try {
			var smbc = item._sizeModifierButtonsController;
			delete item._sizeModifierButtonsController;
			smbc.destroy();
		} catch (e) {
			console.warn('Error removing the size modifiers. Race condition?', e);
			console.trace();
		}
};
	
	
Manipulator.prototype.itemHasModifierButtons = function Manipulator__itemHasModifierButtons(item) {
		return (item !== undefined && item._sizeModifierButtonsController !== undefined);};
	
	
Manipulator.prototype.removeAllModifierButtons = function Manipulator__removeAllModifierButtons() {
		if (Array.isArray(this.editedViews)) this.editedViews.every(function (item) {
			if (this.itemHasModifierButtons(item)) {
				this.removeModifierButtonsForItem(item);
			}return true; }, this);
		};
	
	

	

	Object.defineProperty(Manipulator.prototype, "contentScale", {
		set: function (v) {
			var previousValue = this._contentScale;
			this._contentScale = v;
			if (previousValue !== undefined) 
				this.scaleDidChange();
		}, 
		get: function () {
			return this._contentScale;
		}});
	

Manipulator.prototype.setShiftKeyDownWithEvent = function Manipulator__setShiftKeyDownWithEvent(trueOrFalse, e) {
		return;};
	

	
	

Manipulator.prototype.keyDownInFrame = function Manipulator__keyDownInFrame(e) {
	
		var self = this;
		
		if (e.keyCode === 18 || e.keyCode === 91) {
			this.isInActionMode = e.metaKey && e.altKey;
			return;
		}
		
		
		if (e.target != document.body)
			return;
		
		if (e.keyCode === 8 || e.keyCode === 46) {
			if (this.delegate.deleteSelection() !== false)
			e.preventDefault();
			return;
		}
		
		
		if (!e.metaKey && (e.keyCode >= 37 && e.keyCode <= 40)) {

			var deltaX = 0, deltaY = 0;
			if (e.keyCode == 37) {
				deltaX -= e.shiftKey ? 10 : 1;
			}
			else if (e.keyCode == 38) {
				deltaY -= e.shiftKey ? 10 : 1;
			}
			else if (e.keyCode == 39) {
				deltaX += e.shiftKey ? 10 : 1;
			}
			else if (e.keyCode == 40) {
				deltaY += e.shiftKey ? 10 : 1;
			}
			
			var selection = self.observableItemsController.selectedValues;
			if (Array.isArray(selection)) selection.every(function (item) {
				if (!item.positionIsEditable) return true;

				if (deltaX) {
					if (!item.xIsEditable) return true;
					item.dataController.set({
						'position.left': item.position.left + deltaX
					});
				}
				else if (deltaY) {
					if (!item.yIsEditable) return true;
					item.dataController.set({
						'position.top': item.position.top + deltaY
					});
				}
return true; }, this);
			
			
			this.delegate.manipulatorDidMoveItems(this, selection);

			e.preventDefault();
			return;
		}

		if (e.shiftKey === true) {
			this.setShiftKeyDownWithEvent(true,e);
		}
		};
	

Manipulator.prototype.keyUpInFrame = function Manipulator__keyUpInFrame(e) {

		this.isInActionMode = e.metaKey && e.altKey;

		if (e.shiftKey === false) {
			this.setShiftKeyDownWithEvent(false, e);
		}
	};
	

Manipulator.prototype.mouseDownInFrame = function Manipulator__mouseDownInFrame(e) {

		if (isContextMenuEvent(e))
			return;
	
		if (this.didClickModifierButton === true)
			return;
			
		if (this.didClickNode === true)
			return;
			
		if (this.frameView.mouseEventTargetsScrollbars(e))
			return;

		var aX = this.frameView.getRelativeX(e.x),
			aY = this.frameView.getRelativeY(e.y);

		var startX = (e.x - this.frameView.DOMNode.offsetLeft)
					 + this.frameView.DOMNode.scrollLeft,
			startY = (e.y - this.frameView.DOMNode.offsetTop)
					 + this.frameView.DOMNode.scrollTop;
		
		startX = aX;
		startY = aY;

		this.updateOffsets();
	
		this.dragRect = document.createElement('DIV');
		this.dragRect.style.left = startX + 'px';
		this.dragRect.style.top = startY + 'px';
		this.dragRect.style.pointerEvents = 'none';
		this.dragRect.style.border = '1px solid rgba(167,195,233,.5)';
		this.dragRect.style.backgroundColor = 'rgba(132,173,228,.3)';
		this.dragRect.style.position = 'absolute';
		this.dragRect.style.zIndex = 10000;
		this.dragRect.id = 'dragrect';
		this.frameView.DOMNode.appendChild(this.dragRect);
		
		var mouseDidMove = false;

		var self = this;
		
		
		var mouseMoveFunc = (function() {
			return function(_e) {
				if (mouseDidMove === false) {
					mouseDidMove = true;
					if (!e.shiftKey && !e.metaKey)
						self.unselectAll();
					self.selectionBefore = self.observableItemsController.selectedValues;
				}
			
				self.dragRectMoveFunc(
					_e,
					startX, startY,
					-aX+e.x,	-aY+e.y);
			};
		})();

		window.addEventListener('mousemove', mouseMoveFunc, false);
		window.addEventListener('mouseup', function onMouseUp(e) {

			if (mouseDidMove === false) {
				if (!e.shiftKey && !e.metaKey) {
					self.unselectAll();
				}
			}

			if (self.dragRect) {
				self.dragRect.parentNode.removeChild(self.dragRect);
				delete self.dragRect;
			}

			window.removeEventListener('mousemove', mouseMoveFunc, false);
			window.removeEventListener('mouseup', onMouseUp, false);
			
			self.selectionBefore = null;

		}, false);};
	

Manipulator.prototype.dragRectMoveFunc = function Manipulator__dragRectMoveFunc(e, startX, startY, offsetX, offsetY) {

	
		var deltaX = (e.x - startX) - offsetX,
			deltaY = (e.y - startY) - offsetY,
			dragRect = this.dragRect;
			
		if (deltaX < 0) {	dragRect.style.left = (startX + deltaX) + 'px';
		} else {			dragRect.style.left = startX + 'px';
		}
	
		if (deltaY < 0) {	dragRect.style.top = startY + deltaY + 'px';
		} else {			dragRect.style.top = startY + 'px';
		}

		dragRect.style.width = Math.abs(deltaX) + 'px';
		dragRect.style.height = Math.abs(deltaY) + 'px';
		
		
		var r1 = [ dragRect.offsetLeft, dragRect.offsetTop,
				   dragRect.offsetWidth, dragRect.offsetHeight ];

		r1[0] -= this.frameViewOffset.left;
		r1[1] -= this.frameViewOffset.top;
		r1[2] += r1[0];
		r1[3] += r1[1];
		

		
		if (this._contentScale !== 1) {
			for (var i = 0, c = 4; i != c; i++) {
				r1[i] /= this._contentScale;
			}
		}
		
		
		r1[0] -= this.contentOffset.left;
		r1[1] -= this.contentOffset.top;
		r1[2] -= this.contentOffset.left;
		r1[3] -= this.contentOffset.top;
		

		var items = this.editedViews;
		if (!items) return;
		
		if (Array.isArray(items)) items.every(function (item) {
			if (item.locked) return true;
			
			var node = item.DOMNode;
	
			var r2 = [ node.offsetLeft,
					   node.offsetTop,
					   node.offsetWidth,
					   node.offsetHeight ];

			r2[2] += r2[0];
			r2[3] += r2[1];
	
			if (this.rectsCollide(r1, r2)) {
				if (e.metaKey) {
					if (this.selectionBefore.indexOf(item) !== -1)
						this.unselect(item, this);
					else this.select(item, this);
				}
				else {
					this.select(item, this);
				}
			}
			else {
				if (this.selectionBefore.indexOf(item) === -1)
					this.unselect(item, this);
				else if (e.metaKey)
					this.select(item, this);
			}
			return true; }, this);
		
		};
	
	
	Object.defineProperty(Manipulator.prototype, "editedViews", {
		get: function () {
			return this.delegate.editedViewsForManipulator(this.editedView);
		}});
	

Manipulator.prototype.selectionDidChange = function Manipulator__selectionDidChange(sender) {
	
	};
	
	
	function xyPos(itemPosition) {
		return {
			x: itemPosition.left,
			y: itemPosition.top
		};
	}

Manipulator.prototype.mouseDownInModifierButton = function Manipulator__mouseDownInModifierButton(e) {
	
		
		
		var self = this.manipulator, 
			item = this.item,
			startX = e.x,
			startY = e.y,
			startW = item.size.width,
			startH = item.size.height,
			itemLeft = item.position.left,
			itemTop = item.position.top,
			itemSize = item.size,
			itemPosition = item.position;

		var altKey = e.shiftKey,
			mode;

		if (this.tag === 0) 
			mode = 1;
		else if (this.tag === 2) 
			mode = 2;
		else if (this.tag === 5) 
			mode = 3;
		else if (this.tag === 7) 
			mode = 4;
		else if (this.tag === 3) 
			mode = 5;
		else if (this.tag === 1) 
			mode = 6;
		else if (this.tag === 4) 
			mode = 7;
		else if (this.tag === 6) 
			mode = 8;
			

		var changedKeyPaths = [
			'position.left', 'position.top',
			'size.width', 'size.height'
		];
		
		
		var selection = self.observableItemsController.selectedValues;

		if (altKey) {
			if (Array.isArray(selection)) selection.every(function (item) {
				item.dataController.beginChangingValuesForKeyPaths(changedKeyPaths);return true; }, this);
			
		}
		else {
			item.dataController.beginChangingValuesForKeyPaths(changedKeyPaths);
		}


		e.stopPropagation();

		if (self.guidelineController) {
			self.guidelineController.beginShowingGuidelines();
		}
		
		item._sizeModifierButtonsController.showCoordinatesDelayedInMode(1);
		
		self.mouseIsDown = true;
		
		function updateObjectKeyValue(obj, key, value, altKey) {
			
			if (altKey) {
				
				var objKey = (key === 'width' || key === 'height') ? 'size' : 'position';
				
				if (Array.isArray(selection)) selection.every(function (item) {
					if (!item[key+'IsEditable']) return true;
					item[objKey][key] = value;
					item._sizeModifierButtonsController.positionButtons();return true; }, this);
				
			}
			else
				obj[key] = value;
		}

		window.onmousemove = function (e) {
		
			if (self.guidelineController)
				self.guidelineController.clear();

			item.viewWillResize();
			
			if (mode === 4 || mode === 7 || mode === 2) {
				var w = parseInt(startW + (e.x - startX) / self._contentScale);
				if (self.guidelineController)
					w = self.guidelineController.guideWidth(w, xyPos(itemPosition), {width:w, height:itemSize.height}, true);
				if (w < 1) w = 1;
				updateObjectKeyValue(itemSize, 'width', w, altKey);
			}
			if (mode === 4 || mode === 8 || mode === 3) {
				var h = parseInt(startH + (e.y - startY) / self._contentScale);
				if (self.guidelineController)
					h = self.guidelineController.guideHeight(h, xyPos(itemPosition), {width:itemSize.width, height:h}, true);
				if (h < 1) h = 1;
				updateObjectKeyValue(itemSize, 'height', h, altKey);
			}
			
			if (mode === 1 || mode === 3 || mode === 5) {
				var x = parseInt((e.x - startX) / self._contentScale),
					left = itemLeft + x,
					w = parseInt(startW - x);

				var pos = { x:left, y:itemPosition.top };
				if (self.guidelineController)
					self.guidelineController.guidePositionForSize(pos, {width:w, height:itemSize.height}, true, false, true);
				var diff = pos.x-left;
				left += diff;
				w -= diff;

				if (w < 1) { w = 1; return; }
				updateObjectKeyValue(itemSize, 'width', w, altKey);
				updateObjectKeyValue(itemPosition, 'left', left, altKey);
			}
			if (mode === 1 || mode === 6 || mode === 2) {
				var y = parseInt((e.y - startY) / self._contentScale),
					top = itemTop + y,
					h = parseInt(startH - y);

				var pos = { x:itemPosition.left, y:top };
				if (self.guidelineController)
					self.guidelineController.guidePositionForSize(pos, {width:itemSize.width, height:h}, true, false, true);
				var diff = pos.y-top;
				top += diff;
				h -= diff;

				if (h < 1) { h = 1; return; }
				updateObjectKeyValue(itemSize, 'height', h, altKey);
				updateObjectKeyValue(itemPosition, 'top', top, altKey);
			}


			item.viewDidResize();
			item._sizeModifierButtonsController.positionButtons();
			item._sizeModifierButtonsController.updateCoordinates();

			if (1) {
				item.dataController.context.broadcastValueChangeForKeyPathInObject('size.width', item.dataController, item.dataController);
				item.dataController.context.broadcastValueChangeForKeyPathInObject('size.height', item.dataController, item.dataController);
				item.dataController.context.broadcastValueChangeForKeyPathInObject('position.left', item.dataController, item.dataController);
				item.dataController.context.broadcastValueChangeForKeyPathInObject('position.top', item.dataController, item.dataController);
			}

		};

		window.onmouseup = function (e) {
			self.mouseIsDown = false;
			self.didClickModifierButton = false;
			window.onmousemove = null;
			window.onmouseup = null;
			
			if (altKey) {
				if (Array.isArray(selection)) selection.every(function (item) {
					item.dataController.endChangingValuesForKeyPaths(changedKeyPaths);return true; }, this);
				
			}
			else {
				item.dataController.endChangingValuesForKeyPaths(changedKeyPaths);
			}
			
			
			if (self.guidelineController)
				self.guidelineController.endShowingGuidelines();
			item._sizeModifierButtonsController.hideCoordinates();
		};

		self.didClickModifierButton = true;
		};
	
	
Manipulator.prototype.scaleDidChange = function Manipulator__scaleDidChange() {

		this.updateSizeModifierButtons();
		this.updateOffsets();

		if (this.guidelineController && !this.guidelineController.hidden) {
			this.guidelineController.endShowingGuidelines();
			this.guidelineController.beginShowingGuidelines();
		}
		};
	
	
Manipulator.prototype.updateSizeModifierButtons = function Manipulator_updateSizeModifierButtons() {
		if (Array.isArray(this.observableItemsController.selectedValues)) this.observableItemsController.selectedValues.every(function (item) {
			if (item._sizeModifierButtonsController)
				item._sizeModifierButtonsController.positionButtons();return true; }, this);
		};
	

	
Manipulator.prototype.rectsCollide = function Manipulator__rectsCollide(r1, r2) {
		if (r1[3] < r2[1]) return false;
		if (r1[1] > r2[3]) return false;
		if (r1[2] < r2[0]) return false;
		if (r1[0] > r2[2]) return false;
		return true;};
	
	
	function isContextMenuEvent(e) {
		return e.button === 2 || e.ctrlKey;
	}

Manipulator.prototype.mouseDownInNodeHandler = function Manipulator__mouseDownInNodeHandler(e) {
	
		if (e.metaKey && e.altKey) return; 

		var item =		this.item,
			node = 		item.DOMNode,
			self =		this.self;

		self.context.showGrabCursor();
		
		var activeElementIsBody = document.activeElement === document.body;

		if (!self.delegateIsOverview) {
			
			
			e.preventDefault();
			
			
			
			if (document.activeElement.tagName === 'INPUT' ||
				document.activeElement.tagName === 'TEXTAREA')
				document.activeElement.blur();
		}

		if (!isContextMenuEvent(e))
			self.didClickNode = true;
		
		if (this.mouseUpTimer) clearTimeout(this.mouseUpTimer);
		
		if (activeElementIsBody) {
			self.mouseIsDown = true;
			self.mouseDownInNodeHandlerAfterDelay(e, item, node);
		}
		else {
			this.mouseUpTimer = setTimeout(function () {
				this.mouseDownInNodeHandlerAfterDelay(e, item, node);
				this.mouseUpTimer = null;
			}.bind(self), 1);
		}
		};
	
	
Manipulator.prototype.mouseDownInNodeHandlerAfterDelay = function Manipulator__mouseDownInNodeHandlerAfterDelay(e, item, node) {

		if (!this.mouseIsDown) {
			if (this.wantsContextMenu) {
				this.onContextMenuForNodeHandlerAfterDelay(e);
			}
			return;
		}
	
		var self = this;

		if (this.didClickModifierButton) return;

		this.beginSelecting();
		if (this.observableItemsController.valueIsSelected(item) === false) {
			if (e.shiftKey !== true && e.metaKey !== true) {
				this.unselectAll();
			}
			this.select(item, this);
		}
		else {
			if (e.shiftKey === true || e.metaKey === true) {
				this.unselect(item, this);
			}
		}
		this.endSelecting();

		
		if (isContextMenuEvent(e)) return;

		this.didClickNode = true;
			
		selection = this.observableItemsController.selectedValues;
		this.beginDraggingSelection();

			
		
		
		scale = this._contentScale;
		willMoveCallback = this.delegate.manipulatorWillMoveItems.bind(this.delegate);
		guidelineController = this.guidelineController;
		position = { x: 0, y: 0 };
		mouseDownEvent = e;
		mouseDidMove = false;
		didCopyDrag = false;

		if (guidelineController)
			guidelineController.beginShowingGuidelines();

		var mouseMoveFunc = function (_e) {
			if (!mouseDidMove && !_e.shiftKey && !_e.metaKey && _e.altKey) {

				

				mouseDidMove = true;
				self.isCreatingCopy = true;
				self.endDraggingSelection();
				self.delegate.duplicateSelection();
				self.isCreatingCopy = false;

				selection = self.observableItemsController.selectedValues;
				self.beginDraggingSelection();
				
				didCopyDrag = true;

			}
			self.moveSelectionWithEvent.call(self, _e);
		};

		var mouseUpFunc = function (_e) {

			self.didClickNode = false;
			window.removeEventListener('mouseup', mouseUpFunc, false);
			window.removeEventListener('mousemove', mouseMoveFunc, false);

			var deltaX = (- e.x + _e.x) / scale,
				deltaY = (- e.y + _e.y) / scale;

			var changedKeyPaths =
				(deltaX && deltaY) ? ['position.left', 'position.top'] :
				deltaX ? ['position.left'] :
				deltaY ? ['position.top'] :
				[];
				
			this.endDraggingSelection(changedKeyPaths);
			self.delegate.manipulatorDidMoveItems(this, selection);
			
			if (guidelineController)
				guidelineController.endShowingGuidelines();

		}.bind(this);
		

		window.addEventListener('mousemove', mouseMoveFunc, false);
		window.addEventListener('mouseup', mouseUpFunc, false);
};
	
	
Manipulator.prototype.beginDraggingSelection = function Manipulator__beginDraggingSelection() {

		if (Array.isArray(selection)) selection.every(function (item) {
		
			if (!item.DOMNode) return true;
			if (!item.positionIsEditable) return true;

			item._startX = item.DOMNode.offsetLeft;
			item._startY = item.DOMNode.offsetTop;

			
			

			item.dataController.beginChangingValuesForKeyPaths([
				'position.left', 'position.top' ]);

			if (item._sizeModifierButtonsController) {
				item._sizeModifierButtonsController.showCoordinatesDelayedInMode(0);
			}
			return true; }, this);
		
		};
	

Manipulator.prototype.endDraggingSelection = function Manipulator__endDraggingSelection(changedKeyPaths) {

		if (!changedKeyPaths)
			changedKeyPaths = [];
	
		if (didCopyDrag) {
			
			
			this.context.undoManager.disableRegistration();
		}

		if (Array.isArray(selection)) selection.every(function (item) {
			if (!item.positionIsEditable) return true;
			item.dataController.endChangingValuesForKeyPaths(changedKeyPaths);
			if (item._sizeModifierButtonsController) {
				item._sizeModifierButtonsController.hideCoordinates();
			}return true; }, this);
		
	
		if (didCopyDrag) {
			this.context.undoManager.enableRegistration();
		}};
	
	
Manipulator.prototype.onContextMenuForNodeHandler = function Manipulator__onContextMenuForNodeHandler(e) {

		var self = this.self;

		if (!self.useContextMenu) return;

		e.stopPropagation();
		e.preventDefault();

		self.wantsContextMenu = true;
		self.onContextMenuForNodeHandlerAfterDelay(e);

};
	

Manipulator.prototype.onContextMenuForNodeHandlerAfterDelay = function Manipulator__onContextMenuForNodeHandlerAfterDelay(e) {
		
		var menu = this.delegate.contextMenuForItems(this.observableItemsController.selectedValues);
		if (!menu) return;
		
		menu.x = e.x;
		menu.y = e.y;

		this.context.showContextMenu(menu);
		this.wantsContextMenu = false;

};
	
	
	
	
	
	var mouseDidMove, mouseDownEvent, willMoveCallback, scale, guidelineController, position, selection, x, y, didCopyDrag;
	
Manipulator.prototype.moveSelectionWithEvent = function Manipulator__moveSelectionWithEvent(_e) {
	
		if (mouseDidMove === false) {
			willMoveCallback(this, selection);
			mouseDidMove = true;
		}
		else {
			if (guidelineController)
				guidelineController.clear();
		}
	
		var deltaX = (- mouseDownEvent.x + _e.x) / scale,
			deltaY = _e.shiftKey ? 0 : (- mouseDownEvent.y + _e.y) / scale,
			deltaXLocked = false,
			deltaYLocked = false;

		
		
		if (Array.isArray(selection)) selection.every(function (item) {
			if (!item.positionIsEditable) return true;
			
			x = parseInt(item._startX + deltaX);
			y = parseInt(item._startY + deltaY);
			position.x = x,
			position.y = y;
			
			if (guidelineController) guidelineController.guidePositionForSize(position, item._size);

			if (position.x !== x) {
				deltaXLocked = true;
				deltaX += (position.x-x);
				if (deltaYLocked === true)
					return false;
			}
			
			if (position.y !== y) {
				deltaYLocked = true;
				deltaY += (position.y-y);
				if (deltaXLocked === true)
					return false;
			}return true; }, this);
		

		
		if (Array.isArray(selection)) selection.every(function (item) {
		
			if (!item.positionIsEditable) return true;
		
			x = parseInt(item._startX + deltaX);
			y = parseInt(item._startY + deltaY);

			position.x = x,
			position.y = y;
			
			
			
			

			item.dataController.set({
				'position.left': x,
				'position.top': y
			});
			item.dataController.context.broadcastValueChangeForKeyPathInObject('position.left', item.dataController, item.dataController);
			item.dataController.context.broadcastValueChangeForKeyPathInObject('position.top', item.dataController, item.dataController);
			
			if (item._sizeModifierButtonsController) {
				item._sizeModifierButtonsController.positionButtons();
				item._sizeModifierButtonsController.updateCoordinates();
			}
return true; }, this);
		

		this.delegate.manipulatorIsMovingItems(this, selection);
	};
	

Manipulator.prototype.updateOffsets = function Manipulator__updateOffsets() {
	
		var contentWrapper = this.contentWrapper;

		this.frameViewOffset = {
			left: contentWrapper.position.left,
			top: contentWrapper.position.top
		};
		
		this.contentOffset = {
			left: 0,
			top: 0
		};
		
		var _view = this.editedView;
		do {
			if (!_view) break;
			this.contentOffset.left += _view.position.left || 0;
			this.contentOffset.top += _view.position.top || 0;
			_view = _view.superview;
		}
		while (_view !== contentWrapper);	
			};
	


	

// role Observer (Core) 

Manipulator.prototype.observedObjectSelectionDidChangeForKeyPath = function Manipulator_observedObjectSelectionDidChangeForKeyPath(obj, keyPath, isSelected, sender) {

			
			
			if (this.mouseIsDown && !this.isCreatingCopy && !this.wantsContextMenu) return;
		
			if (!obj.nodeForKeyPath) return;
		
			var node = obj.nodeForKeyPath(keyPath);
			if (!node) {
				console.log('node not found', keyPath, obj.rootNode);
				return;
			}
			
			if (node.representedObject === this.editedView)
				return;

			if (isSelected === true)
				this.select(node.representedObject, sender);
			else
				this.unselect(node.representedObject, sender);
};
		
		
Manipulator.prototype.observedObjectValueDidDisappearForKey = function Manipulator_observedObjectValueDidDisappearForKey(obj, value, key, sender) {

			var item = value.representedObject ? value.representedObject : value;
			this.unselect(item);
			this.unregister(item);
};
		

Manipulator.prototype.observedObjectValueDidAppearForKey = function Manipulator_observedObjectValueDidAppearForKey(obj, key, sender) {

			var item = obj.get(key);
			if (!item) {
				console.warn('item is '+item+' in observedObjectValueDidAppearForKey(obj, key, sender)', obj, key, sender);
				return;
			}
			if (item.superview === this.editedView)
				this.register(item, sender);};
		

	
	
	
	
	
	Object.defineProperty(Manipulator.prototype, "isInActionMode", {
	synthesized: true, 
		set: function (v) {if (!Object.hasOwnProperty(this, "_isInActionMode")) Object.defineProperty(this, "_isInActionMode", { writable: true, configurable: true });
			if (this._isInActionMode === v) return;
			this._isInActionMode = v;
			document.body.className = v ? 'inActionMode' : '';
		}, get:function () { return this._isInActionMode; }});
	

Manipulator.prototype.expectedTypeForProperty = function Manipulator_expectedTypeForProperty(key) {
	if (key === "editedView") return "";
	if (key === "contentScale") return "";
	if (key === "editedViews") return "";
	if (key === "isInActionMode") return "";
	if (__super) return __super.prototype.expectedTypeForProperty(key);
};

return Manipulator; }()));