Web Inspector: Canvas tab: create icons for recordings/shaders in the preview tile
authorwebkit@devinrousso.com <webkit@devinrousso.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 20 Aug 2018 20:30:50 +0000 (20:30 +0000)
committerwebkit@devinrousso.com <webkit@devinrousso.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 20 Aug 2018 20:30:50 +0000 (20:30 +0000)
https://bugs.webkit.org/show_bug.cgi?id=183650

Reviewed by Joseph Pecoraro.

* Localizations/en.lproj/localizedStrings.js:

* UserInterface/Views/CanvasContentView.js:
(WI.CanvasContentView):
(WI.CanvasContentView.prototype.initialLayout):
(WI.CanvasContentView.prototype.attached):
(WI.CanvasContentView.prototype._recordingStopped):
(WI.CanvasContentView.prototype._shaderProgramAdded):
(WI.CanvasContentView.prototype._shaderProgramRemoved):
(WI.CanvasContentView.prototype._updateViewRelatedItems):
(WI.CanvasContentView.prototype._handleViewShaderButtonClicked):
(WI.CanvasContentView.prototype._handleViewRecordingButtonClicked):
(WI.CanvasContentView.prototype._addRecording): Deleted.
(WI.CanvasContentView.prototype._handleRecordingSelectElementChange): Deleted.
* UserInterface/Views/CanvasOverviewContentView.css:
(.content-view.canvas-overview .content-view.canvas > footer > .view-related-items):
(.content-view.canvas-overview .content-view.canvas > footer > .view-related-items > :matches(.view-shader, .view-recording)):
(.content-view.canvas-overview .content-view.canvas > footer > .view-related-items > img + img):
(.content-view.canvas-overview .content-view.canvas > footer > .view-related-items > .view-shader):
(.content-view.canvas-overview .content-view.canvas > footer > .view-related-items > .view-recording):
(.content-view.canvas-overview .content-view.canvas > footer > .recordings): Deleted.
(.content-view.canvas-overview .content-view.canvas > footer > .recordings::before): Deleted.
(.content-view.canvas-overview .content-view.canvas > footer > .recordings > select): Deleted.
(.content-view.canvas-overview .content-view.canvas > footer .recordings > select:focus): Deleted.
Create two image buttons in the bottom left corner of each canvas tile that appear when the
canvas has associated shaders and/or recordings. Clicking each image button will function
similar to path components, in that if there is only one shader/recording, it is immediately
selected, whereas if there are multiple a dropdown is shown.

* UserInterface/Views/CanvasSidebarPanel.js:
(WI.CanvasSidebarPanel.prototype._currentRepresentedObjectsDidChange):
(WI.CanvasSidebarPanel.prototype._recordingChanged):
Drive-by: ensure that the selected recording action is properly updated when first loading a
recording and when scrubbing through one.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@235093 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebInspectorUI/ChangeLog
Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js
Source/WebInspectorUI/UserInterface/Views/CanvasContentView.js
Source/WebInspectorUI/UserInterface/Views/CanvasOverviewContentView.css
Source/WebInspectorUI/UserInterface/Views/CanvasSidebarPanel.js

