author | Sam Foster <sfoster@mozilla.com> |
Tue, 09 Jul 2013 18:04:08 -0700 | |
changeset 137940 | d65cb3cb55f525e110c1523e5ed5d4cdd2f99cd6 |
parent 137939 | f8257d93273a6c36a4aeb6f3fc6332d6a2a4b5b5 |
child 137941 | e54450e7bb5c93ce58e93caad30857f7603def59 |
push id | 24939 |
push user | ryanvm@gmail.com |
push date | Wed, 10 Jul 2013 17:49:39 +0000 |
treeherder | mozilla-central@dde4dcd6fa46 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | jwilde |
bugs | 835984 |
milestone | 25.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/browser/metro/base/content/bindings/grid.xml +++ b/browser/metro/base/content/bindings/grid.xml @@ -635,18 +635,88 @@ return; let event = document.createEvent("Events"); event.initEvent("selectionchange", true, true); this.dispatchEvent(event); ]]> </body> </method> + + <method name="bendItem"> + <parameter name="aItem"/> + <parameter name="aEvent"/> + <body><![CDATA[ + // apply the transform to the contentBox element of the item + let bendNode = 'richgriditem' == aItem.nodeName && aItem._contentBox; + if (!bendNode) + return; + + let event = aEvent; + let rect = bendNode.getBoundingClientRect(); + let angle; + let x = (event.clientX - rect.left) / rect.width; + let y = (event.clientY - rect.top) / rect.height; + let perspective = '450px'; + // scaling factors for the angle of deflection, + // based on the aspect-ratio of the tile + let aspectRatio = rect.width/rect.height; + let deflectX = 10 * Math.ceil(1/aspectRatio); + let deflectY = 10 * Math.ceil(aspectRatio); + + if (Math.abs(x - .5) < .1 && Math.abs(y - .5) < .1) { + bendNode.style.transform = "perspective("+perspective+") translateZ(-10px)"; + } + else if (x > y) { + if (1 - y > x) { + angle = Math.ceil((.5 - y) * deflectY); + bendNode.style.transform = "perspective("+perspective+") rotateX(" + angle + "deg)"; + bendNode.style.transformOrigin = "center bottom"; + } else { + angle = Math.ceil((x - .5) * deflectX); + bendNode.style.transform = "perspective("+perspective+") rotateY(" + angle + "deg)"; + bendNode.style.transformOrigin = "left center"; + } + } else { + if (1 - y < x) { + angle = -Math.ceil((y - .5) * deflectY); + bendNode.style.transform = "perspective("+perspective+") rotateX(" + angle + "deg)"; + bendNode.style.transformOrigin = "center top"; + } else { + angle = -Math.ceil((.5 - x) * deflectX); + bendNode.style.transform = "perspective("+perspective+") rotateY(" + angle + "deg)"; + bendNode.style.transformOrigin = "right center"; + } + } + // mark when bend effect is applied + aItem.setAttribute("bending", true); + ]]></body> + </method> + <method name="unbendItem"> + <parameter name="aItem"/> + <body><![CDATA[ + // clear the 'bend' transform on the contentBox element of the item + let bendNode = 'richgriditem' == aItem.nodeName && aItem._contentBox; + if (bendNode && aItem.hasAttribute("bending")) { + bendNode.style.removeProperty('transform'); + bendNode.style.removeProperty('transformOrigin'); + aItem.removeAttribute("bending"); + } + ]]></body> + </method> </implementation> <handlers> + <!-- item bend effect handlers --> + <handler event="mousedown" button="0" phase="capturing" action="this.bendItem(event.target, event)"/> + <handler event="touchstart" action="this.bendItem(event.target, event.touches[0])"/> + <handler event="mouseup" button="0" action="this.unbendItem(event.target)"/> + <handler event="mouseout" button="0" action="this.unbendItem(event.target)"/> + <handler event="touchend" action="this.unbendItem(event.target)"/> + <!-- /item bend effect handler --> + <handler event="context-action"> <![CDATA[ // context-action is an event fired by the appbar typically // which directs us to do something to the selected tiles switch (event.action) { case "clear": this.clearSelection(); break; @@ -662,22 +732,26 @@ // MozCrossSliding is swipe gesture across a tile // The tile should follow the drag to reinforce the gesture // (with inertia/speedbump behavior) let state = event.crossSlidingState; let thresholds = this._xslideHandler.thresholds; let transformValue; switch(state) { case "cancelled": + this.unbendItem(event.target); + event.target.removeAttribute('crosssliding'); // hopefully nothing else is transform-ing the tile - event.target.removeAttribute('crosssliding'); event.target.style.removeProperty('transform'); break; case "dragging": case "selecting": + // remove bend/depress effect when a cross-slide begins + this.unbendItem(event.target); + event.target.setAttribute("crosssliding", true); // just track the mouse in the initial phases of the drag gesture transformValue = (event.direction=='x') ? 'translateX('+event.delta+'px)' : 'translateY('+event.delta+'px)'; event.target.style.transform = transformValue; break; case "selectSpeedBumping": @@ -722,17 +796,16 @@ <implementation> <property name="isBound" readonly="true" onget="return !!this._icon"/> <constructor> <![CDATA[ this.refresh(); ]]> </constructor> - <property name="_boundNode" onget="return document.getAnonymousElementByAttribute(this, 'anonid', 'anon-tile').parentNode;"/> <property name="_contentBox" onget="return document.getAnonymousElementByAttribute(this, 'class', 'tile-content');"/> <property name="_textbox" onget="return document.getAnonymousElementByAttribute(this, 'class', 'tile-desc');"/> <property name="_top" onget="return document.getAnonymousElementByAttribute(this, 'class', 'tile-start-container');"/> <property name="_icon" onget="return document.getAnonymousElementByAttribute(this, 'anonid', 'anon-tile-icon');"/> <property name="_label" onget="return document.getAnonymousElementByAttribute(this, 'anonid', 'anon-tile-label');"/> <property name="iconSrc" onset="this._icon.src = val; this.setAttribute('iconURI', val);" onget="return this._icon.src;" /> @@ -846,16 +919,17 @@ <![CDATA[ // left-click/touch handler this.control.handleItemClick(this, event); // Stop this from bubbling, when the richgrid container // receives click events, we blur the nav bar. event.stopPropagation(); ]]> </handler> + <handler event="contextmenu"> <![CDATA[ // fires for right-click, long-click and (keyboard) contextmenu input // toggle the selected state of tiles in a grid this.control.handleItemContextMenu(this, event); ]]> </handler> </handlers>
--- a/browser/metro/modules/CrossSlide.jsm +++ b/browser/metro/modules/CrossSlide.jsm @@ -171,61 +171,63 @@ CrossSlideHandler.prototype = { }; }, _onTouchMove: function(aEvent){ if (!this.drag) { return; } - aEvent.stopPropagation(); - if (aEvent.touches.length!==1) { // cancel if another touch point gets involved return this.cancel(aEvent); } let startPt = this.drag.origin; let endPt = this.drag.position = pointFromTouchEvent(aEvent); let scrollAxis = this.drag.scrollAxis, crossAxis = this.drag.crossAxis; // distance from the origin along the axis perpendicular to scrolling let crossAxisDistance = Math.abs(endPt[crossAxis] - startPt[crossAxis]); // distance along the scrolling axis let scrollAxisDistance = Math.abs(endPt[scrollAxis] - startPt[scrollAxis]); - let currState = this.drag.state; let newState = this.getCrossSlideState(crossAxisDistance, scrollAxisDistance); - if (-1 == newState) { - // out of bounds, cancel the event always - return this.cancel(aEvent); + switch (newState) { + case -1 : + // dodgy input/out of bounds + return this.cancel(aEvent); + case CrossSlidingState.STARTED : + break; + case CrossSlidingState.DRAGGING : + if (scrollAxisDistance > this.thresholds.SELECTIONSTART) { + // looks like a pan/scroll was intended + return this.cancel(aEvent); + } + // else fall-thru' + case CrossSlidingState.SELECTING : + case CrossSlidingState.SELECT_SPEED_BUMPING : + case CrossSlidingState.SPEED_BUMPING : + // we're committed to a cross-slide gesture, + // so going out of bounds at this point means aborting + if (!withinCone(crossAxisDistance, scrollAxisDistance)) { + return this.cancel(aEvent); + } + // we're mid-gesture, consume this event + aEvent.stopPropagation(); + break; } - let isWithinCone = withinCone(crossAxisDistance, scrollAxisDistance); - - if (currState < CrossSlidingState.SELECTING && !isWithinCone) { - // ignore, no progress to report - return; + if (currState !== newState) { + this.drag.state = newState; + this._fireProgressEvent( CrossSlidingStateNames[newState], aEvent ); } - if (currState >= CrossSlidingState.SELECTING && !isWithinCone) { - // we're committed to a cross-slide gesture, - // so going out of bounds at this point means aborting - return this.cancel(aEvent); - } - - if (currState > newState) { - // moved backwards, ignoring - return; - } - - this.drag.state = newState; - this._fireProgressEvent( CrossSlidingStateNames[newState], aEvent ); }, _onTouchEnd: function(aEvent){ if (!this.drag) return; if (this.drag.state < CrossSlidingState.SELECTING) { return this.cancel(aEvent); }
--- a/browser/metro/theme/tiles.css +++ b/browser/metro/theme/tiles.css @@ -226,16 +226,20 @@ richgriditem[pinned]:-moz-locale-dir(rtl left: 0; right: auto; } richgriditem[customColor] { color: #f1f1f1; } +richgriditem[bending] > .tile-content { + transform-origin: center center; +} + /* Snapped-view variation We use the compact, single-column grid treatment for <=320px */ @media (max-width: 330px) { richgrid > .richgrid-grid { -moz-column-width: auto!important; /* let it flow */ -moz-column-count: auto!important; /* let it flow */