Arma Reforger Explorer 1.7.0.54
Arma Reforger Code Explorer by Zeroy - Thanks to MisterOutofTime
Loading...
Searching...
No Matches
SCR_GenerateLayoutClassPlugin.c
Go to the documentation of this file.
1#ifdef WORKBENCH
4[WorkbenchPluginAttribute(name: PLUGIN_NAME, wbModules: { "ResourceManager" }, awesomeFontCode: 0xF0DB)]
5class SCR_GenerateLayoutClassPlugin : WorkbenchPlugin
6{
7 protected static const string PLUGIN_VERSION = "0.5.1"; // plugin version, printed in the generated file
8 protected static const string PLUGIN_NAME = "Generate Class from Layout";
9 protected static const string DIALOG_CAPTION = PLUGIN_NAME + " [v" + PLUGIN_VERSION + "]";
10 protected static const string INTRO_TEXT = "This plugin autogenerates widget-binding scripts for .layout files.\n\n";
11
12 //------------------------------------------------------------------------------------------------
13 override void Run()
14 {
15 _print("Run()");
16
17 BaseContainer widgetSource = Workbench.GetModule(ResourceManager).GetContainer();
18 if (!widgetSource) // bail if we are not in layout editor
19 {
20 Workbench.Dialog(DIALOG_CAPTION, INTRO_TEXT + "You need to open a .layout file first!");
21 return;
22 }
23
24 BaseContainer exportRule = SCR_WidgetExportRuleRoot.FindInWidgetSource(widgetSource);
25 if (!exportRule) // bail if SCR_WidgetExportRuleRoot was not found
26 {
27 Workbench.Dialog(DIALOG_CAPTION, INTRO_TEXT + "You need to attach a SCR_WidgetExportRuleRoot component to root widget of your layout!");
28 return;
29 }
30
31 string layoutPath = widgetSource.GetName();
32 string scriptClassName = GenerateScriptClassName(layoutPath, exportRule);
33 string destinationPath = ResolveDestinationPath(scriptClassName + ".c");
34 string dialogText = INTRO_TEXT +
35 "The generator only exports widgets and their components if the widget name starts with 'm_'.\n" +
36 "Attach SCR_WidgetExportRule component to a widget to alter its export rules.\n\n" +
37 "- - - - - - - - - - - - - - - - - - - - \n\n" +
38 string.Format("Generated script class name:\n%1\n\n", scriptClassName) +
39 string.Format("Destination file path:\n%1\n\n", destinationPath) +
40 string.Format("WARNING: The destination file will be overwritten if it already exists! (file exists: %1)", FileIO.FileExists(destinationPath).ToString());
41
42 if (!Workbench.ScriptDialog(DIALOG_CAPTION, dialogText, this))
43 return;
44
45 Generate(widgetSource, exportRule, scriptClassName, destinationPath);
46 }
47
48 //------------------------------------------------------------------------------------------------
54 protected void Generate(notnull BaseContainer widgetSource, notnull BaseContainer exportRule, string scriptClassName, string destinationPath)
55 {
56 // build array of all elements we are going to generate code for
57 array<BaseContainer> widgets = {};
58 array<ref array<BaseContainer>> paths = {};
59 BuildWidgetArray(widgetSource, {}, widgets, paths);
60
61 // generate the output class name
62 string layoutPath = widgetSource.GetName();
63 _print(string.Format("Layout path: %1", layoutPath));
64 _print(string.Format("Script class name: %1", scriptClassName));
65
66 // strings with generated sections
67 string variablesDeclaration; // Type m_wMyWidget;
68 string variablesBinding; // m_wMyWidget = Type.Cast(root.Find...)
69
70 // generate the code
71 _print("Iterating widgets...");
72 bool generateFullWidgetPath = SCR_WidgetExportRuleRoot.GetGenerateFullWidgetPath(exportRule);
73 array<BaseContainer> pathToThisWidget;
74 array<BaseContainer> components;
75 foreach (int widgetId, BaseContainer thisWidget : widgets)
76 {
77 pathToThisWidget = paths[widgetId];
78
79 string wName = GetWidgetName(thisWidget);
80
81 // issue a warning if widget name is not correct
82 if (!IsWidgetExportRequired(thisWidget, pathToThisWidget))
83 continue;
84
85 if (!ValidateWidget(thisWidget))
86 continue;
87
88 components = ResolveWidgetComponentsForExport(thisWidget);
89 int componentsCount = components.Count();
90
91 if (componentsCount > 0 && !variablesDeclaration.IsEmpty())
92 {
93 variablesDeclaration += "\n";
94 variablesBinding += "\n";
95 }
96
97 string widgetVariableName = ResolveWidgetVariableName(thisWidget);
98 if (!widgetVariableName.StartsWith("m_w"))
99 {
100 if (widgetVariableName.StartsWith("m_"))
101 widgetVariableName = SCR_StringHelper.InsertAt(widgetVariableName, "w", 2);
102 else
103 widgetVariableName = "m_w" + widgetVariableName;
104 }
105
106 string pathToThisWidgetStr = GetStringPathToWidget(pathToThisWidget);
107
108 _print(string.Format("Exporting widget: %1, %2, %3", wName, widgetVariableName, pathToThisWidgetStr));
109
110 // declare variable for this widget
111 string wClassName = thisWidget.GetClassName();
112 wClassName = wClassName.Substring(0, wClassName.Length() - 5); // remove "Class" from the end
113 variablesDeclaration += string.Format("\t%1 %2;\n", wClassName, widgetVariableName);
114
115 // perform variable binding for this widget
116 if (generateFullWidgetPath)
117 variablesBinding += string.Format("\t\t%1 = %2.Cast(root.FindWidget(\"%3\"));\n", widgetVariableName, wClassName, pathToThisWidgetStr);
118 else
119 variablesBinding += string.Format("\t\t%1 = %2.Cast(root.FindAnyWidget(\"%3\"));\n", widgetVariableName, wClassName, GetWidgetName(thisWidget));
120
121 if (componentsCount < 1) // no components in this one, next
122 continue;
123
124 string noMWPrefixWidgetVariableName = SCR_StringHelper.ReplaceTimes(widgetVariableName, "m_w", "m_", 1);
125
126 // declare variables for widget components
127 foreach (int i, BaseContainer comp : components)
128 {
129 string compClassName = comp.GetClassName();
130 string compVarName;
131
132 if (componentsCount == 1)
133 compVarName = string.Format("%1Component", noMWPrefixWidgetVariableName);
134 else
135 compVarName = string.Format("%1Component%2", noMWPrefixWidgetVariableName, i);
136
137 variablesDeclaration += string.Format("\t%1 %2;\n", compClassName, compVarName);
138
139 // variable binding for component
140 variablesBinding += string.Format("\t\t%1 = %2.Cast(%3.FindHandler(%4));\n", compVarName, compClassName, widgetVariableName, compClassName);
141 }
142
143 variablesDeclaration += "\n";
144 variablesBinding += "\n";
145 }
146
147 // generate whole code
148 string gc =
149 string.Format("/" + "/ Autogenerated by the Generate Class from Layout plugin v%1\n", PLUGIN_VERSION) +
150 string.Format("/" + "/ Layout file: %1\n", layoutPath) +
151 string.Format("class %1\n{\n", scriptClassName) + // class declaration and opening
152 string.Format("\tprotected static const ResourceName LAYOUT = \"%1\";\n\n", widgetSource.GetResourceName()) + // constant with layout path
153 variablesDeclaration + "\n" + // class variablesBinding
154 "\t//------------------------------------------------------------------------------------------------\n" +
155 "\tbool Init(notnull Widget root)\n\t{\n" + // variable binding
156 variablesBinding + "\n" +
157 "\t\treturn true;\n\t}\n\n" +
158 "\t//------------------------------------------------------------------------------------------------\n" +
159 "\tResourceName GetLayout()\n\t{\n\t\t" + "return LAYOUT;\n\t}\n" +
160 "}\n"; // close class
161
162 // save everything to file
163 string fileOutPath = destinationPath;
164
165 _print(string.Format("Exporting to file: %1", fileOutPath));
166 FileHandle fileHandle = FileIO.OpenFile(fileOutPath, FileMode.WRITE);
167 if (!fileHandle)
168 {
169 _print("Error opening file!");
170 return;
171 }
172
173 fileHandle.Write(gc);
174 fileHandle.Close();
175 _print("Export finished!");
176
177 ScriptEditor scriptEditor = Workbench.GetModule(ScriptEditor);
178 if (scriptEditor)
179 scriptEditor.SetOpenedResource(fileOutPath);
180 }
181
182 // ---------------- Misc functions ---------------
183
184 //------------------------------------------------------------------------------------------------
186 protected bool IsWidgetExportRequired(notnull BaseContainer ws, notnull array<BaseContainer> path)
187 {
188 // check if any widgets in the path explicitly disables export
189 // ignore the last widget (this widget), even if its child widgets are not exported,
190 // it still can be exported
191
192 BaseContainer rule;
193 foreach (BaseContainer pathWs : path)
194 {
195 rule = SCR_WidgetExportRule.FindInWidgetSource(pathWs);
196 if (rule)
197 {
198 bool exportChildren = SCR_WidgetExportRule.GetExportChildWidgets(rule);
199 if (!exportChildren)
200 return false;
201 }
202 }
203
204 // check widget properties
205
206 rule = SCR_WidgetExportRule.FindInWidgetSource(ws);
207 if (rule) // widget name matches pattern, no rule provided - default behaviour
208 return SCR_WidgetExportRule.GetExportThisWidget(rule);
209
210 return GetWidgetName(ws).StartsWith("m_");
211 }
212
213 //------------------------------------------------------------------------------------------------
215 protected string ResolveWidgetVariableName(BaseContainer ws)
216 {
217 BaseContainer rule = SCR_WidgetExportRule.FindInWidgetSource(ws);
218 string wName = GetWidgetName(ws);
219
220 if (!rule)
221 return wName; // no rule, default behaviour - same as widget name
222
223 string wNameFromRule = SCR_WidgetExportRule.GetWidgetVariableName(rule);
224 if (wNameFromRule.IsEmpty())
225 return wName;
226
227 return wNameFromRule;
228 }
229
230 //------------------------------------------------------------------------------------------------
233 protected bool ValidateWidget(BaseContainer ws)
234 {
235 string wName = GetWidgetName(ws);
236 if (wName.Contains(" "))
237 {
238 _print(string.Format("Widget name contains space: %1", wName), LogLevel.ERROR);
239 return false;
240 }
241
242 BaseContainer rule = SCR_WidgetExportRule.FindInWidgetSource(ws);
243 if (!rule)
244 return true;
245
246 string wNameFromRule = SCR_WidgetExportRule.GetWidgetVariableName(rule);
247 if (!wNameFromRule.IsEmpty() && wNameFromRule.Contains(" "))
248 {
249 _print(string.Format("Widget name in the export rule contains space: %1, widget: %2", wNameFromRule, wName), LogLevel.ERROR);
250 return false;
251 }
252
253 return true;
254 }
255
256 //------------------------------------------------------------------------------------------------
258 protected array<BaseContainer> ResolveWidgetComponentsForExport(WidgetSource ws)
259 {
260 BaseContainerList components = ws.GetObjectArray("components");
261 array<BaseContainer> outArray = {};
262 BaseContainer comp;
263 typename compTypename;
264 for (int i, count = components.Count(); i < count; i++)
265 {
266 comp = components.Get(i);
267 compTypename = comp.GetClassName().ToType();
268
269 // we do not want to export this one obviously
270 if (!compTypename || (!compTypename.IsInherited(SCR_WidgetExportRule) && !compTypename.IsInherited(SCR_WidgetExportRuleRoot)))
271 outArray.Insert(comp);
272 }
273
274 return outArray;
275 }
276
277 //------------------------------------------------------------------------------------------------
279 protected string GenerateScriptClassName(string path, notnull BaseContainer exportRule)
280 {
281 int slashId = path.LastIndexOf("/");
282 int dotId = path.LastIndexOf(".");
283 int cutSize = dotId - slashId - 1;
284 string fileNameNoPathNoExt = path.Substring(slashId + 1, cutSize);
285
286 string prefix, suffix;
287 SCR_WidgetExportRuleRoot.GetClassPrefixAndSuffix(exportRule, prefix, suffix);
288
289 return string.Format("%1%2%3", prefix, fileNameNoPathNoExt, suffix);
290 }
291
292 //------------------------------------------------------------------------------------------------
298 protected static void BuildWidgetArray(
299 notnull BaseContainer ws,
300 notnull array<BaseContainer> pathToThis,
301 notnull out array<BaseContainer> outArray,
302 notnull out array<ref array<BaseContainer>> outArrayPaths)
303 {
304 array<BaseContainer> fullPathToThis = {};
305 fullPathToThis.Copy(pathToThis);
306 fullPathToThis.Insert(ws); // path to this widget also includes this widget
307
308 outArrayPaths.Insert(fullPathToThis);
309
310 outArray.Insert(ws);
311
312 for (int e = 0, count = ws.GetNumChildren(); e < count; e++)
313 {
314 BuildWidgetArray(ws.GetChild(e), fullPathToThis, outArray, outArrayPaths);
315 }
316 }
317
318 //------------------------------------------------------------------------------------------------
323 protected static string GetStringPathToWidget(notnull array<BaseContainer> path)
324 {
325 int c = path.Count();
326 if (c < 2)
327 return "_error_";
328
329 string pathStr;
330 for (int i = 1; i < c - 1; i++)
331 {
332 pathStr = pathStr + GetWidgetName(path[i]) + ".";
333 }
334
335 return pathStr + GetWidgetName(path[c - 1]); // last widget name without a dot
336 }
337
338 //------------------------------------------------------------------------------------------------
341 protected static string GetWidgetName(BaseContainer ws)
342 {
343 string result;
344 ws.Get("Name", result);
345 return result;
346 }
347
348 //------------------------------------------------------------------------------------------------
350 protected string ResolveDestinationPath(string fileOutName)
351 {
352 // first, look up the parameters in the root widget
353 BaseContainer widgetSource = Workbench.GetModule(ResourceManager).GetContainer();
354
355 string destinationPath;
356 string scriptAddon;
357
358 BaseContainer rule = SCR_WidgetExportRuleRoot.FindInWidgetSource(widgetSource);
359 if (rule)
360 {
361 destinationPath = SCR_WidgetExportRuleRoot.GetDestinationPath(rule);
362 scriptAddon = SCR_WidgetExportRuleRoot.GetScriptAddon(rule);
363 }
364
365 int bracketIndex = destinationPath.LastIndexOf("}");
366 string fileOutPath = destinationPath.Substring(bracketIndex + 1, destinationPath.Length() - bracketIndex - 1);
367 if (!fileOutPath.EndsWith("/"))
368 fileOutPath = fileOutPath + "/";
369
370 fileOutPath = fileOutPath + fileOutName;
371 fileOutPath = scriptAddon + fileOutPath;
372
373 return fileOutPath;
374 }
375
376 //------------------------------------------------------------------------------------------------
378 protected static void _print(string str, LogLevel logLevel = LogLevel.NORMAL)
379 {
380 PrintFormat("[GenerateLayoutClassPlugin] %1", str, level: logLevel);
381 }
382
383 //------------------------------------------------------------------------------------------------
384 [ButtonAttribute("Generate", true)]
385 protected bool ButtonOK()
386 {
387 return true;
388 }
389
390 //------------------------------------------------------------------------------------------------
391 [ButtonAttribute("Cancel")]
392 protected bool ButtonCancel()
393 {
394 return false;
395 }
396}
397#endif // WORKBENCH
string path
GenerateFlowMaps WorkbenchPlugin WorkbenchPluginAttribute("Regenerate river flow-maps", "Generate and save/overwrite river flow-maps", "", "", {"WorldEditor"}, "", 0xf773)
Definition FlowmapTool.c:59
override void Run()
bool ButtonCancel()
bool ButtonOK()
void Generate()
void _print(string s)
class WorkbenchDialog_AbortRetryIgnore ButtonAttribute("OK", true)
static string ReplaceTimes(string input, string sample, string replacement, int howMany=1, int skip=0)
static string InsertAt(string input, string insertion, int insertionIndex=0)
LogLevel
Enum with severity of the logging message.
Definition LogLevel.c:14
proto void PrintFormat(string fmt, void param1=NULL, void param2=NULL, void param3=NULL, void param4=NULL, void param5=NULL, void param6=NULL, void param7=NULL, void param8=NULL, void param9=NULL, LogLevel level=LogLevel.NORMAL)
FileMode
Mode for opening file. See FileSystem::Open.
Definition FileMode.c:14