Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / devtools / front_end / timeline / TransformController.js
1 /*
2  * Copyright 2014 The Chromium Authors. All rights reserved.
3  * Use of this source code is governed by a BSD-style license that can be
4  * found in the LICENSE file.
5  */
6
7 /**
8  * @constructor
9  * @extends {WebInspector.Object}
10  * @param {!Element} element
11  * @param {boolean=} disableRotate
12  */
13 WebInspector.TransformController = function(element, disableRotate)
14 {
15     this._shortcuts = {};
16     this.element = element;
17     if (this.element.tabIndex < 0)
18         this.element.tabIndex = 0;
19     this._registerShortcuts();
20     WebInspector.installDragHandle(element, this._onDragStart.bind(this), this._onDrag.bind(this), this._onDragEnd.bind(this), "move", null);
21     element.addEventListener("keydown", this._onKeyDown.bind(this), false);
22     element.addEventListener("keyup", this._onKeyUp.bind(this), false);
23     element.addEventListener("mousewheel", this._onMouseWheel.bind(this), false);
24     this._disableRotate = disableRotate;
25     this._minScale = 0;
26     this._maxScale = Infinity;
27
28     this._controlPanelElement = createElement("div");
29     this._controlPanelElement.classList.add("transform-control-panel");
30
31     this._modeButtons = {};
32     if (!disableRotate) {
33         var panModeButton = new WebInspector.StatusBarButton(WebInspector.UIString("Pan mode (X)"), "transform-mode-pan");
34         panModeButton.addEventListener("click", this._setMode.bind(this, WebInspector.TransformController.Modes.Pan));
35         this._modeButtons[WebInspector.TransformController.Modes.Pan] = panModeButton;
36         this._controlPanelElement.appendChild(panModeButton.element);
37         var rotateModeButton = new WebInspector.StatusBarButton(WebInspector.UIString("Rotate mode (V)"), "transform-mode-rotate");
38         rotateModeButton.addEventListener("click", this._setMode.bind(this, WebInspector.TransformController.Modes.Rotate));
39         this._modeButtons[WebInspector.TransformController.Modes.Rotate] = rotateModeButton;
40         this._controlPanelElement.appendChild(rotateModeButton.element);
41     }
42     this._setMode(WebInspector.TransformController.Modes.Pan);
43
44     var resetButton = new WebInspector.StatusBarButton(WebInspector.UIString("Reset transform (0)"), "transform-reset");
45     resetButton.addEventListener("click", this.resetAndNotify.bind(this, undefined));
46     this._controlPanelElement.appendChild(resetButton.element);
47
48     this._reset();
49 }
50
51 /**
52  * @enum {string}
53  */
54 WebInspector.TransformController.Events = {
55     TransformChanged: "TransformChanged"
56 }
57
58 /**
59  * @enum {string}
60  */
61 WebInspector.TransformController.Modes = {
62     Pan: "Pan",
63     Rotate: "Rotate",
64 }
65
66 WebInspector.TransformController.prototype = {
67     /**
68      * @return {!Element}
69      */
70     controlPanelElement: function()
71     {
72         return this._controlPanelElement;
73     },
74
75     _onKeyDown: function(event)
76     {
77         if (event.keyCode === WebInspector.KeyboardShortcut.Keys.Shift.code) {
78             this._toggleMode();
79             return;
80         }
81
82         var shortcutKey = WebInspector.KeyboardShortcut.makeKeyFromEventIgnoringModifiers(event);
83         var handler = this._shortcuts[shortcutKey];
84         if (handler && handler(event))
85             event.consume();
86     },
87
88     _onKeyUp: function(event)
89     {
90         if (event.keyCode === WebInspector.KeyboardShortcut.Keys.Shift.code)
91             this._toggleMode();
92     },
93
94     _addShortcuts: function(keys, handler)
95     {
96         for (var i = 0; i < keys.length; ++i)
97             this._shortcuts[keys[i].key] = handler;
98     },
99
100     _registerShortcuts: function()
101     {
102         this._addShortcuts(WebInspector.ShortcutsScreen.LayersPanelShortcuts.ResetView, this.resetAndNotify.bind(this));
103         this._addShortcuts(WebInspector.ShortcutsScreen.LayersPanelShortcuts.PanMode, this._setMode.bind(this, WebInspector.TransformController.Modes.Pan));
104         this._addShortcuts(WebInspector.ShortcutsScreen.LayersPanelShortcuts.RotateMode, this._setMode.bind(this, WebInspector.TransformController.Modes.Rotate));
105         var zoomFactor = 1.1;
106         this._addShortcuts(WebInspector.ShortcutsScreen.LayersPanelShortcuts.ZoomIn, this._onKeyboardZoom.bind(this, zoomFactor));
107         this._addShortcuts(WebInspector.ShortcutsScreen.LayersPanelShortcuts.ZoomOut, this._onKeyboardZoom.bind(this, 1 / zoomFactor));
108         this._addShortcuts(WebInspector.ShortcutsScreen.LayersPanelShortcuts.Up, this._onKeyboardPanOrRotate.bind(this, 0, -1));
109         this._addShortcuts(WebInspector.ShortcutsScreen.LayersPanelShortcuts.Down, this._onKeyboardPanOrRotate.bind(this, 0, 1));
110         this._addShortcuts(WebInspector.ShortcutsScreen.LayersPanelShortcuts.Left, this._onKeyboardPanOrRotate.bind(this, -1, 0));
111         this._addShortcuts(WebInspector.ShortcutsScreen.LayersPanelShortcuts.Right, this._onKeyboardPanOrRotate.bind(this, 1, 0));
112     },
113
114     _postChangeEvent: function()
115     {
116         this.dispatchEventToListeners(WebInspector.TransformController.Events.TransformChanged);
117     },
118
119     _reset: function()
120     {
121         this._scale = 1;
122         this._offsetX = 0;
123         this._offsetY = 0;
124         this._rotateX = 0;
125         this._rotateY = 0;
126     },
127
128     _toggleMode: function()
129     {
130         this._setMode(this._mode === WebInspector.TransformController.Modes.Pan ? WebInspector.TransformController.Modes.Rotate : WebInspector.TransformController.Modes.Pan);
131     },
132
133     /**
134      * @param {!WebInspector.TransformController.Modes} mode
135      */
136     _setMode: function(mode)
137     {
138         if (this._mode === mode)
139             return;
140         this._mode = mode;
141         this._updateModeButtons();
142         this.element.focus();
143     },
144
145     _updateModeButtons: function()
146     {
147         for (var mode in this._modeButtons)
148             this._modeButtons[mode].toggled = (mode === this._mode);
149     },
150
151     /**
152      * @param {!Event=} event
153      */
154     resetAndNotify: function(event)
155     {
156         this._reset();
157         this._postChangeEvent();
158         if (event)
159             event.preventDefault();
160         this.element.focus();
161     },
162
163     /**
164      * @param {number} minScale
165      * @param {number} maxScale
166      */
167     setScaleConstraints: function(minScale, maxScale)
168     {
169         this._minScale = minScale;
170         this._maxScale = maxScale;
171         this._scale = Number.constrain(this._scale, minScale, maxScale);
172     },
173
174     /**
175      * @param {number} minX
176      * @param {number} maxX
177      * @param {number} minY
178      * @param {number} maxY
179      */
180     clampOffsets: function(minX, maxX, minY, maxY)
181     {
182         this._offsetX = Number.constrain(this._offsetX, minX, maxX);
183         this._offsetY = Number.constrain(this._offsetY, minY, maxY);
184     },
185
186     /**
187      * @return {number}
188      */
189     scale: function()
190     {
191         return this._scale;
192     },
193
194     /**
195      * @return {number}
196      */
197     offsetX: function()
198     {
199         return this._offsetX;
200     },
201
202     /**
203      * @return {number}
204      */
205     offsetY: function()
206     {
207         return this._offsetY;
208     },
209
210     /**
211      * @return {number}
212      */
213     rotateX: function()
214     {
215         return this._rotateX;
216     },
217
218     /**
219      * @return {number}
220      */
221     rotateY: function()
222     {
223         return this._rotateY;
224     },
225
226     /**
227      * @param {number} scaleFactor
228      * @param {number} x
229      * @param {number} y
230      */
231     _onScale: function(scaleFactor, x, y)
232     {
233         scaleFactor = Number.constrain(this._scale * scaleFactor, this._minScale, this._maxScale) / this._scale;
234         this._scale *= scaleFactor;
235         this._offsetX -= (x - this._offsetX) * (scaleFactor - 1);
236         this._offsetY -= (y - this._offsetY) * (scaleFactor - 1);
237         this._postChangeEvent();
238     },
239
240     /**
241      * @param {number} offsetX
242      * @param {number} offsetY
243      */
244     _onPan: function(offsetX, offsetY)
245     {
246         this._offsetX += offsetX;
247         this._offsetY += offsetY;
248         this._postChangeEvent();
249     },
250
251     /**
252      * @param {number} rotateX
253      * @param {number} rotateY
254      */
255     _onRotate: function(rotateX, rotateY)
256     {
257         this._rotateX = rotateX;
258         this._rotateY = rotateY;
259         this._postChangeEvent();
260     },
261
262     /**
263      * @param {number} zoomFactor
264      */
265     _onKeyboardZoom: function(zoomFactor)
266     {
267         this._onScale(zoomFactor, this.element.clientWidth / 2, this.element.clientHeight / 2);
268     },
269
270     /**
271      * @param {number} xMultiplier
272      * @param {number} yMultiplier
273      */
274     _onKeyboardPanOrRotate: function(xMultiplier, yMultiplier)
275     {
276         var panStepInPixels = 6;
277         var rotateStepInDegrees = 5;
278
279         if (this._mode === WebInspector.TransformController.Modes.Rotate) {
280             // Sic! _onRotate treats X and Y as "rotate around X" and "rotate around Y", so swap X/Y multiplers.
281             this._onRotate(this._rotateX + yMultiplier * rotateStepInDegrees, this._rotateY + xMultiplier * rotateStepInDegrees);
282         } else {
283             this._onPan(xMultiplier * panStepInPixels, yMultiplier * panStepInPixels);
284         }
285     },
286
287     /**
288      * @param {!Event} event
289      */
290     _onMouseWheel: function(event)
291     {
292         /** @const */
293         var zoomFactor = 1.1;
294         /** @const */
295         var mouseWheelZoomSpeed = 1 / 120;
296         var scaleFactor = Math.pow(zoomFactor, event.wheelDeltaY * mouseWheelZoomSpeed);
297         this._onScale(scaleFactor, event.clientX - this.element.totalOffsetLeft(), event.clientY - this.element.totalOffsetTop());
298     },
299
300     /**
301      * @param {!Event} event
302      */
303     _onDrag: function(event)
304     {
305         if (this._mode === WebInspector.TransformController.Modes.Rotate) {
306             this._onRotate(this._oldRotateX + (this._originY - event.clientY) / this.element.clientHeight * 180, this._oldRotateY - (this._originX - event.clientX) / this.element.clientWidth * 180);
307         } else {
308             this._onPan(event.clientX - this._originX, event.clientY - this._originY);
309             this._originX = event.clientX;
310             this._originY = event.clientY;
311         }
312     },
313
314     /**
315      * @param {!MouseEvent} event
316      */
317     _onDragStart: function(event)
318     {
319         this.element.focus();
320         this._originX = event.clientX;
321         this._originY = event.clientY;
322         this._oldRotateX = this._rotateX;
323         this._oldRotateY = this._rotateY;
324         return true;
325     },
326
327     _onDragEnd: function()
328     {
329         delete this._originX;
330         delete this._originY;
331         delete this._oldRotateX;
332         delete this._oldRotateY;
333     },
334
335     __proto__: WebInspector.Object.prototype
336 }