source: EcnlProtoTool/trunk/webapp/webmrbc/Variables.cs@ 425

Last change on this file since 425 was 425, checked in by coas-nagasima, 4 years ago

Visual Studio 2019 と Bridge.NET でビルドできるよう更新。

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csharp;charset=UTF-8
File size: 9.9 KB
Line 
1/**
2 * @license
3 * Visual Blocks Editor
4 *
5 * Copyright 2012 Google Inc.
6 * https://developers.google.com/blockly/
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 */
20
21/**
22 * @fileoverview Utility functions for handling variables.
23 * @author fraser@google.com (Neil Fraser)
24 */
25using System;
26using System.Collections.Generic;
27using System.Runtime.InteropServices;
28using Bridge;
29using Bridge.Html5;
30using WebMrbc;
31
32namespace WebMrbc
33{
34 public class Variables
35 {
36 /// <summary>
37 /// Category to separate variable names from procedures and generated functions.
38 /// </summary>
39 public string NAME_TYPE = "VARIABLE";
40
41 /// <summary>
42 /// Common HSV hue for all blocks in this category.
43 /// </summary>
44 public int HUE = 330;
45
46 /// <summary>
47 /// Find all user-created variables that are in use in the workspace.
48 /// For use by generators.
49 /// </summary>
50 /// <param name="root">Root block or workspace.</param>
51 /// <returns>Array of variable names.</returns>
52 public string[] allUsedVariables(Union<Block, Workspace> root)
53 {
54 Block[] blocks;
55 if (Script.Write<bool>("root instanceof Blockly.Block")) {
56 // Root is Block.
57 blocks = ((Block)root).getDescendants();
58 }
59 else if (Script.Write<bool>("root instanceof Blockly.Workspace")) {
60 // Root is Workspace.
61 blocks = ((Workspace)root).getAllBlocks();
62 }
63 else {
64 throw new Exception("Not Block or Workspace: " + root);
65 }
66 var variableHash = new Dictionary<string, string>();
67 // Iterate through every block and add each variable to the hash.
68 for (var x = 0; x < blocks.Length; x++) {
69 var blockVariables = blocks[x].getVars();
70 if (blockVariables != null) {
71 for (var y = 0; y < blockVariables.Length; y++) {
72 var varName = blockVariables[y];
73 // Variable name may be null if the block is only half-built.
74 if (varName != null) {
75 variableHash[varName.ToLower()] = varName;
76 }
77 }
78 }
79 }
80 // Flatten the hash into a list.
81 var variableList = new string[0];
82 foreach (var name in variableHash.Keys) {
83 variableList.Push(variableHash[name]);
84 }
85 return variableList;
86 }
87
88 /// <summary>
89 /// Find all variables that the user has created through the workspace or
90 /// toolbox. For use by generators.
91 /// </summary>
92 /// <param name="root">The workspace to inspect.</param>
93 /// <returns>Array of variable names.</returns>
94 public string[] allVariables(Workspace root)
95 {
96 if (Script.Write<bool>("root instanceof Blockly.Block")) {
97 // Root is Block.
98 App.WriteLine("Deprecated call to Variables.allVariables " +
99 "with a block instead of a workspace. You may want " +
100 "Variables.allUsedVariables");
101 }
102 return root.variableList;
103 }
104
105 /// <summary>
106 /// Construct the blocks required by the flyout for the variable category.
107 /// </summary>
108 /// <param name="workspace">The workspace contianing variables.</param>
109 /// <returns>Array of XML block elements.</returns>
110 public Element[] flyoutCategory(Workspace workspace)
111 {
112 var variableList = workspace.variableList;
113 Array.Sort(variableList, goog.@string.caseInsensitiveCompare);
114
115 var xmlList = new Element[0];
116 var button = goog.dom.createDom("button");
117 button.SetAttribute("text", Msg.NEW_VARIABLE);
118 button.SetAttribute("callbackKey", "CREATE_VARIABLE");
119
120 Blockly.registerButtonCallback("CREATE_VARIABLE", (btn) => {
121 createVariable(btn.getTargetWorkspace());
122 });
123
124 xmlList.Push(button);
125
126 if (variableList.Length > 0) {
127 if (Script.Get(Blockly.Blocks, "variables_set") != null) {
128 // <block type="variables_set" gap="20">
129 // <field name="VAR">item</field>
130 // </block>
131 var block = goog.dom.createDom("block");
132 block.SetAttribute("type", "variables_set");
133 if (Script.Get(Blockly.Blocks, "math_change") != null) {
134 block.SetAttribute("gap", "8");
135 }
136 else {
137 block.SetAttribute("gap", "24");
138 }
139 var field = goog.dom.createDom("field", null, variableList[0]);
140 field.SetAttribute("name", "VAR");
141 block.AppendChild(field);
142 xmlList.Push(block);
143 }
144 if (Script.Get(Blockly.Blocks, "math_change") != null) {
145 // <block type="math_change">
146 // <value name="DELTA">
147 // <shadow type="math_number">
148 // <field name="NUM">1</field>
149 // </shadow>
150 // </value>
151 // </block>
152 var block = goog.dom.createDom("block");
153 block.SetAttribute("type", "math_change");
154 if (Script.Get(Blockly.Blocks, "variables_get") != null) {
155 block.SetAttribute("gap", "20");
156 }
157 var value = goog.dom.createDom("value");
158 value.SetAttribute("name", "DELTA");
159 block.AppendChild(value);
160
161 var field = goog.dom.createDom("field", null, variableList[0]);
162 field.SetAttribute("name", "VAR");
163 block.AppendChild(field);
164
165 var shadowBlock = goog.dom.createDom("shadow");
166 shadowBlock.SetAttribute("type", "math_number");
167 value.AppendChild(shadowBlock);
168
169 var numberField = goog.dom.createDom("field", null, "1");
170 numberField.SetAttribute("name", "NUM");
171 shadowBlock.AppendChild(numberField);
172
173 xmlList.Push(block);
174 }
175
176 for (var i = 0; i < variableList.Length; i++) {
177 if (Script.Get(Blockly.Blocks, "variables_get") != null) {
178 // <block type="variables_get" gap="8">
179 // <field name="VAR">item</field>
180 // </block>
181 var block = goog.dom.createDom("block");
182 block.SetAttribute("type", "variables_get");
183 if (Script.Get(Blockly.Blocks, "variables_set") != null) {
184 block.SetAttribute("gap", "8");
185 }
186 var field = goog.dom.createDom("field", null, variableList[i]);
187 field.SetAttribute("name", "VAR");
188 block.AppendChild(field);
189 xmlList.Push(block);
190 }
191 }
192 }
193 return xmlList;
194 }
195
196 /// <summary>
197 /// Return a new variable name that is not yet being used. This will try to
198 /// generate single letter variable names in the range 'i' to 'z' to start with.
199 /// If no unique name is located it will try 'i' to 'z', 'a' to 'h',
200 /// then 'i2' to 'z2' etc. Skip 'l'.
201 /// </summary>
202 /// <param name="workspace">The workspace to be unique in.</param>
203 /// <returns>New variable name.</returns>
204 public string generateUniqueName(Workspace workspace)
205 {
206 var variableList = workspace.variableList;
207 var newName = "";
208 if (variableList.Length != 0) {
209 var nameSuffix = 1;
210 var letters = "ijkmnopqrstuvwxyzabcdefgh"; // No 'l'.
211 var letterIndex = 0;
212 var potName = letters.CharAt(letterIndex);
213 while (String.IsNullOrEmpty(newName)) {
214 var inUse = false;
215 for (var i = 0; i < variableList.Length; i++) {
216 if (variableList[i].ToLower() == potName) {
217 // This potential name is already used.
218 inUse = true;
219 break;
220 }
221 }
222 if (inUse) {
223 // Try the next potential name.
224 letterIndex++;
225 if (letterIndex == letters.Length) {
226 // Reached the end of the character sequence so back to 'i'.
227 // a new suffix.
228 letterIndex = 0;
229 nameSuffix++;
230 }
231 potName = letters.CharAt(letterIndex);
232 if (nameSuffix > 1) {
233 potName += nameSuffix;
234 }
235 }
236 else {
237 // We can use the current potential name.
238 newName = potName;
239 }
240 }
241 }
242 else {
243 newName = "i";
244 }
245 return newName;
246 }
247
248 /// <summary>
249 /// Create a new variable on the given workspace.
250 /// </summary>
251 /// <param name="workspace">The workspace on which to create the variable.</param>
252 /// <param name="opt_callback">A callback. It will
253 /// return an acceptable new variable name, or null if change is to be
254 /// aborted (cancel button), or undefined if an existing variable was chosen.</param>
255 public void createVariable(Workspace workspace, Func<string, object> opt_callback = null)
256 {
257 Action<string> promptAndCheckWithAlert = null;
258 promptAndCheckWithAlert = new Action<string>((defaultName) => {
259 promptName(Msg.NEW_VARIABLE_TITLE, defaultName,
260 (text) => {
261 if (text != null) {
262 if (workspace.variableIndexOf(text) != -1) {
263 Blockly.alert(Msg.VARIABLE_ALREADY_EXISTS.Replace("%1",
264 text.ToLower()),
265 () => {
266 promptAndCheckWithAlert(text); // Recurse
267 });
268 }
269 else {
270 workspace.createVariable(text);
271 if (opt_callback != null) {
272 opt_callback(text);
273 }
274 }
275 }
276 else {
277 // User canceled prompt without a value.
278 if (opt_callback != null) {
279 opt_callback(null);
280 }
281 }
282 });
283 });
284 promptAndCheckWithAlert("");
285 }
286
287 /// <summary>
288 /// Prompt the user for a new variable name.
289 /// </summary>
290 /// <param name="promptText">The string of the prompt.</param>
291 /// <param name="defaultText">The default value to show in the prompt's field.</param>
292 /// <param name="callback">A callback. It will return the new
293 /// variable name, or null if the user picked something illegal.</param>
294 public void promptName(string promptText, string defaultText, Action<string> callback)
295 {
296 Blockly.prompt(promptText, defaultText, new Action<string>((newVar) => {
297 // Merge runs of whitespace. Strip leading and trailing whitespace.
298 // Beyond this, all names are legal.
299 if (newVar != null) {
300 newVar = newVar.Replace(new RegExp(@"[\s\xa0] +"), " ").Replace(new RegExp("^ | $"), "");
301 if (newVar == Msg.RENAME_VARIABLE ||
302 newVar == Msg.NEW_VARIABLE) {
303 // Ok, not ALL names are legal...
304 newVar = null;
305 }
306 }
307 callback(newVar);
308 }));
309 }
310 }
311}
Note: See TracBrowser for help on using the repository browser.