Changeset 228301 in webkit
- Timestamp:
- Feb 8, 2018 4:52:28 PM (6 years ago)
- Location:
- trunk/Source/WebInspectorUI
- Files:
-
- 3 added
- 22 edited
- 1 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebInspectorUI/ChangeLog
r228296 r228301 1 2018-02-08 Matt Baker <mattbaker@apple.com> 2 3 Web Inspector: add listing of Canvases/Programs/Recordings to the NavigationSidebar 4 https://bugs.webkit.org/show_bug.cgi?id=178744 5 <rdar://problem/35374379> 6 7 Reviewed by Devin Rousso. 8 9 * Localizations/en.lproj/localizedStrings.js: 10 11 * UserInterface/Images/Canvas2D.svg: 12 * UserInterface/Images/Canvas3D.svg: 13 * UserInterface/Images/Recording.svg: 14 Update canvas icons to be monochrome. Simplified the recording icon. 15 16 * UserInterface/Main.html: 17 18 * UserInterface/Models/RecordingAction.js: 19 (WI.RecordingAction.prototype.get state): 20 (WI.RecordingAction.prototype.set state): 21 Allow (2D) snapshot state to be associated with the action. Used by 22 RecordingActionDetailsSidebarPanel to retrieve the snapshot state. 23 24 * UserInterface/Views/CanvasContentView.css: 25 (.content-view.canvas:not(.tab)): 26 (.content-view.canvas:not(.tab) > .progress): Deleted. 27 (.content-view.canvas:not(.tab) > .progress > .frame-count): Deleted. 28 29 * UserInterface/Views/CanvasContentView.js: 30 (WI.CanvasContentView): 31 (WI.CanvasContentView.prototype.get navigationItems): 32 (WI.CanvasContentView.prototype.layout): 33 (WI.CanvasContentView.prototype.shown): 34 (WI.CanvasContentView.prototype._recordingStarted): 35 (WI.CanvasContentView.prototype._recordingProgress): 36 (WI.CanvasContentView.prototype._recordingStopped): 37 (WI.CanvasContentView.prototype._updateRecordNavigationItem): 38 (WI.CanvasContentView.prototype._updateProgressView): 39 Replace progress UI with a reusable ProgressView class. 40 When in the overview, clicking the CanvasContentView shows a dedicated 41 CanvasContentView for inspecting shaders and recordings. This behavior 42 is controlled by CollectionContentView, so we need to prevent it when 43 clicking inside the header and footer elements, which contain clickable UI. 44 45 * UserInterface/Views/CanvasDetailsSidebarPanel.js: 46 (WI.CanvasDetailsSidebarPanel.prototype.inspect): 47 48 * UserInterface/Views/CanvasOverviewContentView.css: 49 (.content-view.canvas-overview .content-view.canvas): 50 (.content-view.canvas-overview .content-view.canvas.is-recording): 51 (.content-view.canvas-overview .content-view.canvas > :matches(header, footer)): 52 (.content-view.canvas-overview .content-view.canvas > header): 53 (.content-view.canvas-overview .content-view.canvas.is-recording > header): 54 (.content-view.canvas-overview .content-view.canvas > header > .navigation-bar): 55 (.content-view.canvas-overview .content-view.canvas:matches(:hover, .is-recording) > header > .navigation-bar): 56 (.content-view.canvas-overview .content-view.canvas.is-recording > .progress-view,): 57 (.content-view.canvas-overview .content-view.canvas.is-recording > .preview): 58 (.content-view.canvas-overview .content-view.canvas > :matches(header, .progress, .preview, footer)): Deleted. 59 (.content-view.canvas-overview .content-view.canvas.selected > :matches(.progress, .preview, footer),): Deleted. 60 (.content-view.canvas-overview .content-view.canvas:not(:hover, .is-recording, .selected) > header > .navigation-bar): Deleted. 61 (.content-view.canvas-overview .content-view.canvas > :matches(.progress, .preview)): Deleted. 62 (.content-view.canvas-overview .content-view.canvas > .preview): Deleted. 63 (.content-view.canvas-overview .content-view.canvas > .progress ~ .preview): Deleted. 64 Clean up styles, and remove selection styles as canvases are no longer selectable in the overview. 65 66 * UserInterface/Views/CanvasOverviewContentView.js: 67 (WI.CanvasOverviewContentView): 68 (WI.CanvasOverviewContentView.prototype.get navigationItems): 69 (WI.CanvasOverviewContentView.prototype.attached): 70 (WI.CanvasOverviewContentView.prototype.detached): 71 (WI.CanvasOverviewContentView.prototype.get selectionPathComponents): Deleted. 72 (WI.CanvasOverviewContentView.prototype._changeSelectedItemVertically): Deleted. 73 (WI.CanvasOverviewContentView.prototype._changeSelectedItemHorizontally): Deleted. 74 (WI.CanvasOverviewContentView.prototype._selectionPathComponentsChanged): Deleted. 75 (WI.CanvasOverviewContentView.prototype._handleUp): Deleted. 76 (WI.CanvasOverviewContentView.prototype._handleRight): Deleted. 77 (WI.CanvasOverviewContentView.prototype._handleDown): Deleted. 78 (WI.CanvasOverviewContentView.prototype._handleLeft): Deleted. 79 (WI.CanvasOverviewContentView.prototype._handleSpace): Deleted. 80 (WI.CanvasOverviewContentView.prototype._supplementalRepresentedObjectsDidChange): Deleted. 81 Disable canvas selection. Remove logic for supplemental represented objects, 82 path components, and selection keyboard shortcuts. 83 84 * UserInterface/Views/CanvasSidebarPanel.css: Added. 85 (.sidebar > .panel.navigation.canvas > .content): 86 (.sidebar > .panel.navigation.canvas > .navigation-bar > .item.record-start-stop.disabled): 87 (.sidebar > .panel.navigation.canvas > .content > .tree-outline .item.canvas.canvas-2d .icon): 88 (.sidebar > .panel.navigation.canvas > .content > .tree-outline .item.canvas.webgl .icon): 89 (.sidebar > .panel.navigation.canvas > .content > .navigation-bar): 90 (.sidebar > .panel.navigation.canvas.has-recordings > .content > .tree-outline.canvas): 91 (.sidebar > .panel.navigation.canvas:not(.has-recordings) > .filter-bar,): 92 (.sidebar > .panel.navigation.canvas > .content > .tree-outline .item.recording > .icon): 93 (.sidebar > .panel.navigation.canvas > .content > .tree-outline .item.shader-program > .icon): 94 (.sidebar > .panel.navigation.canvas > .content > .tree-outline .item.folder-icon > .icon): 95 (.sidebar > .panel.navigation.canvas > .content > .tree-outline .item.folder-icon > .status): 96 97 * UserInterface/Views/CanvasSidebarPanel.js: Added. 98 (WI.CanvasSidebarPanel): 99 (WI.CanvasSidebarPanel.prototype.get canvas): 100 (WI.CanvasSidebarPanel.prototype.set canvas): 101 (WI.CanvasSidebarPanel.prototype.set recording): 102 (WI.CanvasSidebarPanel.prototype.set action): 103 (WI.CanvasSidebarPanel.prototype.shown): 104 (WI.CanvasSidebarPanel.prototype.hidden): 105 (WI.CanvasSidebarPanel.prototype.hasCustomFilters): 106 (WI.CanvasSidebarPanel.prototype.matchTreeElementAgainstCustomFilters): 107 (WI.CanvasSidebarPanel.prototype.initialLayout): 108 (WI.CanvasSidebarPanel.prototype._recordingAdded): 109 (WI.CanvasSidebarPanel.prototype._recordingRemoved): 110 (WI.CanvasSidebarPanel.prototype._scopeBarSelectionChanged): 111 (WI.CanvasSidebarPanel.prototype._toggleRecording): 112 (WI.CanvasSidebarPanel.prototype._currentRepresentedObjectsDidChange): 113 (WI.CanvasSidebarPanel.prototype._treeOutlineSelectionDidChange): 114 (WI.CanvasSidebarPanel.prototype._canvasChanged): 115 (WI.CanvasSidebarPanel.prototype._recordingChanged): 116 (WI.CanvasSidebarPanel.prototype._updateRecordNavigationItem): 117 (WI.CanvasSidebarPanel.prototype._updateRecordingScopeBar): 118 Add new navigation sidebar, split into two sections. The upper section 119 contains a tree with a single element for the current canvas, and child 120 elements for any shader programs. The maximum height of this section is 50% 121 of the sidebar's height. The lower section contains a tree for the selected 122 recording, and a scope bar for choosing between recordings. 123 124 * UserInterface/Views/CanvasTabContentView.css: 125 (.content-view.tab.canvas .navigation-bar > .item .canvas-overview .icon): 126 (.content-view.tab.canvas .navigation-bar > .item .canvas.canvas-2d .icon): 127 (.content-view.tab.canvas .navigation-bar > .item .canvas.webgl .icon): 128 (.content-view.tab.canvas .navigation-bar > .item .shader-program > .icon): 129 (.content-view.tab.canvas .navigation-bar > .item > .hierarchical-path-component > .icon): Deleted. 130 (.content-view.tab.canvas .navigation-bar > .item .canvas .icon): Deleted. 131 132 * UserInterface/Views/CanvasTabContentView.js: 133 (WI.CanvasTabContentView): 134 (WI.CanvasTabContentView.prototype.canShowRepresentedObject): 135 (WI.CanvasTabContentView.prototype.attached): 136 (WI.CanvasTabContentView.prototype._addCanvas): 137 (WI.CanvasTabContentView.prototype._removeCanvas): 138 (WI.CanvasTabContentView.prototype._canvasTreeOutlineSelectionDidChange): 139 (WI.CanvasTabContentView.prototype._recordingAdded): 140 (WI.CanvasTabContentView.prototype._handleSpace): 141 (WI.CanvasTabContentView.prototype.showRepresentedObject): Deleted. 142 (WI.CanvasTabContentView.prototype._navigationSidebarTreeOutlineSelectionChanged): Deleted. 143 (WI.CanvasTabContentView.prototype._recordingActionIndexChanged): Deleted. 144 (WI.CanvasTabContentView.prototype._updateActionIndex): Deleted. 145 The canvas tab now maintains a tree outline of all canvases, with an 146 "Overview" element as the root. The Overview element is always the first 147 item of content browser's hierarchical path. 148 149 * UserInterface/Views/CanvasTreeElement.js: 150 (WI.CanvasTreeElement.createRecordingTreeElement): 151 (WI.CanvasTreeElement): 152 (WI.CanvasTreeElement.prototype.onattach): 153 (WI.CanvasTreeElement.prototype.onpopulate): 154 (WI.CanvasTreeElement.prototype._updateStatus): 155 (WI.CanvasTreeElement.prototype.ondetach): Deleted. 156 Make it possible to not show recordings under the Canvas element. 157 Create `isRecording` status element (spinner). 158 159 * UserInterface/Views/CollectionContentView.js: 160 (WI.CollectionContentView.prototype.shown): 161 (WI.CollectionContentView.prototype.hidden): 162 Child ContentViews need to be updated when the collection's visibility changes. 163 164 * UserInterface/Views/ContentView.js: 165 (WI.ContentView.isViewable): 166 167 * UserInterface/Views/ProgressView.css: Added. 168 (.progress-view): 169 (.progress-view > .titles): 170 (.progress-view > .titles > .title): 171 (.progress-view > .titles > .subtitle): 172 (.progress-view > .titles > .subtitle::before): 173 (.progress-view > .indeterminate-progress-spinner): 174 175 * UserInterface/Views/ProgressView.js: Added. 176 (WI.ProgressView): 177 (WI.ProgressView.prototype.get title): 178 (WI.ProgressView.prototype.set title): 179 (WI.ProgressView.prototype.get subtitle): 180 (WI.ProgressView.prototype.set subtitle): 181 (WI.ProgressView.prototype.get visible): 182 (WI.ProgressView.prototype.set visible): 183 (WI.ProgressView.prototype.initialLayout): 184 (WI.ProgressView.prototype._updateTitles): 185 New view class (not a ContentView) for showing a generic progress message, 186 with a title, subtitle, and progress spinner. 187 188 * UserInterface/Views/RecordingContentView.css: 189 (.content-view:not(.tab).recording > .preview-container): 190 Remove unnecessary styles. 191 192 * UserInterface/Views/RecordingContentView.js: 193 (WI.RecordingContentView): 194 (WI.RecordingContentView.prototype.get navigationItems): 195 (WI.RecordingContentView.prototype.get supplementalRepresentedObjects): 196 (WI.RecordingContentView.prototype.updateActionIndex): 197 (WI.RecordingContentView.prototype.get saveData): 198 (WI.RecordingContentView.prototype._exportRecording): 199 Relocate the recording export logic and UI. 200 (WI.RecordingContentView.prototype.async._generateContentCanvas2D): 201 (WI.RecordingContentView.prototype.async._generateContentCanvasWebGL): 202 (WI.RecordingContentView.prototype._sliderChanged): 203 Refactor logic for notifying the rest of the UI of changes to the action slider. 204 The selected action is now exposed as a supplemental represented object, and a 205 corresponding SupplementalRepresentedObjectsDidChange event. 206 207 * UserInterface/Views/RecordingStateDetailsSidebarPanel.js: 208 (WI.RecordingStateDetailsSidebarPanel.prototype.inspect): 209 (WI.RecordingStateDetailsSidebarPanel.prototype.set action): 210 (WI.RecordingStateDetailsSidebarPanel.prototype._generateDetailsCanvas2D): 211 (WI.RecordingStateDetailsSidebarPanel): 212 (WI.RecordingStateDetailsSidebarPanel.prototype.updateAction): Deleted. 213 214 * UserInterface/Views/RecordingTraceDetailsSidebarPanel.js: 215 (WI.RecordingTraceDetailsSidebarPanel.prototype.inspect): 216 (WI.RecordingTraceDetailsSidebarPanel.prototype.set action): 217 (WI.RecordingTraceDetailsSidebarPanel): 218 (WI.RecordingTraceDetailsSidebarPanel.prototype.updateAction): Deleted. 219 Now that the selected action is exposed to the UI as a supplemental 220 represented object, details sidebars can be more decoupled from the 221 canvas tab, and be notified of changes to the selection via `inspect()`. 222 223 * UserInterface/Views/ResourceIcons.css: 224 (.canvas > .icon): Deleted. 225 (.shader-program .icon): Deleted. 226 1 227 2018-02-08 Nikita Vasilyev <nvasilyev@apple.com> 2 228 -
trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js
r228215 r228301 169 169 localizedStrings["Canvas %d"] = "Canvas %d"; 170 170 localizedStrings["Canvas %s"] = "Canvas %s"; 171 localizedStrings["Canvas Overview"] = "Canvas Overview";172 171 localizedStrings["Canvases"] = "Canvases"; 173 172 localizedStrings["Cap"] = "Cap"; … … 403 402 localizedStrings["Export"] = "Export"; 404 403 localizedStrings["Export HAR"] = "Export HAR"; 404 localizedStrings["Export recording (%s)"] = "Export recording (%s)"; 405 405 localizedStrings["Expression"] = "Expression"; 406 406 localizedStrings["Extension Scripts"] = "Extension Scripts"; … … 497 497 localizedStrings["Immediate Pause Requested"] = "Immediate Pause Requested"; 498 498 localizedStrings["Import"] = "Import"; 499 localizedStrings["Import recording from file"] = "Import recording from file"; 500 localizedStrings["Imported Recordings"] = "Imported Recordings"; 499 501 localizedStrings["Incomplete"] = "Incomplete"; 500 502 localizedStrings["Indent"] = "Indent"; … … 906 908 localizedStrings["Start element selection (%s)"] = "Start element selection (%s)"; 907 909 localizedStrings["Start recording (%s)\nCreate new recording (%s)"] = "Start recording (%s)\nCreate new recording (%s)"; 908 localizedStrings["Start recording canvas actions. Shift-click to record a single frame."] = "Start recording canvas actions.Shift-click to record a single frame.";910 localizedStrings["Start recording canvas actions.\nShift-click to record a single frame."] = "Start recording canvas actions.\nShift-click to record a single frame."; 909 911 localizedStrings["Start to Finish"] = "Start to Finish"; 910 912 localizedStrings["State"] = "State"; -
trunk/Source/WebInspectorUI/UserInterface/Images/Canvas2D.svg
r219180 r228301 1 1 <?xml version="1.0" encoding="utf-8"?> 2 2 <!-- Copyright © 2017 Apple Inc. All rights reserved. --> 3 <svg viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg">4 < polygon fill="rgb(242, 97, 97)" stroke="white" stroke-width="0.5" points="9,5.226497308103743 14,13.88675134594813 4,13.88675134594813"/>5 < circle fill="rgb(97, 242, 97)" stroke="white" stroke-width="0.5" cx="10" cy="5" r="4"/>6 < rect fill="rgb(92, 140, 229)" stroke="white" stroke-width="0.5" x="1.5" y="3" width="8" height="8"/>3 <svg xmlns="http://www.w3.org/2000/svg" id="root" version="1.1" viewBox="0 0 16 16"> 4 <rect x="1.5" y="1.5" width="13" height="13" rx="1.5" ry="1.5" fill="#fff" stroke="#4d4d4d"/> 5 <path d="M11,9,9,11,6,8,3,11v1.3a.7.7,0,0,0,.7.7h8.6a.7.7,0,0,0,.7-.7V11Z" fill="#666"/> 6 <circle cx="10.5" cy="5.5" r="1.75" fill="#666"/> 7 7 </svg> -
trunk/Source/WebInspectorUI/UserInterface/Images/Canvas3D.svg
r219180 r228301 1 1 <?xml version="1.0" encoding="utf-8"?> 2 2 <!-- Copyright © 2017 Apple Inc. All rights reserved. --> 3 <svg viewBox="0 0 14 16" version="1.1" xmlns="http://www.w3.org/2000/svg">4 < path fill="rgb(92, 140, 229)" stroke="white" stroke-width="0.5" stroke-linejoin="round" stroke-linecap="square" d="M 0.5 4.29857047 L 7.09714095 7.59714095 L 7.09714095 15.0189245 L 0.5 11.720354 L 0.5 4.29857047 Z"/>5 <p ath fill="rgb(242, 97, 97)" stroke="white" stroke-width="0.5" stroke-linejoin="round" stroke-linecap="square" d="M 13.697 4.299 L 7.097 7.597 L 7.097 15.019 L 13.697 11.72 L 13.697 4.299 Z"/>6 <path fill="rgb(97, 242, 97)" stroke="white" stroke-width="0.5" stroke-linejoin="round" d="M 0.5 4.29857047 L 7.09714095 1 L 13.6908901 4.29857047 L 7.09714095 7.59714095 L 0.5 4.29857047 Z"/>3 <svg xmlns="http://www.w3.org/2000/svg" id="root" version="1.1" viewBox="0 0 16 16"> 4 <rect x="1.5" y="1.5" width="13" height="13" rx="1.5" ry="1.5" fill="#fff" stroke="#4d4d4d"/> 5 <polygon points="12.109 10.361 8.451 12.469 8 12.731 7.549 12.469 3.891 10.361 3.891 5.63 4.207 5.45 7.982 3.269 11.775 5.45 12.1 5.639 12.1 6.315 12.109 10.361" fill="#ccc" stroke="#666"/> 6 <path d="M12.1,5.639,8,8,3.891,5.63M8,8v4.731" fill="none" stroke="#666"/> 7 7 </svg> -
trunk/Source/WebInspectorUI/UserInterface/Images/Recording.svg
r223918 r228301 2 2 <!-- Copyright © 2017 Apple Inc. All rights reserved. --> 3 3 <svg xmlns="http://www.w3.org/2000/svg" id="root" version="1.1" viewBox="0 0 16 16"> 4 <path d="M 6.5 8 A 1.5 1.5 0 1 1 5 6.5 1.5 1.5 0 0 1 6.5 8 Z M 5 9.5 h 6 m 0 -3 A 1.5 1.5 0 1 0 12.5 8 1.5 1.5 0 0 0 11 6.5 Z" fill="none" stroke="currentColor"/> 5 <path d="M1.5 3.729 v 8.542 a 1.127 1.127 0 0 0 1 1.22 h 11 a 1.127 1.127 0 0 0 1 -1.22 V 3.729 a 1.127 1.127 0 0 0 -1 -1.22 H 2.5 A 1.127 1.127 0 0 0 1.5 3.729 Z" fill="none" stroke="currentColor"/> 4 <circle cx="4" cy="8" r="2.5" fill="none" stroke="rgb(26, 26, 26)" stroke-width="1.2"/> 5 <circle cx="12" cy="8" r="2.5" fill="none" stroke="rgb(26, 26, 26)" stroke-width="1.2"/> 6 <line x1="4" y1="10.5" x2="12" y2="10.5" fill="none" stroke="rgb(26, 26, 26)"/> 6 7 </svg> -
trunk/Source/WebInspectorUI/UserInterface/Main.html
r228024 r228301 47 47 <link rel="stylesheet" href="Views/CanvasDetailsSidebarPanel.css"> 48 48 <link rel="stylesheet" href="Views/CanvasOverviewContentView.css"> 49 <link rel="stylesheet" href="Views/CanvasSidebarPanel.css"> 49 50 <link rel="stylesheet" href="Views/CanvasTabContentView.css"> 50 51 <link rel="stylesheet" href="Views/ChartDetailsSectionRow.css"> … … 140 141 <link rel="stylesheet" href="Views/ProbeSetDataGrid.css"> 141 142 <link rel="stylesheet" href="Views/ProfileView.css"> 143 <link rel="stylesheet" href="Views/ProgressView.css"> 142 144 <link rel="stylesheet" href="Views/QuickConsole.css"> 143 145 <link rel="stylesheet" href="Views/RadioButtonNavigationItem.css"> … … 146 148 <link rel="stylesheet" href="Views/RecordingStateDetailsSidebarPanel.css"> 147 149 <link rel="stylesheet" href="Views/RecordingTraceDetailsSidebarPanel.css"> 148 <link rel="stylesheet" href="Views/RecordingNavigationSidebarPanel.css">149 150 <link rel="stylesheet" href="Views/RenderingFrameTimelineOverviewGraph.css"> 150 151 <link rel="stylesheet" href="Views/RenderingFrameTimelineView.css"> … … 561 562 <script src="Views/CanvasDetailsSidebarPanel.js"></script> 562 563 <script src="Views/CanvasOverviewContentView.js"></script> 564 <script src="Views/CanvasSidebarPanel.js"></script> 563 565 <script src="Views/CanvasTreeElement.js"></script> 564 566 <script src="Views/ChartDetailsSectionRow.js"></script> … … 689 691 <script src="Views/ProfileNodeTreeElement.js"></script> 690 692 <script src="Views/ProfileView.js"></script> 693 <script src="Views/ProgressView.js"></script> 691 694 <script src="Views/QuickConsole.js"></script> 692 695 <script src="Views/QuickConsoleNavigationBar.js"></script> … … 694 697 <script src="Views/RecordingActionTreeElement.js"></script> 695 698 <script src="Views/RecordingContentView.js"></script> 696 <script src="Views/RecordingNavigationSidebarPanel.js"></script>697 699 <script src="Views/RecordingStateDetailsSidebarPanel.js"></script> 698 700 <script src="Views/RecordingTraceDetailsSidebarPanel.js"></script> -
trunk/Source/WebInspectorUI/UserInterface/Models/RecordingAction.js
r225602 r228301 99 99 get hasVisibleEffect() { return this._hasVisibleEffect; } 100 100 get stateModifiers() { return this._stateModifiers; } 101 102 get state() { return this._state; } 103 set state(state) { this._state = state; } 101 104 102 105 markInvalid() -
trunk/Source/WebInspectorUI/UserInterface/Views/CanvasContentView.css
r224726 r228301 26 26 .content-view.canvas:not(.tab) { 27 27 background-color: hsl(0, 0%, 90%); 28 29 --progress-padding: 8px;30 }31 32 .content-view.canvas:not(.tab) > .progress {33 padding: var(--progress-padding) 0;34 text-align: center;35 color: var(--text-color-gray-medium);36 }37 38 .content-view.canvas:not(.tab) > .progress > .frame-count {39 color: var(--text-color-gray-dark);40 28 } 41 29 … … 47 35 height: 100%; 48 36 padding: 15px; 37 } 38 39 .content-view.canvas:not(.tab) { 40 display: flex; 41 flex-direction: column; 49 42 } 50 43 -
trunk/Source/WebInspectorUI/UserInterface/Views/CanvasContentView.js
r227243 r228301 34 34 this.element.classList.add("canvas"); 35 35 36 this._ recordingProgressElement= null;36 this._progressView = null; 37 37 this._previewContainerElement = null; 38 38 this._previewImageElement = null; … … 46 46 47 47 if (this.representedObject.contextType === WI.Canvas.ContextType.Canvas2D || this.representedObject.contextType === WI.Canvas.ContextType.WebGL) { 48 const toolTip = WI.UIString("Start recording canvas actions. 48 const toolTip = WI.UIString("Start recording canvas actions.\nShift-click to record a single frame."); 49 49 const altToolTip = WI.UIString("Stop recording canvas actions"); 50 50 this._recordButtonNavigationItem = new WI.ToggleButtonNavigationItem("record-start-stop", toolTip, altToolTip, "Images/Record.svg", "Images/Stop.svg", 13, 13); … … 67 67 get navigationItems() 68 68 { 69 let navigationItems = [this._refreshButtonNavigationItem, this._showGridButtonNavigationItem]; 70 if (this._recordButtonNavigationItem) 71 navigationItems.unshift(this._recordButtonNavigationItem); 72 return navigationItems; 69 // The toggle recording NavigationItem isn't added to the ContentBrowser's NavigationBar. 70 // It's added to the "quick access" NavigationBar shown when hovering the canvas in the overview. 71 return [this._refreshButtonNavigationItem, this._showGridButtonNavigationItem]; 73 72 } 74 73 … … 98 97 99 98 let header = this.element.appendChild(document.createElement("header")); 99 header.addEventListener("click", (event) => { event.stopPropagation(); }); 100 100 101 let titles = header.appendChild(document.createElement("div")); 101 102 titles.className = "titles"; … … 121 122 122 123 let footer = this.element.appendChild(document.createElement("footer")); 124 footer.addEventListener("click", (event) => { event.stopPropagation(); }); 123 125 124 126 this._recordingSelectContainer = footer.appendChild(document.createElement("div")); … … 179 181 180 182 this._updateRecordNavigationItem(); 183 this._updateProgressView(); 181 184 } 182 185 … … 263 266 { 264 267 this._updateRecordNavigationItem(); 265 266 if (!this.representedObject.isRecording) 267 return; 268 269 if (!this._recordingProgressElement) { 270 this._recordingProgressElement = this._previewContainerElement.insertAdjacentElement("beforebegin", document.createElement("div")); 271 this._recordingProgressElement.className = "progress"; 272 } 273 274 this._recordingProgressElement.textContent = WI.UIString("Waiting for frames…"); 268 this._updateProgressView(); 275 269 } 276 270 … … 281 275 return; 282 276 283 this._recordingProgressElement.removeChildren(); 284 285 let frameCountElement = this._recordingProgressElement.appendChild(document.createElement("span")); 286 frameCountElement.className = "frame-count"; 287 288 let frameString = frameCount === 1 ? WI.UIString("%d Frame") : WI.UIString("%d Frames"); 289 frameCountElement.textContent = frameString.format(frameCount); 290 291 this._recordingProgressElement.append(" "); 292 293 let bufferUsedElement = this._recordingProgressElement.appendChild(document.createElement("span")); 294 bufferUsedElement.className = "buffer-used"; 295 bufferUsedElement.textContent = "(" + Number.bytesToString(bufferUsed) + ")"; 277 this._updateProgressView(frameCount, bufferUsed); 296 278 } 297 279 … … 304 286 return; 305 287 288 this._updateProgressView(); 289 306 290 if (recording) 307 291 this._addRecording(recording); 308 309 if (this._recordingProgressElement) {310 this._recordingProgressElement.remove();311 this._recordingProgressElement = null;312 }313 292 } 314 293 … … 389 368 this._recordButtonNavigationItem.toggled = isRecording; 390 369 370 this._refreshButtonNavigationItem.enabled = !isRecording; 371 391 372 this.element.classList.toggle("is-recording", isRecording); 392 373 } 374 375 _updateProgressView(frameCount, bufferUsed) 376 { 377 if (!this.representedObject.isRecording) { 378 if (this._progressView && this._progressView.parentView) { 379 this.removeSubview(this._progressView); 380 this._progressView = null; 381 } 382 return; 383 } 384 385 if (!this._progressView) { 386 this._progressView = new WI.ProgressView; 387 this.element.insertBefore(this._progressView.element, this._previewContainerElement); 388 this.addSubview(this._progressView); 389 } 390 391 let title; 392 if (frameCount) { 393 let formatString = frameCount === 1 ? WI.UIString("%d Frame") : WI.UIString("%d Frames"); 394 title = formatString.format(frameCount); 395 } else 396 title = WI.UIString("Waiting for frames…") 397 398 this._progressView.title = title; 399 this._progressView.subtitle = bufferUsed ? Number.bytesToString(bufferUsed) : ""; 400 } 393 401 }; -
trunk/Source/WebInspectorUI/UserInterface/Views/CanvasDetailsSidebarPanel.js
r225487 r228301 56 56 this.canvas = objects.find((object) => object instanceof WI.Canvas); 57 57 58 return true;58 return !!this.canvas; 59 59 } 60 60 -
trunk/Source/WebInspectorUI/UserInterface/Views/CanvasOverviewContentView.css
r227155 r228301 39 39 } 40 40 41 .content-view.canvas-overview .content-view.canvas > :matches(header, .progress, .preview, footer){41 .content-view.canvas-overview .content-view.canvas { 42 42 border: 1px solid var(--border-color); 43 cursor: pointer; 43 44 } 44 45 45 .content-view.canvas-overview .content-view.canvas.selected > :matches(.progress, .preview, footer), 46 .content-view.canvas-overview .content-view.canvas.selected:not(.is-recording) > header { 47 border-color: var(--selected-background-color); 46 .content-view.canvas-overview .content-view.canvas.is-recording { 47 border-color: red; 48 48 } 49 49 … … 56 56 padding: 0 6px; 57 57 height: var(--navigation-bar-height); 58 cursor: default; 58 59 } 59 60 60 61 .content-view.canvas-overview .content-view.canvas > header { 61 62 font-size: 13px; 62 border-bottom: none;63 63 } 64 64 65 65 .content-view.canvas-overview .content-view.canvas.is-recording > header { 66 66 background-color: red; 67 border-color: red;68 67 } 69 68 … … 101 100 align-items: initial; 102 101 border: none; 102 opacity: 0; 103 transition: opacity 200ms ease-in-out; 103 104 } 104 105 105 .content-view.canvas-overview .content-view.canvas:not(:hover, .is-recording, .selected) > header > .navigation-bar { 106 visibility: hidden; 106 .content-view.canvas-overview .content-view.canvas:matches(:hover, .is-recording) > header > .navigation-bar { 107 opacity: 1; 108 transition: opacity 200ms ease-in-out; 107 109 } 108 110 … … 120 122 } 121 123 122 .content-view.canvas-overview .content-view.canvas > :matches(.progress, .preview) {123 border-top: none; 124 border-bottom: none;124 .content-view.canvas-overview .content-view.canvas.is-recording > .progress-view, 125 .content-view.canvas-overview .content-view.canvas > .preview { 126 height: 280px; 125 127 } 126 128 127 .content-view.canvas-overview .content-view.canvas > .preview { 128 height: var(--preview-height); 129 130 --preview-height: 280px; 131 } 132 133 .content-view.canvas-overview .content-view.canvas > .progress ~ .preview { 134 /* Keep the height of each CanvasContentView constant by subtracting the padding-top, */ 135 /* padding-bottom, and text-height (1em) from the previously set height. */ 136 height: calc(var(--preview-height) - 1em - (2 * var(--progress-padding))); 129 .content-view.canvas-overview .content-view.canvas.is-recording > .preview { 130 display: none; 137 131 } 138 132 -
trunk/Source/WebInspectorUI/UserInterface/Views/CanvasOverviewContentView.js
r227008 r228301 46 46 this.element.classList.add("canvas-overview"); 47 47 48 this._importButtonNavigationItem = new WI.ButtonNavigationItem("import-recording", WI.UIString("Import"), "Images/Import.svg", 15, 15); 49 this._importButtonNavigationItem.toolTip = WI.UIString("Import recording from file"); 50 this._importButtonNavigationItem.buttonStyle = WI.ButtonNavigationItem.Style.ImageAndText; 51 this._importButtonNavigationItem.addEventListener(WI.ButtonNavigationItem.Event.Clicked, () => { WI.canvasManager.importRecording(); }); 52 48 53 this._refreshButtonNavigationItem = new WI.ButtonNavigationItem("refresh-all", WI.UIString("Refresh all"), "Images/ReloadFull.svg", 13, 13); 49 54 this._refreshButtonNavigationItem.enabled = false; … … 54 59 this._showGridButtonNavigationItem.enabled = false; 55 60 this._showGridButtonNavigationItem.addEventListener(WI.ButtonNavigationItem.Event.Clicked, this._showGridButtonClicked, this); 56 57 this.selectionEnabled = true;58 59 this._keyboardShortcuts = [60 new WI.KeyboardShortcut(null, WI.KeyboardShortcut.Key.Up, this._handleUp.bind(this)),61 new WI.KeyboardShortcut(null, WI.KeyboardShortcut.Key.Right, this._handleRight.bind(this)),62 new WI.KeyboardShortcut(null, WI.KeyboardShortcut.Key.Down, this._handleDown.bind(this)),63 new WI.KeyboardShortcut(null, WI.KeyboardShortcut.Key.Left, this._handleLeft.bind(this)),64 ];65 66 let recordShortcut = new WI.KeyboardShortcut(null, WI.KeyboardShortcut.Key.Space, this._handleSpace.bind(this));67 recordShortcut.implicitlyPreventsDefault = false;68 this._keyboardShortcuts.push(recordShortcut);69 70 let recordSingleFrameShortcut = new WI.KeyboardShortcut(WI.KeyboardShortcut.Modifier.Shift, WI.KeyboardShortcut.Key.Space, this._handleSpace.bind(this));71 recordSingleFrameShortcut.implicitlyPreventsDefault = false;72 this._keyboardShortcuts.push(recordSingleFrameShortcut);73 74 for (let shortcut of this._keyboardShortcuts)75 shortcut.disabled = true;76 61 } 77 62 … … 80 65 get navigationItems() 81 66 { 82 return [this._refreshButtonNavigationItem, this._showGridButtonNavigationItem]; 83 } 84 85 get selectionPathComponents() 86 { 87 let components = []; 88 89 if (this.supplementalRepresentedObjects.length) { 90 let [canvas] = this.supplementalRepresentedObjects; 91 let tabContentView = WI.tabBrowser.selectedTabContentView; 92 if (tabContentView) { 93 let treeElement = tabContentView.treeElementForRepresentedObject(canvas); 94 console.assert(treeElement); 95 if (treeElement) { 96 let pathComponent = new WI.GeneralTreeElementPathComponent(treeElement); 97 pathComponent.addEventListener(WI.HierarchicalPathComponent.Event.SiblingWasSelected, this._selectionPathComponentsChanged, this); 98 components.push(pathComponent); 99 } 100 } 101 } 102 103 return components; 67 return [this._importButtonNavigationItem, new WI.DividerNavigationItem, this._refreshButtonNavigationItem, this._showGridButtonNavigationItem]; 104 68 } 105 69 … … 134 98 135 99 WI.settings.showImageGrid.addEventListener(WI.Setting.Event.Changed, this._updateShowImageGrid, this); 136 137 this.addEventListener(WI.ContentView.Event.SupplementalRepresentedObjectsDidChange, this._supplementalRepresentedObjectsDidChange, this);138 139 for (let shortcut of this._keyboardShortcuts)140 shortcut.disabled = false;141 100 } 142 101 … … 144 103 { 145 104 WI.settings.showImageGrid.removeEventListener(null, null, this); 146 147 this.removeEventListener(null, null, this);148 149 for (let shortcut of this._keyboardShortcuts)150 shortcut.disabled = true;151 105 152 106 super.detached(); … … 166 120 } 167 121 168 _changeSelectedItemVertically(shift)169 {170 let itemElementWidth = this.element.firstElementChild.offsetWidth + (2 * this._itemMargin);171 let itemsPerRow = Math.floor(this.element.offsetWidth / itemElementWidth);172 173 let items = Array.from(this.representedObject.items);174 let index = items.indexOf(this._selectedItem);175 if (index === -1)176 index = shift < 0 ? items.length + 1 : itemsPerRow;177 178 index += shift * itemsPerRow;179 if (index < 0)180 index = items.length + index;181 182 this.setSelectedItem(items[index % items.length]);183 }184 185 _changeSelectedItemHorizontally(shift)186 {187 let itemElementWidth = this.element.firstElementChild.offsetWidth + (2 * this._itemMargin);188 let itemsPerRow = Math.floor(this.element.offsetWidth / itemElementWidth);189 190 let items = Array.from(this.representedObject.items);191 let index = items.indexOf(this._selectedItem);192 if (index === -1)193 index = shift >= 0 ? itemsPerRow - 1 : 0;194 195 let selectedRow = Math.floor(index / itemsPerRow);196 index += shift;197 if (index < selectedRow * itemsPerRow)198 index += itemsPerRow;199 else if (index >= (selectedRow + 1) * itemsPerRow)200 index -= itemsPerRow;201 202 this.setSelectedItem(items[index]);203 }204 205 122 _updateNavigationItems() 206 123 { … … 210 127 } 211 128 212 _selectionPathComponentsChanged(event)213 {214 let pathComponent = event.data.pathComponent;215 if (pathComponent.representedObject instanceof WI.Canvas)216 this.setSelectedItem(pathComponent.representedObject);217 else if (pathComponent.representedObject instanceof WI.Recording)218 WI.showRepresentedObject(pathComponent.representedObject);219 }220 221 129 _showGridButtonClicked(event) 222 130 { … … 224 132 } 225 133 226 _handleUp(event)227 {228 this._changeSelectedItemVertically(-1);229 }230 231 _handleRight(event)232 {233 let shift = WI.resolvedLayoutDirection() === WI.LayoutDirection.RTL ? -1 : 1;234 this._changeSelectedItemHorizontally(shift);235 }236 237 _handleDown(event)238 {239 this._changeSelectedItemVertically(1);240 }241 242 _handleLeft(event)243 {244 let shift = WI.resolvedLayoutDirection() === WI.LayoutDirection.RTL ? 1 : -1;245 this._changeSelectedItemHorizontally(shift);246 }247 248 _handleSpace(event)249 {250 if (WI.isEventTargetAnEditableField(event))251 return;252 253 if (!this._selectedItem)254 return;255 256 if (this._selectedItem.isRecording)257 WI.canvasManager.stopRecording();258 else if (!WI.canvasManager.recordingCanvas) {259 let singleFrame = !!event.shiftKey;260 WI.canvasManager.startRecording(this._selectedItem, singleFrame);261 }262 263 event.preventDefault();264 }265 266 134 _updateShowImageGrid() 267 135 { 268 136 this._showGridButtonNavigationItem.activated = !!WI.settings.showImageGrid.value; 269 }270 271 _supplementalRepresentedObjectsDidChange()272 {273 this.dispatchEventToListeners(WI.ContentView.Event.SelectionPathComponentsDidChange);274 137 } 275 138 -
trunk/Source/WebInspectorUI/UserInterface/Views/CanvasTabContentView.css
r223918 r228301 24 24 */ 25 25 26 .content-view.tab.canvas .navigation-bar > .item > .hierarchical-path-component >.icon {27 opacity: 0.7;26 .content-view.tab.canvas .navigation-bar > .item .canvas-overview .icon { 27 content: url(../Images/CanvasOverview.svg); 28 28 } 29 29 30 /* FIXME: this can be removed once <https://webkit.org/b/177606> is complete. */ 31 .content-view.tab.canvas .navigation-bar > .item .canvas .icon { 32 content: url(../Images/Canvas.svg); 30 .content-view.tab.canvas .navigation-bar > .item .canvas.canvas-2d .icon { 31 content: url(../Images/Canvas2D.svg); 32 } 33 34 .content-view.tab.canvas .navigation-bar > .item .canvas.webgl .icon { 35 content: url(../Images/Canvas3D.svg); 33 36 } 34 37 … … 36 39 content: url(../Images/Recording.svg); 37 40 } 41 42 .content-view.tab.canvas .navigation-bar > .item .shader-program > .icon { 43 content: image-set(url(../Images/DocumentGL.png) 1x, url(../Images/DocumentGL@2x.png) 2x); 44 } -
trunk/Source/WebInspectorUI/UserInterface/Views/CanvasTabContentView.js
r228024 r228301 32 32 let tabBarItem = WI.GeneralTabBarItem.fromTabInfo(WI.CanvasTabContentView.tabInfo()); 33 33 34 const navigationSidebarPanelConstructor = WI. RecordingNavigationSidebarPanel;34 const navigationSidebarPanelConstructor = WI.CanvasSidebarPanel; 35 35 const detailsSidebarPanelConstructors = [WI.RecordingStateDetailsSidebarPanel, WI.RecordingTraceDetailsSidebarPanel, WI.CanvasDetailsSidebarPanel]; 36 36 const disableBackForward = true; … … 42 42 this._canvasTreeOutline.addEventListener(WI.TreeOutline.Event.SelectionDidChange, this._canvasTreeOutlineSelectionDidChange, this); 43 43 44 const leftArrow = "Images/BackForwardArrows.svg#left-arrow-mask"; 45 const rightArrow = "Images/BackForwardArrows.svg#right-arrow-mask"; 46 let isRTL = WI.resolvedLayoutDirection() === WI.LayoutDirection.RTL; 47 let backButtonImage = isRTL ? rightArrow : leftArrow; 48 this._overviewNavigationItem = new WI.ButtonNavigationItem("canvas-overview", WI.UIString("Canvas Overview"), backButtonImage, 8, 13); 49 this._overviewNavigationItem.hidden = true; 50 this._overviewNavigationItem.visibilityPriority = WI.NavigationItem.VisibilityPriority.High; 51 this._overviewNavigationItem.addEventListener(WI.ButtonNavigationItem.Event.Clicked, () => { this.showRepresentedObject(this._canvasCollection); }); 52 53 this.contentBrowser.navigationBar.insertNavigationItem(this._overviewNavigationItem, 2); 54 this.contentBrowser.navigationBar.insertNavigationItem(new WI.DividerNavigationItem, 3); 55 56 this.navigationSidebarPanel.contentTreeOutline.addEventListener(WI.TreeOutline.Event.SelectionDidChange, this._navigationSidebarTreeOutlineSelectionChanged, this); 44 this._overviewTreeElement = new WI.GeneralTreeElement("canvas-overview", WI.UIString("Overview"), null, this._canvasCollection); 45 this._canvasTreeOutline.appendChild(this._overviewTreeElement); 46 47 this._importedRecordingsTreeElement = new WI.FolderTreeElement(WI.UIString("Imported Recordings")); 48 this._importedRecordingsTreeElement.hidden = true; 49 this._overviewTreeElement.appendChild(this._importedRecordingsTreeElement); 50 51 this._recordShortcut = new WI.KeyboardShortcut(null, WI.KeyboardShortcut.Key.Space, this._handleSpace.bind(this)); 52 this._recordShortcut.implicitlyPreventsDefault = false; 53 54 this._recordSingleFrameShortcut = new WI.KeyboardShortcut(WI.KeyboardShortcut.Modifier.Shift, WI.KeyboardShortcut.Key.Space, this._handleSpace.bind(this)); 55 this._recordSingleFrameShortcut.implicitlyPreventsDefault = false; 57 56 } 58 57 … … 89 88 canShowRepresentedObject(representedObject) 90 89 { 91 return representedObject instanceof WI.CanvasCollection 90 return representedObject instanceof WI.Canvas 91 || representedObject instanceof WI.CanvasCollection 92 92 || representedObject instanceof WI.Recording 93 93 || representedObject instanceof WI.ShaderProgram; 94 }95 96 showRepresentedObject(representedObject, cookie)97 {98 super.showRepresentedObject(representedObject, cookie);99 100 this.navigationSidebarPanel.recording = null;101 102 if (representedObject instanceof WI.CanvasCollection || representedObject instanceof WI.ShaderProgram) {103 this._overviewNavigationItem.hidden = true;104 return;105 }106 107 if (representedObject instanceof WI.Recording) {108 this._overviewNavigationItem.hidden = false;109 this.navigationSidebarPanel.recording = representedObject;110 return;111 }112 113 console.assert(false, "Should not be reached.");114 94 } 115 95 … … 142 122 WI.canvasManager.addEventListener(WI.CanvasManager.Event.RecordingImported, this._recordingImportedOrStopped, this); 143 123 WI.canvasManager.addEventListener(WI.CanvasManager.Event.RecordingStopped, this._recordingImportedOrStopped, this); 144 WI.RecordingContentView.addEventListener(WI.RecordingContentView.Event.RecordingActionIndexChanged, this._recordingActionIndexChanged, this);145 124 146 125 let canvases = new Set(Array.from(this._canvasCollection.items).concat(WI.canvasManager.canvases)); … … 169 148 _addCanvas(canvas) 170 149 { 171 this._ canvasTreeOutline.appendChild(new WI.CanvasTreeElement(canvas));150 this._overviewTreeElement.appendChild(new WI.CanvasTreeElement(canvas)); 172 151 this._canvasCollection.add(canvas); 173 152 … … 178 157 _removeCanvas(canvas) 179 158 { 180 // Move all existing recordings for the removed canvas to be imported recordings, as the 181 // recording's source is no longer valid. 182 for (let recording of canvas.recordingCollection.items) { 183 recording.source = null; 184 recording.createDisplayName(); 185 186 const subtitle = null; 187 this._canvasTreeOutline.appendChild(new WI.GeneralTreeElement(["recording"], recording.displayName, subtitle, recording)); 188 } 159 // FIXME: Create tree elements/cards for recordings belonging to the removed canvas. 189 160 190 161 let treeElement = this._canvasTreeOutline.findTreeElement(canvas); 191 162 console.assert(treeElement, "Missing tree element for canvas.", canvas); 192 this._ canvasTreeOutline.removeChild(treeElement);163 this._overviewTreeElement.removeChild(treeElement); 193 164 this._canvasCollection.remove(canvas); 194 165 … … 215 186 216 187 let representedObject = selectedElement.representedObject; 217 218 if (this.canShowRepresentedObject(representedObject)) { 219 this.showRepresentedObject(representedObject); 220 221 if (representedObject instanceof WI.Recording) 222 this._updateActionIndex(0); 223 return; 224 } 225 226 if (representedObject instanceof WI.Canvas) { 227 this.showRepresentedObject(this._canvasCollection); 228 this.contentBrowser.currentContentView.setSelectedItem(representedObject); 229 return; 230 } 231 232 console.assert(false, "Unexpected representedObject.", representedObject); 188 if (!this.canShowRepresentedObject(representedObject)) { 189 console.assert(false, "Unexpected representedObject.", representedObject); 190 return; 191 } 192 193 this.showRepresentedObject(representedObject); 233 194 } 234 195 … … 244 205 } 245 206 246 _navigationSidebarTreeOutlineSelectionChanged(event)247 {248 if (!event.data.selectedElement)249 return;250 251 let recordingContentView = this.contentBrowser.currentContentView;252 if (!(recordingContentView instanceof WI.RecordingContentView))253 return;254 255 let selectedTreeElement = event.data.selectedElement;256 if (selectedTreeElement instanceof WI.FolderTreeElement)257 selectedTreeElement = selectedTreeElement.children.lastValue;258 259 this._updateActionIndex(selectedTreeElement.index, {suppressNavigationSidebarUpdate: true});260 }261 262 207 _recordingAdded(recording, options = {}) 263 208 { … … 265 210 const subtitle = null; 266 211 let recordingTreeElement = new WI.GeneralTreeElement(["recording"], recording.displayName, subtitle, recording); 267 this._canvasTreeOutline.appendChild(recordingTreeElement); 268 } 269 270 if (!options.suppressShowRecording) { 212 this._importedRecordingsTreeElement.hidden = false; 213 this._importedRecordingsTreeElement.appendChild(recordingTreeElement); 214 } 215 216 if (!options.suppressShowRecording) 271 217 this.showRepresentedObject(recording); 272 this._updateActionIndex(0, {suppressNavigationSidebarUpdate: true}); 273 } 274 } 275 276 _recordingActionIndexChanged(event) 277 { 278 if (event.target !== this.contentBrowser.currentContentView) 279 return; 280 281 this._updateActionIndex(event.data.index); 282 } 283 284 _updateActionIndex(index, options = {}) 285 { 286 options.actionCompletedCallback = (action, context) => { 287 for (let detailsSidebarPanel of this.detailsSidebarPanels) { 288 if (detailsSidebarPanel.updateAction) 289 detailsSidebarPanel.updateAction(action, context, options); 290 } 291 }; 292 293 if (!options.suppressNavigationSidebarUpdate) 294 this.navigationSidebarPanel.updateActionIndex(index, options); 295 296 this.contentBrowser.currentContentView.updateActionIndex(index, options); 218 } 219 220 _handleSpace(event) 221 { 222 if (WI.isEventTargetAnEditableField(event)) 223 return; 224 225 if (!this.navigationSidebarPanel) 226 return; 227 228 let canvas = this.navigationSidebarPanel.canvas; 229 if (!canvas) 230 return; 231 232 if (canvas.isRecording) 233 WI.canvasManager.stopRecording(); 234 else if (!WI.canvasManager.recordingCanvas) { 235 let singleFrame = !!event.shiftKey; 236 WI.canvasManager.startRecording(canvas, singleFrame); 237 } 238 239 event.preventDefault(); 297 240 } 298 241 }; -
trunk/Source/WebInspectorUI/UserInterface/Views/CanvasTreeElement.js
r224200 r228301 26 26 WI.CanvasTreeElement = class CanvasTreeElement extends WI.FolderizedTreeElement 27 27 { 28 constructor(representedObject )28 constructor(representedObject, showRecordings = true) 29 29 { 30 30 console.assert(representedObject instanceof WI.Canvas); 31 31 32 const subtitle = null;32 let subtitle = WI.Canvas.displayNameForContextType(representedObject.contextType); 33 33 super(["canvas", representedObject.contextType], representedObject.displayName, subtitle, representedObject); 34 34 35 35 this.registerFolderizeSettings("shader-programs", WI.UIString("Shader Programs"), this.representedObject.shaderProgramCollection, WI.ShaderProgramTreeElement); 36 36 37 function createRecordingTreeElement(recording) { 38 return new WI.GeneralTreeElement(["recording"], recording.displayName, subtitle, recording); 37 WI.canvasManager.addEventListener(WI.CanvasManager.Event.RecordingStarted, this._updateStatus, this); 38 WI.canvasManager.addEventListener(WI.CanvasManager.Event.RecordingStopped, this._updateStatus, this); 39 40 this.representedObject.shaderProgramCollection.addEventListener(WI.Collection.Event.ItemAdded, this._handleItemAdded, this); 41 this.representedObject.shaderProgramCollection.addEventListener(WI.Collection.Event.ItemRemoved, this._handleItemRemoved, this); 42 43 this._showRecordings = showRecordings; 44 if (this._showRecordings) { 45 function createRecordingTreeElement(recording) { 46 return new WI.GeneralTreeElement(["recording"], recording.displayName, null, recording); 47 } 48 this.registerFolderizeSettings("recordings", WI.UIString("Recordings"), this.representedObject.recordingCollection, createRecordingTreeElement); 49 50 this.representedObject.recordingCollection.addEventListener(WI.Collection.Event.ItemAdded, this._handleItemAdded, this); 51 this.representedObject.recordingCollection.addEventListener(WI.Collection.Event.ItemRemoved, this._handleItemRemoved, this); 39 52 } 40 this.registerFolderizeSettings("recordings", WI.UIString("Recordings"), this.representedObject.recordingCollection, createRecordingTreeElement);41 53 } 42 54 … … 47 59 super.onattach(); 48 60 49 this.representedObject.shaderProgramCollection.addEventListener(WI.Collection.Event.ItemAdded, this._handleItemAdded, this);50 this.representedObject.shaderProgramCollection.addEventListener(WI.Collection.Event.ItemRemoved, this._handleItemRemoved, this);51 52 this.representedObject.recordingCollection.addEventListener(WI.Collection.Event.ItemAdded, this._handleItemAdded, this);53 this.representedObject.recordingCollection.addEventListener(WI.Collection.Event.ItemRemoved, this._handleItemRemoved, this);54 55 61 this.element.addEventListener("mouseover", this._handleMouseOver.bind(this)); 56 62 this.element.addEventListener("mouseout", this._handleMouseOut.bind(this)); 57 63 58 64 this.onpopulate(); 59 }60 61 ondetach()62 {63 this.representedObject.shaderProgramCollection.removeEventListener(WI.Collection.Event.ItemAdded, this._handleItemAdded, this);64 this.representedObject.shaderProgramCollection.removeEventListener(WI.Collection.Event.ItemRemoved, this._handleItemRemoved, this);65 66 this.representedObject.recordingCollection.removeEventListener(WI.Collection.Event.ItemAdded, this._handleItemAdded, this);67 this.representedObject.recordingCollection.removeEventListener(WI.Collection.Event.ItemRemoved, this._handleItemRemoved, this);68 69 super.ondetach();70 65 } 71 66 … … 84 79 this.addChildForRepresentedObject(program); 85 80 86 for (let recording of this.representedObject.recordingCollection.items) 87 this.addChildForRepresentedObject(recording); 81 if (this._showRecordings) { 82 for (let recording of this.representedObject.recordingCollection.items) 83 this.addChildForRepresentedObject(recording); 84 } 88 85 } 89 86 … … 138 135 WI.domTreeManager.hideDOMNodeHighlight(); 139 136 } 137 138 _updateStatus() 139 { 140 if (this.representedObject.isRecording) { 141 if (!this.status || !this.status[WI.CanvasTreeElement.SpinnerSymbol]) { 142 let spinner = new WI.IndeterminateProgressSpinner; 143 this.status = spinner.element; 144 this.status[WI.CanvasTreeElement.SpinnerSymbol] = true; 145 } 146 } else { 147 if (this.status && this.status[WI.CanvasTreeElement.SpinnerSymbol]) 148 this.status = ""; 149 } 150 } 140 151 }; -
trunk/Source/WebInspectorUI/UserInterface/Views/CollectionContentView.js
r225487 r228301 52 52 } 53 53 54 shown() 55 { 56 super.shown(); 57 58 for (let contentView of this._contentViewMap.values()) 59 contentView.shown(); 60 } 61 62 hidden() 63 { 64 for (let contentView of this._contentViewMap.values()) 65 contentView.hidden(); 66 67 super.hidden(); 68 } 69 54 70 get selectionEnabled() 55 71 { -
trunk/Source/WebInspectorUI/UserInterface/Views/ContentView.js
r226415 r228301 256 256 if (representedObject instanceof WI.Canvas) 257 257 return true; 258 if (representedObject instanceof WI.CanvasCollection) 259 return true; 258 260 if (representedObject instanceof WI.ShaderProgram) 259 261 return true; -
trunk/Source/WebInspectorUI/UserInterface/Views/ProgressView.css
r228300 r228301 1 1 /* 2 * Copyright (C) 201 7Apple Inc. All rights reserved.2 * Copyright (C) 2018 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 24 24 */ 25 25 26 .content-view.canvas:not(.tab) { 27 background-color: hsl(0, 0%, 90%); 28 29 --progress-padding: 8px; 26 .progress-view { 27 display: flex; 28 flex-shrink: 0; 29 flex-direction: column; 30 justify-content: center; 31 font-size: var(--message-text-view-font-size); 32 text-align: center; 30 33 } 31 34 32 .content-view.canvas:not(.tab) > .progress { 33 padding: var(--progress-padding) 0; 34 text-align: center; 35 .progress-view > .titles { 36 padding: 15px 0; 37 } 38 39 .progress-view > .titles > .title { 40 color: var(--text-color-gray-dark); 41 } 42 43 .progress-view > .titles > .subtitle { 35 44 color: var(--text-color-gray-medium); 36 45 } 37 46 38 . content-view.canvas:not(.tab) > .progress > .frame-count{39 co lor: var(--text-color-gray-dark);47 .progress-view > .titles > .subtitle::before { 48 content: "\2002\2012\2002"; 40 49 } 41 50 42 .content-view.canvas:not(.tab) > .preview { 43 display: flex; 44 justify-content: center; 45 align-items: center; 46 width: 100%; 47 height: 100%; 48 padding: 15px; 51 .progress-view > .indeterminate-progress-spinner { 52 flex-shrink: 0; 53 width: 24px; 54 height: 24px; 55 margin: 0 auto; 49 56 } 50 51 .content-view.canvas:not(.tab) > .preview > img {52 max-width: 100%;53 max-height: 100%;54 }55 56 .content-view.canvas:not(.tab) > :matches(header, footer) {57 display: none;58 }59 60 .navigation-bar > .item.canvas-record.disabled {61 filter: grayscale();62 opacity: 0.5;63 } -
trunk/Source/WebInspectorUI/UserInterface/Views/RecordingContentView.css
r226077 r228301 68 68 justify-content: center; 69 69 align-items: center; 70 position: relative;71 width: 100%;72 height: 100%;73 70 } 74 71 -
trunk/Source/WebInspectorUI/UserInterface/Views/RecordingContentView.js
r226755 r228301 33 33 34 34 this._index = NaN; 35 this._action = null; 35 36 this._snapshots = []; 36 37 this._initialContent = null; … … 54 55 this._showGridButtonNavigationItem.addEventListener(WI.ButtonNavigationItem.Event.Clicked, this._showGridButtonClicked, this); 55 56 this._showGridButtonNavigationItem.activated = !!WI.settings.showImageGrid.value; 57 58 this._exportButtonNavigationItem = new WI.ButtonNavigationItem("export-recording", WI.UIString("Export"), "Images/Export.svg", 15, 15); 59 this._exportButtonNavigationItem.toolTip = WI.UIString("Export recording (%s)").format(WI.saveKeyboardShortcut.displayName); 60 this._exportButtonNavigationItem.buttonStyle = WI.ButtonNavigationItem.Style.ImageAndText; 61 this._exportButtonNavigationItem.visibilityPriority = WI.NavigationItem.VisibilityPriority.High; 62 this._exportButtonNavigationItem.addEventListener(WI.ButtonNavigationItem.Event.Clicked, () => { this._exportRecording(); }); 56 63 } 57 64 } … … 89 96 let isCanvas2D = this.representedObject.type === WI.Recording.Type.Canvas2D; 90 97 let isCanvasWebGL = this.representedObject.type === WI.Recording.Type.CanvasWebGL; 91 if (isCanvas2D || isCanvasWebGL) { 92 let navigationItems = [this._showGridButtonNavigationItem]; 93 if (isCanvas2D && WI.RecordingContentView.supportsCanvasPathDebugging()) 94 navigationItems.unshift(this._showPathButtonNavigationItem); 95 return navigationItems; 96 } 97 return []; 98 } 99 100 updateActionIndex(index, options = {}) 98 if (!isCanvas2D && !isCanvasWebGL) 99 return []; 100 101 let navigationItems = [this._exportButtonNavigationItem, new WI.DividerNavigationItem]; 102 if (isCanvas2D && WI.RecordingContentView.supportsCanvasPathDebugging()) 103 navigationItems.push(this._showPathButtonNavigationItem); 104 105 navigationItems.push(this._showGridButtonNavigationItem); 106 return navigationItems; 107 } 108 109 get supplementalRepresentedObjects() 110 { 111 return this._action ? [this._action] : []; 112 } 113 114 updateActionIndex(index) 101 115 { 102 116 if (!this.representedObject) … … 115 129 116 130 if (this.representedObject.type === WI.Recording.Type.Canvas2D) 117 this._throttler._generateContentCanvas2D(index, actions , options);131 this._throttler._generateContentCanvas2D(index, actions); 118 132 else if (this.representedObject.type === WI.Recording.Type.CanvasWebGL) 119 this._throttler._generateContentCanvasWebGL(index, actions , options);133 this._throttler._generateContentCanvasWebGL(index, actions); 120 134 }); 121 135 } … … 151 165 get saveData() 152 166 { 153 let filename = this.representedObject.displayName; 154 if (!filename.endsWith(".json")) 155 filename += ".json"; 156 157 return { 158 url: "web-inspector:///" + encodeURI(filename), 159 content: JSON.stringify(this.representedObject.toJSON()), 160 forceSaveAs: true, 161 }; 167 return {customSaveHandler: () => { this._exportRecording(); }}; 162 168 } 163 169 … … 192 198 // Private 193 199 194 async _generateContentCanvas2D(index, actions, options = {}) 200 _exportRecording() 201 { 202 if (!this.representedObject) { 203 InspectorFrontendHost.beep(); 204 return; 205 } 206 207 let filename = this.representedObject.displayName; 208 let url = "web-inspector:///" + encodeURI(filename) + ".json"; 209 210 WI.saveDataToFile({ 211 url, 212 content: JSON.stringify(this.representedObject.toJSON()), 213 forceSaveAs: true, 214 }); 215 } 216 217 async _generateContentCanvas2D(index, actions) 195 218 { 196 219 let imageLoad = (event) => { … … 199 222 return; 200 223 201 this._generateContentCanvas2D(index, actions , options);224 this._generateContentCanvas2D(index, actions); 202 225 }; 203 226 … … 227 250 for (let name in snapshot.state) { 228 251 if (!(name in snapshot.context)) 252 continue; 253 254 // Skip internal state used for path debugging. 255 if (name === "currentX" || name === "currentY") 229 256 continue; 230 257 … … 305 332 this._pathContext.canvas.remove(); 306 333 307 callback(); 334 let state = { 335 currentX: snapshot.context.currentX, 336 currentY: snapshot.context.currentY, 337 direction: snapshot.context.direction, 338 fillStyle: snapshot.context.fillStyle, 339 font: snapshot.context.font, 340 globalAlpha: snapshot.context.globalAlpha, 341 globalCompositeOperation: snapshot.context.globalCompositeOperation, 342 imageSmoothingEnabled: snapshot.context.imageSmoothingEnabled, 343 imageSmoothingQuality: snapshot.context.imageSmoothingQuality, 344 lineCap: snapshot.context.lineCap, 345 lineDash: snapshot.context.getLineDash(), 346 lineDashOffset: snapshot.context.lineDashOffset, 347 lineJoin: snapshot.context.lineJoin, 348 lineWidth: snapshot.context.lineWidth, 349 miterLimit: snapshot.context.miterLimit, 350 shadowBlur: snapshot.context.shadowBlur, 351 shadowColor: snapshot.context.shadowColor, 352 shadowOffsetX: snapshot.context.shadowOffsetX, 353 shadowOffsetY: snapshot.context.shadowOffsetY, 354 strokeStyle: snapshot.context.strokeStyle, 355 textAlign: snapshot.context.textAlign, 356 textBaseline: snapshot.context.textBaseline, 357 transform: snapshot.context.getTransform(), 358 webkitImageSmoothingEnabled: snapshot.context.webkitImageSmoothingEnabled, 359 webkitLineDash: snapshot.context.webkitLineDash, 360 webkitLineDashOffset: snapshot.context.webkitLineDashOffset, 361 }; 362 363 if (WI.RecordingContentView.supportsCanvasPathDebugging()) 364 state.setPath = [snapshot.context.getPath()]; 308 365 309 366 snapshot.context.restore(); 310 367 while (saveCount-- > 0) 311 368 snapshot.context.restore(); 369 370 return state; 312 371 }; 313 372 … … 385 444 } 386 445 387 applyActions(startIndex, snapshot.index - 1, () => { 388 snapshot.state = { 389 direction: snapshot.context.direction, 390 fillStyle: snapshot.context.fillStyle, 391 font: snapshot.context.font, 392 globalAlpha: snapshot.context.globalAlpha, 393 globalCompositeOperation: snapshot.context.globalCompositeOperation, 394 imageSmoothingEnabled: snapshot.context.imageSmoothingEnabled, 395 imageSmoothingQuality: snapshot.context.imageSmoothingQuality, 396 lineCap: snapshot.context.lineCap, 397 lineDashOffset: snapshot.context.lineDashOffset, 398 lineJoin: snapshot.context.lineJoin, 399 lineWidth: snapshot.context.lineWidth, 400 miterLimit: snapshot.context.miterLimit, 401 setLineDash: [snapshot.context.getLineDash()], 402 setTransform: [snapshot.context.getTransform()], 403 shadowBlur: snapshot.context.shadowBlur, 404 shadowColor: snapshot.context.shadowColor, 405 shadowOffsetX: snapshot.context.shadowOffsetX, 406 shadowOffsetY: snapshot.context.shadowOffsetY, 407 strokeStyle: snapshot.context.strokeStyle, 408 textAlign: snapshot.context.textAlign, 409 textBaseline: snapshot.context.textBaseline, 410 webkitImageSmoothingEnabled: snapshot.context.webkitImageSmoothingEnabled, 411 webkitLineDash: snapshot.context.webkitLineDash, 412 webkitLineDashOffset: snapshot.context.webkitLineDashOffset, 413 }; 414 415 if (WI.RecordingContentView.supportsCanvasPathDebugging()) 416 snapshot.state.setPath = [snapshot.context.getPath()]; 417 }); 446 snapshot.state = applyActions(startIndex, snapshot.index - 1); 418 447 419 448 snapshot.content = new Image; … … 431 460 } 432 461 433 applyActions(snapshot.index, this._index, () => { 434 if (options.actionCompletedCallback) 435 options.actionCompletedCallback(actions[this._index], snapshot.context); 436 }); 462 this._action = actions[this._index]; 463 464 let state = applyActions(snapshot.index, this._index); 465 console.assert(!this._action.state || Object.shallowEqual(this._action.state, state)); 466 if (!this._action.state) 467 this._action.state = state; 468 469 this.dispatchEventToListeners(WI.ContentView.Event.SupplementalRepresentedObjectsDidChange); 437 470 438 471 this._previewContainer.appendChild(snapshot.element); … … 440 473 } 441 474 442 async _generateContentCanvasWebGL(index, actions , options = {})475 async _generateContentCanvasWebGL(index, actions) 443 476 { 444 477 let imageLoad = (event) => { … … 447 480 return; 448 481 449 this._generateContentCanvasWebGL(index, actions , options);482 this._generateContentCanvasWebGL(index, actions); 450 483 }; 451 484 … … 482 515 } 483 516 484 if (options.actionCompletedCallback) 485 options.actionCompletedCallback(actions[this._index]); 517 this.dispatchEventToListeners(WI.ContentView.Event.SupplementalRepresentedObjectsDidChange); 486 518 } 487 519 … … 546 578 index = this.representedObject.visualActionIndexes[visualActionIndex]; 547 579 548 this. dispatchEventToListeners(WI.RecordingContentView.Event.RecordingActionIndexChanged, {index});580 this.updateActionIndex(index); 549 581 } 550 582 }; 551 583 552 584 WI.RecordingContentView.SnapshotInterval = 5000; 553 554 WI.RecordingContentView.Event = {555 RecordingActionIndexChanged: "recording-action-index-changed",556 }; -
trunk/Source/WebInspectorUI/UserInterface/Views/RecordingStateDetailsSidebarPanel.js
r224433 r228301 44 44 45 45 this.recording = objects.find((object) => object instanceof WI.Recording && object.type === WI.Recording.Type.Canvas2D); 46 this.action = objects.find((object) => object instanceof WI.RecordingAction); 46 47 47 return !!this._recording;48 return this._recording && this._action; 48 49 } 49 50 … … 60 61 } 61 62 62 updateAction(action, context, options = {})63 set action(action) 63 64 { 65 console.assert(!action || action instanceof WI.RecordingAction); 64 66 if (!this._recording || action === this._action) 65 67 return; … … 67 69 this._action = action; 68 70 69 if (this._ recording.type === WI.Recording.Type.Canvas2D)70 this._generateDetailsCanvas2D( action, context, options);71 if (this._action && this._recording.type === WI.Recording.Type.Canvas2D) 72 this._generateDetailsCanvas2D(this._action); 71 73 72 74 this.updateLayoutIfNeeded(); … … 75 77 // Private 76 78 77 _generateDetailsCanvas2D(action , context, options = {})79 _generateDetailsCanvas2D(action) 78 80 { 79 81 if (!this._dataGrid) { … … 88 90 this._dataGrid.removeChildren(); 89 91 90 if (!context) 92 console.assert(action.state); 93 if (!action.state) 91 94 return; 92 93 let state = {};94 95 if (WI.RecordingContentView.supportsCanvasPathDebugging()) {96 state.currentX = context.currentX;97 state.currentY = context.currentY;98 }99 100 state.direction = context.direction;101 state.fillStyle = context.fillStyle;102 state.font = context.font;103 state.globalAlpha = context.globalAlpha;104 state.globalCompositeOperation = context.globalCompositeOperation;105 state.imageSmoothingEnabled = context.imageSmoothingEnabled;106 state.imageSmoothingQuality = context.imageSmoothingQuality;107 state.lineCap = context.lineCap;108 state.lineDash = context.getLineDash();109 state.lineDashOffset = context.lineDashOffset;110 state.lineJoin = context.lineJoin;111 state.lineWidth = context.lineWidth;112 state.miterLimit = context.miterLimit;113 state.shadowBlur = context.shadowBlur;114 state.shadowColor = context.shadowColor;115 state.shadowOffsetX = context.shadowOffsetX;116 state.shadowOffsetY = context.shadowOffsetY;117 state.strokeStyle = context.strokeStyle;118 state.textAlign = context.textAlign;119 state.textBaseline = context.textBaseline;120 state.transform = context.getTransform();121 state.webkitImageSmoothingEnabled = context.webkitImageSmoothingEnabled;122 state.webkitLineDash = context.webkitLineDash;123 state.webkitLineDashOffset = context.webkitLineDashOffset;124 95 125 96 function isColorProperty(name) { … … 136 107 } 137 108 138 for (let name in state) { 139 let value = state[name]; 109 for (let name in action.state) { 110 // Skip internal state used for path debugging. 111 if (name === "setPath") 112 continue; 113 114 let value = action.state[name]; 140 115 if (typeof value === "object") { 141 116 let isGradient = value instanceof CanvasGradient; -
trunk/Source/WebInspectorUI/UserInterface/Views/RecordingTraceDetailsSidebarPanel.js
r225261 r228301 47 47 48 48 this.recording = objects.find((object) => object instanceof WI.Recording); 49 this.action = objects.find((object) => object instanceof WI.RecordingAction); 49 50 50 return !!this._recording;51 return this._recording && this._action; 51 52 } 52 53 … … 62 63 } 63 64 64 updateAction(action, context, options = {})65 set action(action) 65 66 { 67 console.assert(!action || action instanceof WI.RecordingAction); 66 68 if (!this._recording || action === this._action) 67 69 return; … … 70 72 71 73 this.contentView.element.removeChildren(); 74 75 if (!this._action) 76 return; 72 77 73 78 let trace = this._action.trace; -
trunk/Source/WebInspectorUI/UserInterface/Views/ResourceIcons.css
r224975 r228301 77 77 } 78 78 79 .canvas > .icon {80 content: url(../Images/Canvas.svg);81 }82 83 .shader-program .icon {84 content: image-set(url(../Images/DocumentGL.png) 1x, url(../Images/DocumentGL@2x.png) 2x);85 }86 87 79 .large .resource-icon .icon { 88 80 content: image-set(url(../Images/DocumentGenericLarge.png) 1x, url(../Images/DocumentGenericLarge@2x.png) 2x);
Note: See TracChangeset
for help on using the changeset viewer.