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

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

mruby版ECNLプロトタイピング・ツールを追加

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