2 * Copyright (C) 2017 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
26 WI.ShaderProgramContentView = class ShaderProgramContentView extends WI.ContentView
28 constructor(shaderProgram)
30 console.assert(shaderProgram instanceof WI.ShaderProgram);
34 let isWebGPU = this.representedObject.contextType === WI.Canvas.ContextType.WebGPU;
36 this._refreshButtonNavigationItem = new WI.ButtonNavigationItem("refresh", WI.UIString("Refresh"), "Images/ReloadFull.svg", 13, 13);
37 this._refreshButtonNavigationItem.visibilityPriority = WI.NavigationItem.VisibilityPriority.Low;
38 this._refreshButtonNavigationItem.addEventListener(WI.ButtonNavigationItem.Event.Clicked, this._refreshContent, this);
40 let contentDidChangeDebouncer = new Debouncer((event) => {
41 this._contentDidChange(event);
44 this.element.classList.add("shader-program", this.representedObject.programType);
46 let createEditor = (shaderType) => {
47 let container = this.element.appendChild(document.createElement("div"));
49 let header = container.appendChild(document.createElement("header"));
51 let shaderTypeContainer = header.appendChild(document.createElement("div"));
52 shaderTypeContainer.classList.add("shader-type");
54 let textEditor = new WI.TextEditor;
55 textEditor.readOnly = false;
56 textEditor.addEventListener(WI.TextEditor.Event.Focused, this._editorFocused, this);
57 textEditor.addEventListener(WI.TextEditor.Event.NumberOfSearchResultsDidChange, this._numberOfSearchResultsDidChange, this);
58 textEditor.addEventListener(WI.TextEditor.Event.ContentDidChange, (event) => {
59 contentDidChangeDebouncer.delayForTime(250, event);
63 case WI.ShaderProgram.ShaderType.Compute:
64 shaderTypeContainer.textContent = WI.UIString("Compute Shader");
65 textEditor.mimeType = isWebGPU ? "x-pipeline/x-compute" : "x-shader/x-compute";
68 case WI.ShaderProgram.ShaderType.Fragment:
69 shaderTypeContainer.textContent = WI.UIString("Fragment Shader");
70 textEditor.mimeType = isWebGPU ? "x-pipeline/x-fragment" : "x-shader/x-fragment";
73 case WI.ShaderProgram.ShaderType.Vertex:
74 shaderTypeContainer.textContent = WI.UIString("Vertex Shader");
75 textEditor.mimeType = isWebGPU ? "x-pipeline/x-vertex" : "x-shader/x-vertex";
79 this.addSubview(textEditor);
80 container.appendChild(textEditor.element);
81 container.classList.add("shader", shaderType);
83 return {container, textEditor};
86 switch (this.representedObject.programType) {
87 case WI.ShaderProgram.ProgramType.Compute: {
88 let computeEditor = createEditor(WI.ShaderProgram.ShaderType.Compute);
89 this._computeContainer = computeEditor.container;
90 this._computeEditor = computeEditor.textEditor;
92 this._lastActiveEditor = this._computeEditor;
96 case WI.ShaderProgram.ProgramType.Render: {
97 let vertexEditor = createEditor(WI.ShaderProgram.ShaderType.Vertex);
98 this._vertexContainer = vertexEditor.container;
99 this._vertexEditor = vertexEditor.textEditor;
101 let fragmentEditor = createEditor(WI.ShaderProgram.ShaderType.Fragment);
102 this._fragmentContainer = fragmentEditor.container;
103 this._fragmentEditor = fragmentEditor.textEditor;
105 this._lastActiveEditor = this._vertexEditor;
113 get navigationItems()
115 return [this._refreshButtonNavigationItem];
124 switch (this.representedObject.programType) {
125 case WI.ShaderProgram.ProgramType.Compute:
126 this._computeEditor.shown();
129 case WI.ShaderProgram.ProgramType.Render:
130 this._vertexEditor.shown();
131 this._fragmentEditor.shown();
135 this._refreshContent();
140 switch (this.representedObject.programType) {
141 case WI.ShaderProgram.ProgramType.Compute:
142 this._computeEditor.hidden();
145 case WI.ShaderProgram.ProgramType.Render:
146 this._vertexEditor.hidden();
147 this._fragmentEditor.hidden();
162 switch (this._lastActiveEditor) {
163 case this._computeEditor:
164 filename = WI.UIString("Compute");
166 case this._fragmentEditor:
167 filename = WI.UIString("Fragment");
169 case this._vertexEditor:
170 filename = WI.UIString("Vertex");
173 console.assert(filename);
176 switch (this.representedObject.canvas.contextType) {
177 case WI.Canvas.ContextType.WebGL:
178 case WI.Canvas.ContextType.WebGL2:
179 extension = WI.unlocalizedString(".glsl");
181 case WI.Canvas.ContextType.WebGPU:
182 extension = WI.unlocalizedString(".wsl");
185 console.assert(extension);
188 url: WI.FileUtilities.inspectorURLForFilename(filename + extension),
189 content: this._lastActiveEditor.string,
199 get numberOfSearchResults()
201 return this._lastActiveEditor.numberOfSearchResults;
204 get hasPerformedSearch()
206 return this._lastActiveEditor.currentSearchQuery !== null;
209 set automaticallyRevealFirstSearchResult(reveal)
211 this._lastActiveEditor.automaticallyRevealFirstSearchResult = reveal;
216 this._lastActiveEditor.performSearch(query);
221 this._lastActiveEditor.searchCleared();
224 searchQueryWithSelection()
226 return this._lastActiveEditor.searchQueryWithSelection();
229 revealPreviousSearchResult(changeFocus)
231 this._lastActiveEditor.revealPreviousSearchResult(changeFocus);
234 revealNextSearchResult(changeFocus)
236 this._lastActiveEditor.revealNextSearchResult(changeFocus);
239 revealPosition(position, textRangeToSelect, forceUnformatted)
241 this._lastActiveEditor.revealPosition(position, textRangeToSelect, forceUnformatted);
248 let createCallback = (container, textEditor) => {
249 return (source, entryPoint) => {
250 if (source === null) {
255 if (!container.parentNode) {
257 case this._computeContainer:
258 case this._vertexContainer:
259 this.element.insertAdjacentElement("afterbegin", container);
262 case this._fragmentContainer:
263 this.element.insertAdjacentElement("beforeend", container);
268 textEditor.string = source || "";
272 switch (this.representedObject.programType) {
273 case WI.ShaderProgram.ProgramType.Compute:
274 this.representedObject.requestShaderSource(WI.ShaderProgram.ShaderType.Compute, createCallback(this._computeContainer, this._computeEditor));
277 case WI.ShaderProgram.ProgramType.Render:
278 this.representedObject.requestShaderSource(WI.ShaderProgram.ShaderType.Vertex, createCallback(this._vertexContainer, this._vertexEditor));
279 this.representedObject.requestShaderSource(WI.ShaderProgram.ShaderType.Fragment, createCallback(this._fragmentContainer, this._fragmentEditor));
286 _updateShader(shaderType)
288 switch (shaderType) {
289 case WI.ShaderProgram.ShaderType.Compute:
290 this.representedObject.updateShader(shaderType, this._computeEditor.string);
293 case WI.ShaderProgram.ShaderType.Fragment:
294 this.representedObject.updateShader(shaderType, this._fragmentEditor.string);
297 case WI.ShaderProgram.ShaderType.Vertex:
298 this.representedObject.updateShader(shaderType, this._vertexEditor.string);
305 _editorFocused(event)
307 if (this._lastActiveEditor === event.target)
310 let currentSearchQuery = null;
312 if (this._lastActiveEditor) {
313 currentSearchQuery = this._lastActiveEditor.currentSearchQuery;
315 this._lastActiveEditor.searchCleared();
318 this._lastActiveEditor = event.target;
320 if (currentSearchQuery)
321 this._lastActiveEditor.performSearch(currentSearchQuery);
324 _numberOfSearchResultsDidChange(event)
326 this.dispatchEventToListeners(WI.ContentView.Event.NumberOfSearchResultsDidChange);
329 _contentDidChange(event)
331 switch (event.target) {
332 case this._computeEditor:
333 this._updateShader(WI.ShaderProgram.ShaderType.Compute);
336 case this._fragmentEditor:
337 this._updateShader(WI.ShaderProgram.ShaderType.Fragment);
340 case this._vertexEditor:
341 this._updateShader(WI.ShaderProgram.ShaderType.Vertex);