index 1d0a626..d6e2796 100644 (file)
@@ -1,3 +1,45 @@
+2018-08-20  Devin Rousso  <webkit@devinrousso.com>
+
+        Web Inspector: Canvas tab: create icons for recordings/shaders in the preview tile
+        https://bugs.webkit.org/show_bug.cgi?id=183650
+
+        Reviewed by Joseph Pecoraro.
+
+        * Localizations/en.lproj/localizedStrings.js:
+
+        * UserInterface/Views/CanvasContentView.js:
+        (WI.CanvasContentView):
+        (WI.CanvasContentView.prototype.initialLayout):
+        (WI.CanvasContentView.prototype.attached):
+        (WI.CanvasContentView.prototype._recordingStopped):
+        (WI.CanvasContentView.prototype._shaderProgramAdded):
+        (WI.CanvasContentView.prototype._shaderProgramRemoved):
+        (WI.CanvasContentView.prototype._updateViewRelatedItems):
+        (WI.CanvasContentView.prototype._handleViewShaderButtonClicked):
+        (WI.CanvasContentView.prototype._handleViewRecordingButtonClicked):
+        (WI.CanvasContentView.prototype._addRecording): Deleted.
+        (WI.CanvasContentView.prototype._handleRecordingSelectElementChange): Deleted.
+        * UserInterface/Views/CanvasOverviewContentView.css:
+        (.content-view.canvas-overview .content-view.canvas > footer > .view-related-items):
+        (.content-view.canvas-overview .content-view.canvas > footer > .view-related-items > :matches(.view-shader, .view-recording)):
+        (.content-view.canvas-overview .content-view.canvas > footer > .view-related-items > img + img):
+        (.content-view.canvas-overview .content-view.canvas > footer > .view-related-items > .view-shader):
+        (.content-view.canvas-overview .content-view.canvas > footer > .view-related-items > .view-recording):
+        (.content-view.canvas-overview .content-view.canvas > footer > .recordings): Deleted.
+        (.content-view.canvas-overview .content-view.canvas > footer > .recordings::before): Deleted.
+        (.content-view.canvas-overview .content-view.canvas > footer > .recordings > select): Deleted.
+        (.content-view.canvas-overview .content-view.canvas > footer .recordings > select:focus): Deleted.
+        Create two image buttons in the bottom left corner of each canvas tile that appear when the
+        canvas has associated shaders and/or recordings. Clicking each image button will function
+        similar to path components, in that if there is only one shader/recording, it is immediately
+        selected, whereas if there are multiple a dropdown is shown.
+
+        * UserInterface/Views/CanvasSidebarPanel.js:
+        (WI.CanvasSidebarPanel.prototype._currentRepresentedObjectsDidChange):
+        (WI.CanvasSidebarPanel.prototype._recordingChanged):
+        Drive-by: ensure that the selected recording action is properly updated when first loading a
+        recording and when scrubbing through one.
+
 2018-08-16  Devin Rousso  <drousso@apple.com>
 
         Web Inspector: support breakpoints for arbitrary event names
index aa25795..3014fe8 100644 (file)
@@ -1043,7 +1043,8 @@ localizedStrings["Vertex"] = "Vertex";
 localizedStrings["Vertex Shader"] = "Vertex Shader";
 localizedStrings["Vertical"] = "Vertical";
 localizedStrings["View Image"] = "View Image";
-localizedStrings["View Recordings... (%d)"] = "View Recordings... (%d)";
+localizedStrings["View Recording"] = "View Recording";
+localizedStrings["View Shader"] = "View Shader";
 localizedStrings["View variable value"] = "View variable value";
 localizedStrings["Visibility"] = "Visibility";
 localizedStrings["Visible"] = "Visible";
index ef655b2..0c01e23 100644 (file)
@@ -42,7 +42,6 @@ WI.CanvasContentView = class CanvasContentView extends WI.ContentView
         this._pixelSize = null;
         this._pixelSizeElement = null;
         this._canvasNode = null;
-        this._recordingOptionElementMap = new WeakMap;
 
         if (this.representedObject.contextType === WI.Canvas.ContextType.Canvas2D || this.representedObject.contextType === WI.Canvas.ContextType.WebGL) {
             const toolTip = WI.UIString("Start recording canvas actions.\nShift-click to record a single frame.");
@@ -127,16 +126,20 @@ WI.CanvasContentView = class CanvasContentView extends WI.ContentView
         let footer = this.element.appendChild(document.createElement("footer"));
         footer.addEventListener("click", (event) => { event.stopPropagation(); });
 
-        this._recordingSelectContainer = footer.appendChild(document.createElement("div"));
-        this._recordingSelectContainer.classList.add("recordings", "hidden");
+        this._viewRelatedItemsContainer = footer.appendChild(document.createElement("div"));
+        this._viewRelatedItemsContainer.classList.add("view-related-items");
 
-        this._recordingSelectText = this._recordingSelectContainer.appendChild(document.createElement("span"));
+        this._viewShaderButton = document.createElement("img");
+        this._viewShaderButton.classList.add("view-shader");
+        this._viewShaderButton.title = WI.UIString("View Shader");
+        this._viewShaderButton.addEventListener("click", this._handleViewShaderButtonClicked.bind(this));
 
-        this._recordingSelectElement = this._recordingSelectContainer.appendChild(document.createElement("select"));
-        this._recordingSelectElement.addEventListener("change", this._handleRecordingSelectElementChange.bind(this));
+        this._viewRecordingButton = document.createElement("img");
+        this._viewRecordingButton.classList.add("view-recording");
+        this._viewRecordingButton.title = WI.UIString("View Recording");
+        this._viewRecordingButton.addEventListener("click", this._handleViewRecordingButtonClicked.bind(this));
 
-        for (let recording of this.representedObject.recordingCollection)
-            this._addRecording(recording);
+        this._updateViewRelatedItems();
 
         let flexibleSpaceElement = footer.appendChild(document.createElement("div"));
         flexibleSpaceElement.className = "flexible-space";
@@ -206,11 +209,10 @@ WI.CanvasContentView = class CanvasContentView extends WI.ContentView
         WI.canvasManager.addEventListener(WI.CanvasManager.Event.RecordingStarted, this._recordingStarted, this);
         WI.canvasManager.addEventListener(WI.CanvasManager.Event.RecordingProgress, this._recordingProgress, this);
         WI.canvasManager.addEventListener(WI.CanvasManager.Event.RecordingStopped, this._recordingStopped, this);
+        WI.canvasManager.addEventListener(WI.CanvasManager.Event.ShaderProgramAdded, this._shaderProgramAdded, this);
+        WI.canvasManager.addEventListener(WI.CanvasManager.Event.ShaderProgramRemoved, this._shaderProgramRemoved, this);
 
         WI.settings.showImageGrid.addEventListener(WI.Setting.Event.Changed, this._updateImageGrid, this);
-
-        if (this.didInitialLayout)
-            this._recordingSelectElement.selectedIndex = -1;
     }
 
     detached()
