dd9254ed5bee00856e232a52ff0b72d5b9234384
[WebKit-https.git] / Source / WebInspectorUI / UserInterface / Views / ShaderProgramContentView.js
1 /*
2  * Copyright (C) 2017 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
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.
12  *
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.
24  */
25
26 WI.ShaderProgramContentView = class ShaderProgramContentView extends WI.ContentView
27 {
28     constructor(shaderProgram)
29     {
30         console.assert(shaderProgram instanceof WI.ShaderProgram);
31
32         super(shaderProgram);
33
34         let contentDidChangeDebouncer = new Debouncer((event) => {
35             this._contentDidChange(event);
36         });
37
38         this.element.classList.add("shader-program");
39
40         let createEditor = (shaderType) => {
41             let textEditor = new WI.TextEditor;
42             textEditor.readOnly = false;
43             textEditor.addEventListener(WI.TextEditor.Event.Focused, this._editorFocused, this);
44             textEditor.addEventListener(WI.TextEditor.Event.NumberOfSearchResultsDidChange, this._numberOfSearchResultsDidChange, this);
45             textEditor.addEventListener(WI.TextEditor.Event.ContentDidChange, (event) => {
46                 contentDidChangeDebouncer.delayForTime(250, event);
47             }, this);
48             textEditor.element.classList.add("shader");
49
50             let shaderTypeContainer = textEditor.element.insertAdjacentElement("afterbegin", document.createElement("div"));
51             shaderTypeContainer.classList.add("type-title");
52
53             switch (shaderType) {
54             case WI.ShaderProgram.ShaderType.Vertex:
55                 shaderTypeContainer.textContent = WI.UIString("Vertex Shader");
56                 textEditor.mimeType = "x-shader/x-vertex";
57                 textEditor.element.classList.add("vertex");
58                 break;
59
60             case WI.ShaderProgram.ShaderType.Fragment:
61                 shaderTypeContainer.textContent = WI.UIString("Fragment Shader");
62                 textEditor.mimeType = "x-shader/x-fragment";
63                 textEditor.element.classList.add("fragment");
64                 break;
65             }
66
67             this.addSubview(textEditor);
68             return textEditor;
69         };
70
71         this._vertexEditor = createEditor(WI.ShaderProgram.ShaderType.Vertex);
72         this._fragmentEditor = createEditor(WI.ShaderProgram.ShaderType.Fragment);
73         this._lastActiveEditor = this._vertexEditor;
74     }
75
76     // Protected
77
78     shown()
79     {
80         super.shown();
81
82         this._vertexEditor.shown();
83         this._fragmentEditor.shown();
84
85         this.representedObject.requestVertexShaderSource((content) => {
86             this._vertexEditor.string = content || "";
87         });
88
89         this.representedObject.requestFragmentShaderSource((content) => {
90             this._fragmentEditor.string = content || "";
91         });
92     }
93
94     hidden()
95     {
96         this._vertexEditor.hidden();
97         this._fragmentEditor.hidden();
98
99         super.hidden();
100     }
101
102     get supportsSave()
103     {
104         return true;
105     }
106
107     get saveData()
108     {
109         let filename = WI.UIString("Shader");
110         if (this._lastActiveEditor === this._vertexEditor)
111             filename = WI.UIString("Vertex");
112         else if (this._lastActiveEditor === this._fragmentEditor)
113             filename = WI.UIString("Fragment");
114
115         return {
116             url: WI.FileUtilities.inspectorURLForFilename(filename + ".glsl"),
117             content: this._lastActiveEditor.string,
118             forceSaveAs: true,
119         };
120     }
121
122     get supportsSearch()
123     {
124         return true;
125     }
126
127     get numberOfSearchResults()
128     {
129         return this._lastActiveEditor.numberOfSearchResults;
130     }
131
132     get hasPerformedSearch()
133     {
134         return this._lastActiveEditor.currentSearchQuery !== null;
135     }
136
137     set automaticallyRevealFirstSearchResult(reveal)
138     {
139         this._lastActiveEditor.automaticallyRevealFirstSearchResult = reveal;
140     }
141
142     performSearch(query)
143     {
144         this._lastActiveEditor.performSearch(query);
145     }
146
147     searchCleared()
148     {
149         this._lastActiveEditor.searchCleared();
150     }
151
152     searchQueryWithSelection()
153     {
154         return this._lastActiveEditor.searchQueryWithSelection();
155     }
156
157     revealPreviousSearchResult(changeFocus)
158     {
159         this._lastActiveEditor.revealPreviousSearchResult(changeFocus);
160     }
161
162     revealNextSearchResult(changeFocus)
163     {
164         this._lastActiveEditor.revealNextSearchResult(changeFocus);
165     }
166
167     revealPosition(position, textRangeToSelect, forceUnformatted)
168     {
169         this._lastActiveEditor.revealPosition(position, textRangeToSelect, forceUnformatted);
170     }
171
172     // Private
173
174     _editorFocused(event)
175     {
176         if (this._lastActiveEditor === event.target)
177             return;
178
179         let currentSearchQuery = null;
180
181         if (this._lastActiveEditor) {
182             currentSearchQuery = this._lastActiveEditor.currentSearchQuery;
183
184             this._lastActiveEditor.searchCleared();
185         }
186
187         this._lastActiveEditor = event.target;
188
189         if (currentSearchQuery)
190             this._lastActiveEditor.performSearch(currentSearchQuery);
191     }
192
193     _numberOfSearchResultsDidChange(event)
194     {
195         this.dispatchEventToListeners(WI.ContentView.Event.NumberOfSearchResultsDidChange);
196     }
197
198     _contentDidChange(event)
199     {
200         if (event.target === this._vertexEditor)
201             this.representedObject.updateVertexShader(this._vertexEditor.string);
202         else if (event.target === this._fragmentEditor)
203             this.representedObject.updateFragmentShader(this._fragmentEditor.string);
204     }
205 };