OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 cr.exportPath('options'); | 5 cr.exportPath('options'); |
6 | 6 |
7 /** | 7 /** |
8 * Enumeration of display layout. These values must match the C++ values in | 8 * Enumeration of display layout. These values must match the C++ values in |
9 * ash::DisplayController. | 9 * ash::DisplayController. |
10 * @enum {number} | 10 * @enum {number} |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
98 // Prefer the closer one if both edges are close enough. | 98 // Prefer the closer one if both edges are close enough. |
99 if (startDiff < SNAP_DISTANCE_PX && startDiff < endDiff) | 99 if (startDiff < SNAP_DISTANCE_PX && startDiff < endDiff) |
100 return basePoint; | 100 return basePoint; |
101 else if (endDiff < SNAP_DISTANCE_PX) | 101 else if (endDiff < SNAP_DISTANCE_PX) |
102 return basePoint + baseWidth - width; | 102 return basePoint + baseWidth - width; |
103 | 103 |
104 return point; | 104 return point; |
105 } | 105 } |
106 | 106 |
107 /** | 107 /** |
108 * @param {number} visualScale | |
109 * @constructor | 108 * @constructor |
110 */ | 109 */ |
111 function DisplayLayoutManager(visualScale) { | 110 function DisplayLayoutManager() { |
112 this.visualScale_ = visualScale; | 111 this.displayLayoutMap_ = {}; |
| 112 this.displayAreaOffset_ = {x: 0, y: 0}; |
113 } | 113 } |
114 | 114 |
115 // Helper class for display layout management. Implements logic for laying | 115 // Helper class for display layout management. Implements logic for laying |
116 // out two displays. | 116 // out two displays. |
117 DisplayLayoutManager.prototype = { | 117 DisplayLayoutManager.prototype = { |
118 /** | 118 /** |
119 * An object containing DisplayLayout objects for each entry in | 119 * An object containing DisplayLayout objects for each entry in |
120 * |displays_|. | 120 * |displays_|. |
121 * @type {!Object<!options.DisplayLayout>} | 121 * @type {?Object<!options.DisplayLayout>} |
122 * @private | 122 * @private |
123 */ | 123 */ |
124 displayLayoutMap_: {}, | 124 displayLayoutMap_: null, |
125 | 125 |
126 /** | 126 /** |
127 * The scale factor of the actual display size to the drawn display | 127 * The scale factor of the actual display size to the drawn display |
128 * rectangle size. Set to the correct value for the UI in the constructor. | 128 * rectangle size. Set in calculateDisplayArea_. |
129 * @type {number} | 129 * @type {number} |
130 * @private | 130 * @private |
131 */ | 131 */ |
132 visualScale_: 1, | 132 visualScale_: 1, |
133 | 133 |
134 /** | 134 /** |
| 135 * The offset to the center of the display area div. |
| 136 * @type {?options.DisplayPosition} |
| 137 * @private |
| 138 */ |
| 139 displayAreaOffset_: null, |
| 140 |
| 141 /** |
135 * Adds a display to the layout map. | 142 * Adds a display to the layout map. |
136 * @param {options.DisplayLayout} displayLayout | 143 * @param {options.DisplayLayout} displayLayout |
137 */ | 144 */ |
138 addDisplayLayout: function(displayLayout) { | 145 addDisplayLayout: function(displayLayout) { |
139 this.displayLayoutMap_[displayLayout.id] = displayLayout; | 146 this.displayLayoutMap_[displayLayout.id] = displayLayout; |
140 }, | 147 }, |
141 | 148 |
142 /** | 149 /** |
143 * Returns the layout type for |id|. | 150 * Returns the display layout for |id|. |
144 * @param {string} id | 151 * @param {string} id |
145 * @return {options.DisplayLayout} | 152 * @return {options.DisplayLayout} |
146 */ | 153 */ |
147 getDisplayLayout: function(id) { return this.displayLayoutMap_[id]; }, | 154 getDisplayLayout: function(id) { return this.displayLayoutMap_[id]; }, |
148 | 155 |
149 /** | 156 /** |
150 * Creates a div for each entry in displayLayoutMap_. | 157 * Returns the number of display layout entries. |
151 * @param {!Element} parentElement The parent element to contain the divs. | 158 * @return {number} |
152 * @param {!options.DisplayPosition} offset The offset to the center of | |
153 * the display area. | |
154 */ | 159 */ |
155 createDisplayLayoutDivs: function(parentElement, offset) { | 160 getDisplayLayoutCount: function() { |
| 161 return Object.keys(/** @type {!Object} */ (this.displayLayoutMap_)) |
| 162 .length; |
| 163 }, |
| 164 |
| 165 /** |
| 166 * Returns the display layout corresponding to |div|. |
| 167 * @param {!HTMLElement} div |
| 168 * @return {?options.DisplayLayout} |
| 169 */ |
| 170 getFocusedLayoutForDiv: function(div) { |
| 171 for (var id in this.displayLayoutMap_) { |
| 172 var layout = this.displayLayoutMap_[id]; |
| 173 if (layout.div == div || |
| 174 (div.offsetParent && layout.div == div.offsetParent)) { |
| 175 return layout; |
| 176 } |
| 177 } |
| 178 return null; |
| 179 }, |
| 180 |
| 181 /** |
| 182 * Sets the display area div size and creates a div for each entry in |
| 183 * displayLayoutMap_. |
| 184 * @param {!Element} displayAreaDiv The display area div element. |
| 185 * @param {number} minVisualScale The minimum visualScale value. |
| 186 * @return {number} The calculated visual scale. |
| 187 */ |
| 188 createDisplayArea: function(displayAreaDiv, minVisualScale) { |
| 189 this.calculateDisplayArea_(displayAreaDiv, minVisualScale); |
156 for (var id in this.displayLayoutMap_) { | 190 for (var id in this.displayLayoutMap_) { |
157 var layout = this.displayLayoutMap_[id]; | 191 var layout = this.displayLayoutMap_[id]; |
158 if (layout.div) { | 192 if (layout.div) { |
159 // Parent divs must be created before children, so the div for this | 193 // Parent divs must be created before children, so the div for this |
160 // entry may have already been created. | 194 // entry may have already been created. |
161 continue; | 195 continue; |
162 } | 196 } |
163 this.createDisplayLayoutDiv_(id, parentElement, offset); | 197 this.createDisplayLayoutDiv_(id, displayAreaDiv); |
| 198 } |
| 199 return this.visualScale_; |
| 200 }, |
| 201 |
| 202 /** |
| 203 * Sets the display layout div corresponding to |id| to focused and |
| 204 * sets all other display layouts to unfocused. |
| 205 * @param {string} focusedId |
| 206 */ |
| 207 setFocusedId: function(focusedId) { |
| 208 for (var id in this.displayLayoutMap_) { |
| 209 var layout = this.displayLayoutMap_[id]; |
| 210 layout.div.classList.toggle('displays-focused', layout.id == focusedId); |
164 } | 211 } |
165 }, | 212 }, |
166 | 213 |
| 214 /** |
| 215 * Sets the mouse event callbacks for each div. |
| 216 * @param {function (Event)} onMouseDown |
| 217 * @param {function (Event)} onTouchStart |
| 218 */ |
| 219 setDivCallbacks: function(onMouseDown, onTouchStart) { |
| 220 for (var id in this.displayLayoutMap_) { |
| 221 var layout = this.displayLayoutMap_[id]; |
| 222 layout.div.onmousedown = onMouseDown; |
| 223 layout.div.ontouchstart = onTouchStart; |
| 224 } |
| 225 }, |
| 226 |
167 /** | 227 /** |
168 * Update the location of display |id| to |newPosition|. | 228 * Update the location of display |id| to |newPosition|. |
169 * @param {string} id | 229 * @param {string} id |
170 * @param {options.DisplayPosition} newPosition | 230 * @param {options.DisplayPosition} newPosition |
171 * @private | 231 * @private |
172 */ | 232 */ |
173 updatePosition: function(id, newPosition) { | 233 updatePosition: function(id, newPosition) { |
174 var displayLayout = this.displayLayoutMap_[id]; | 234 var displayLayout = this.displayLayoutMap_[id]; |
175 var div = displayLayout.div; | 235 var div = displayLayout.div; |
176 var baseLayout = this.getBaseLayout_(displayLayout); | 236 var baseLayout = this.getBaseLayout_(displayLayout); |
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
320 } | 380 } |
321 | 381 |
322 // Calculate the offset of the child display. | 382 // Calculate the offset of the child display. |
323 this.calculateOffset_(isPrimary ? baseLayout : displayLayout); | 383 this.calculateOffset_(isPrimary ? baseLayout : displayLayout); |
324 | 384 |
325 return displayLayout.originalPosition.x != div.offsetLeft || | 385 return displayLayout.originalPosition.x != div.offsetLeft || |
326 displayLayout.originalPosition.y != div.offsetTop; | 386 displayLayout.originalPosition.y != div.offsetTop; |
327 }, | 387 }, |
328 | 388 |
329 /** | 389 /** |
| 390 * Calculates the display area offset and scale. |
| 391 * @param {!Element} displayAreaDiv The containing display area div. |
| 392 * @param {number} minVisualScale The minimum visualScale value. |
| 393 */ |
| 394 calculateDisplayArea_(displayAreaDiv, minVisualScale) { |
| 395 var maxWidth = 0; |
| 396 var maxHeight = 0; |
| 397 var boundingBox = {left: 0, right: 0, top: 0, bottom: 0}; |
| 398 |
| 399 for (var id in this.displayLayoutMap_) { |
| 400 var layout = this.displayLayoutMap_[id]; |
| 401 var bounds = layout.bounds; |
| 402 boundingBox.left = Math.min(boundingBox.left, bounds.left); |
| 403 boundingBox.right = |
| 404 Math.max(boundingBox.right, bounds.left + bounds.width); |
| 405 boundingBox.top = Math.min(boundingBox.top, bounds.top); |
| 406 boundingBox.bottom = |
| 407 Math.max(boundingBox.bottom, bounds.top + bounds.height); |
| 408 maxWidth = Math.max(maxWidth, bounds.width); |
| 409 maxHeight = Math.max(maxHeight, bounds.height); |
| 410 } |
| 411 |
| 412 // Make the margin around the bounding box. |
| 413 var areaWidth = boundingBox.right - boundingBox.left + maxWidth; |
| 414 var areaHeight = boundingBox.bottom - boundingBox.top + maxHeight; |
| 415 |
| 416 // Calculates the scale by the width since horizontal size is more strict. |
| 417 // TODO(mukai): Adds the check of vertical size in case. |
| 418 this.visualScale_ = |
| 419 Math.min(minVisualScale, displayAreaDiv.offsetWidth / areaWidth); |
| 420 |
| 421 // Prepare enough area for displays_view by adding the maximum height. |
| 422 displayAreaDiv.style.height = |
| 423 Math.ceil(areaHeight * this.visualScale_) + 'px'; |
| 424 |
| 425 // Centering the bounding box of the display rectangles. |
| 426 this.displayAreaOffset_ = { |
| 427 x: Math.floor( |
| 428 displayAreaDiv.offsetWidth / 2 - |
| 429 (boundingBox.right + boundingBox.left) * this.visualScale_ / 2), |
| 430 y: Math.floor( |
| 431 displayAreaDiv.offsetHeight / 2 - |
| 432 (boundingBox.bottom + boundingBox.top) * this.visualScale_ / 2) |
| 433 }; |
| 434 }, |
| 435 |
| 436 /** |
330 * Creates a div element and assigns it to |displayLayout|. Returns the | 437 * Creates a div element and assigns it to |displayLayout|. Returns the |
331 * created div for additional decoration. | 438 * created div for additional decoration. |
332 * @param {string} id | 439 * @param {string} id |
333 * @param {!Element} parentElement The parent element to contain the div. | 440 * @param {!Element} displayAreaDiv The containing display area div. |
334 * @param {!options.DisplayPosition} offset The offset to the center of | |
335 * the display area. | |
336 */ | 441 */ |
337 createDisplayLayoutDiv_: function(id, parentElement, offset) { | 442 createDisplayLayoutDiv_: function(id, displayAreaDiv) { |
338 var displayLayout = this.displayLayoutMap_[id]; | 443 var displayLayout = this.displayLayoutMap_[id]; |
339 var parentId = displayLayout.parentId; | 444 var parentId = displayLayout.parentId; |
| 445 var offset = this.displayAreaOffset_; |
340 if (parentId) { | 446 if (parentId) { |
341 // Ensure the parent div is created first. | 447 // Ensure the parent div is created first. |
342 var parentLayout = this.displayLayoutMap_[parentId]; | 448 var parentLayout = this.displayLayoutMap_[parentId]; |
343 if (!parentLayout.div) | 449 if (!parentLayout.div) |
344 this.createDisplayLayoutDiv_(parentId, parentElement, offset); | 450 this.createDisplayLayoutDiv_(parentId, displayAreaDiv); |
345 } | 451 } |
346 | 452 |
347 var div = /** @type {!HTMLElement} */ (document.createElement('div')); | 453 var div = /** @type {!HTMLElement} */ (document.createElement('div')); |
348 div.className = 'displays-display'; | 454 div.className = 'displays-display'; |
349 | 455 |
350 // div needs to be added to the DOM tree first, otherwise offsetHeight for | 456 // div needs to be added to the DOM tree first, otherwise offsetHeight for |
351 // nameContainer below cannot be computed. | 457 // nameContainer below cannot be computed. |
352 parentElement.appendChild(div); | 458 displayAreaDiv.appendChild(div); |
353 | 459 |
354 var nameContainer = document.createElement('div'); | 460 var nameContainer = document.createElement('div'); |
355 nameContainer.textContent = displayLayout.name; | 461 nameContainer.textContent = displayLayout.name; |
356 div.appendChild(nameContainer); | 462 div.appendChild(nameContainer); |
357 | 463 |
358 var bounds = displayLayout.bounds; | 464 var bounds = displayLayout.bounds; |
359 div.style.width = Math.floor(bounds.width * this.visualScale_) + 'px'; | 465 div.style.width = Math.floor(bounds.width * this.visualScale_) + 'px'; |
360 var newHeight = Math.floor(bounds.height * this.visualScale_); | 466 var newHeight = Math.floor(bounds.height * this.visualScale_); |
361 div.style.height = newHeight + 'px'; | 467 div.style.height = newHeight + 'px'; |
362 nameContainer.style.marginTop = | 468 nameContainer.style.marginTop = |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
441 return child; | 547 return child; |
442 } | 548 } |
443 assertNotReached(); | 549 assertNotReached(); |
444 return null; | 550 return null; |
445 } | 551 } |
446 }; | 552 }; |
447 | 553 |
448 // Export | 554 // Export |
449 return {DisplayLayoutManager: DisplayLayoutManager}; | 555 return {DisplayLayoutManager: DisplayLayoutManager}; |
450 }); | 556 }); |
OLD | NEW |