@@ -242,20 +244,6 @@ WI.CanvasContentView = class CanvasContentView extends WI.ContentView
         this._previewContainerElement.appendChild(this._errorElement);
     }
 
-    _addRecording(recording)
-    {
-        let optionElement = this._recordingSelectElement.appendChild(document.createElement("option"));
-        optionElement.textContent = recording.displayName;
-
-        this._recordingOptionElementMap.set(optionElement, recording);
-
-        let recordingCount = this._recordingSelectElement.options.length;
-        this._recordingSelectText.textContent = WI.UIString("View Recordings... (%d)").format(recordingCount);
-        this._recordingSelectContainer.classList.remove("hidden");
-
-        this._recordingSelectElement.selectedIndex = -1;
-    }
-
     _toggleRecording(event)
     {
         if (this.representedObject.isRecording)
@@ -285,29 +273,31 @@ WI.CanvasContentView = class CanvasContentView extends WI.ContentView
     {
         this._updateRecordNavigationItem();
 
-        let {canvas, recording} = event.data;
+        let {canvas} = event.data;
         if (canvas !== this.representedObject)
             return;
 
         this._updateProgressView();
 
-        if (recording)
-            this._addRecording(recording);
+        this._updateViewRelatedItems();
     }
 
-    _handleRecordingSelectElementChange(event)
+    _shaderProgramAdded(event)
     {
-        let selectedOption = this._recordingSelectElement.options[this._recordingSelectElement.selectedIndex];
-        console.assert(selectedOption, "An option should have been selected.");
-        if (!selectedOption)
+        let {shaderProgram} = event.data;
+        if (!shaderProgram || shaderProgram.canvas !== this.representedObject)
             return;
 
-        let representedObject = this._recordingOptionElementMap.get(selectedOption);
-        console.assert(representedObject, "Missing map entry for option.");
-        if (!representedObject)
+        this._updateViewRelatedItems();
+    }
+
+    _shaderProgramRemoved(event)
+    {
+        let {shaderProgram} = event.data;
+        if (!shaderProgram || shaderProgram.canvas !== this.representedObject)
             return;
 
-        WI.showRepresentedObject(representedObject);
+        this._updateViewRelatedItems();
     }
 
     _refreshPixelSize()
@@ -425,4 +415,61 @@ WI.CanvasContentView = class CanvasContentView extends WI.ContentView
         this._progressView.title = title;
         this._progressView.subtitle = bufferUsed ? Number.bytesToString(bufferUsed) : "";
     }
+
+    _updateViewRelatedItems()
+    {
+        this._viewRelatedItemsContainer.removeChildren();
+
+        if (this.representedObject.shaderProgramCollection.size)
+            this._viewRelatedItemsContainer.appendChild(this._viewShaderButton);
+
+        if (this.representedObject.recordingCollection.size)
+            this._viewRelatedItemsContainer.appendChild(this._viewRecordingButton);
+    }
+
+    _handleViewShaderButtonClicked(event)
+    {
+        let shaderPrograms = this.representedObject.shaderProgramCollection;
+        console.assert(shaderPrograms.size);
+        if (!shaderPrograms.size)
+            return;
+
+        if (shaderPrograms.size === 1) {
+            WI.showRepresentedObject(shaderPrograms.values().next().value);
+            return;
+        }
+
+        let contextMenu = WI.ContextMenu.createFromEvent(event);
+
+        for (let shaderProgram of shaderPrograms) {
+            contextMenu.appendItem(shaderProgram.displayName, (event) => {
+                WI.showRepresentedObject(shaderProgram);
+            });
+        }
+
+        contextMenu.show();
+    }
+
+    _handleViewRecordingButtonClicked(event)
+    {
+        let recordings = this.representedObject.recordingCollection;
+        console.assert(recordings.size);
+        if (!recordings.size)
+            return;
+
+        if (recordings.size === 1) {
+            WI.showRepresentedObject(recordings.values().next().value);
+            return;
+        }
+
+        let contextMenu = WI.ContextMenu.createFromEvent(event);
+
+        for (let recording of recordings) {
+            contextMenu.appendItem(recording.displayName, (event) => {
+                WI.showRepresentedObject(recording);
+            });
+        }
+
+        contextMenu.show();
+    }
 };
index 563eac1..cd5c41e 100644 (file)
     border-top: none;
 }
 
-.content-view.canvas-overview .content-view.canvas > footer > .recordings {
-    position: absolute;
+.content-view.canvas-overview .content-view.canvas > footer > .view-related-items {
     display: flex;
     align-items: center;
 }
 
-.content-view.canvas-overview .content-view.canvas > footer > .recordings::before {
-    display: inline-block;
+.content-view.canvas-overview .content-view.canvas > footer > .view-related-items > :matches(.view-shader, .view-recording) {
     width: 16px;
-    margin-top: 3px;
-    -webkit-padding-end: 4px;
-    content: url(../Images/Recording.svg);
+    height: 16px;
 }
 
-.content-view.canvas-overview .content-view.canvas > footer > .recordings > select {
-    position: absolute;
-    top: 0;
-    right: 0;
-    bottom: 0;
-    left: 0;
-    margin: 0;
-    padding: 0;
-    border: none;
-    opacity: 0;
-    -webkit-appearance: none;
+.content-view.canvas-overview .content-view.canvas > footer > .view-related-items > img + img {
+    -webkit-margin-start: 4px;
 }
 
-.content-view.canvas-overview .content-view.canvas > footer .recordings > select:focus {
-    -webkit-margin-start: 11px;
+.content-view.canvas-overview .content-view.canvas > footer > .view-related-items > .view-shader {
+    content: image-set(url(../Images/DocumentGL.png) 1x, url(../Images/DocumentGL@2x.png) 2x);
+}
+
+.content-view.canvas-overview .content-view.canvas > footer > .view-related-items > .view-recording {
+    content: url(../Images/Recording.svg);
 }
 
 .content-view.canvas-overview .content-view.canvas > footer > .flexible-space {
index 75c30b5..784b7c1 100644 (file)
@@ -260,7 +260,10 @@ WI.CanvasSidebarPanel = class CanvasSidebarPanel extends WI.NavigationSidebarPan
 
         let recording = objects.find((object) => object instanceof WI.Recording);
         if (recording) {
-            recording[WI.CanvasSidebarPanel.SelectedActionSymbol] = objects.find((object) => object instanceof WI.RecordingAction);
+            let recordingAction = objects.find((object) => object instanceof WI.RecordingAction);
+            if (recordingAction !== recording[WI.CanvasSidebarPanel.SelectedActionSymbol])
+                this.action = recordingAction;
+
             this.recording = recording;
             return;
         }
@@ -342,6 +345,8 @@ WI.CanvasSidebarPanel = class CanvasSidebarPanel extends WI.NavigationSidebarPan
             if (recording !== this._recording || promise !== this._recordingProcessPromise)
                 return;
 
+            this._recordingProcessPromise = null;
+
             if (this._recordingProcessSpinner) {
                 this._recordingProcessSpinner.element.remove();
                 this._recordingProcessSpinner = null;
@@ -381,8 +386,6 @@ WI.CanvasSidebarPanel = class CanvasSidebarPanel extends WI.NavigationSidebarPan
             }
 
             this.action = this._recording[WI.CanvasSidebarPanel.SelectedActionSymbol] || this._recording.actions[0];
-
-            this._recordingProcessPromise = null;
         });
 
         this._recordingProcessPromise = promise;