Ide.hx 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335
  1. package hide;
  2. @:expose
  3. class Ide {
  4. public var currentConfig(get,never) : Config;
  5. public var projectDir(get,never) : String;
  6. public var resourceDir(get,never) : String;
  7. public var initializing(default,null) : Bool;
  8. public var appPath(get, null): String;
  9. public var mouseX : Int = 0;
  10. public var mouseY : Int = 0;
  11. public var isWindows(get, never) : Bool;
  12. public var isFocused(get, never) : Bool;
  13. public var database : cdb.Database;
  14. public var shaderLoader : hide.tools.ShaderLoader;
  15. public var fileWatcher : hide.tools.FileWatcher;
  16. public var isCDB = false;
  17. public var isDebugger = false;
  18. public var gamePad(default,null) : hxd.Pad;
  19. var databaseFile : String;
  20. var databaseDiff : String;
  21. var pakFile : hxd.fmt.pak.FileSystem;
  22. var originDataBase : cdb.Database;
  23. var dbWatcher : hide.tools.FileWatcher.FileWatchEvent;
  24. var config : {
  25. global : Config,
  26. project : Config,
  27. user : Config,
  28. current : Config,
  29. };
  30. public var ideConfig(get, never) : hide.Config.HideGlobalConfig;
  31. public var projectConfig(get, never) : hide.Config.HideProjectConfig;
  32. var window : nw.Window;
  33. var saveMenu : nw.Menu;
  34. var layout : golden.Layout;
  35. var currentLayout : { name : String, state : Config.LayoutState };
  36. var defaultLayout : { name : String, state : Config.LayoutState };
  37. var currentFullScreen(default,set) : hide.ui.View<Dynamic>;
  38. var maximized : Bool;
  39. var updates : Array<Void->Void> = [];
  40. var views : Array<hide.ui.View<Dynamic>> = [];
  41. var renderers : Array<h3d.mat.MaterialSetup>;
  42. var subView : { component : String, state : Dynamic, events : {} };
  43. var scripts : Map<String,Array<Void->Void>> = new Map();
  44. var hasReloaded = false;
  45. static var firstInit = true;
  46. function new() {
  47. initPad();
  48. isCDB = Sys.getEnv("HIDE_START_CDB") == "1" || nw.App.manifest.name == "CDB";
  49. isDebugger = Sys.getEnv("HIDE_DEBUG") == "1";
  50. function wait() {
  51. if( monaco.ScriptEditor == null ) {
  52. haxe.Timer.delay(wait, 10);
  53. return;
  54. }
  55. startup();
  56. }
  57. wait();
  58. }
  59. function initPad() {
  60. gamePad = hxd.Pad.createDummy();
  61. hxd.Pad.wait((p) -> gamePad = p);
  62. }
  63. function startup() {
  64. inst = this;
  65. window = nw.Window.get();
  66. var cwd = Sys.getCwd();
  67. config = Config.loadForProject(cwd, cwd+"/res");
  68. var current = ideConfig.currentProject;
  69. if( StringTools.endsWith(cwd,"package.nw") && sys.FileSystem.exists(cwd.substr(0,-10)+"res") )
  70. cwd = cwd.substr(0,-11);
  71. if( current == "" ) cwd;
  72. var args = js.Browser.document.URL.split("?")[1];
  73. if( args != null ) {
  74. var parts = args.split("&");
  75. var vars = new Map();
  76. for( p in parts ) {
  77. var p = p.split("=");
  78. vars.set(p[0],StringTools.urlDecode(p[1]));
  79. }
  80. var sub = vars.get("subView");
  81. if( sub != null ) {
  82. var obj = untyped global.sharedRefs.get(Std.parseInt(vars.get("sid")));
  83. subView = { component : sub, state : obj.state, events : obj.events };
  84. }
  85. }
  86. if( subView == null ) {
  87. var wp = ideConfig.windowPos;
  88. if( wp != null ) {
  89. if( wp.w > 400 && wp.h > 300 )
  90. window.resizeBy(wp.w - Std.int(window.window.outerWidth), wp.h - Std.int(window.window.outerHeight));
  91. if( wp.x >= 0 && wp.y >= 0 )
  92. window.moveTo(wp.x, wp.y);
  93. if( wp.max ) {
  94. window.maximize();
  95. maximized = true;
  96. }
  97. }
  98. }
  99. window.show(true);
  100. if( config.global.get("hide") == null )
  101. error("Failed to load defaultProps.json");
  102. fileWatcher = new hide.tools.FileWatcher();
  103. if( !sys.FileSystem.exists(current) || !sys.FileSystem.isDirectory(current) ) {
  104. if( current != "" ) js.Browser.alert(current+" no longer exists");
  105. current = cwd;
  106. }
  107. setProject(current);
  108. window.window.document.addEventListener("mousedown", function(e) {
  109. mouseX = e.x;
  110. mouseY = e.y;
  111. });
  112. window.window.document.addEventListener("mousemove", function(e) {
  113. mouseX = e.x;
  114. mouseY = e.y;
  115. });
  116. window.on('maximize', function() { maximized = true; onWindowChange(); });
  117. window.on('restore', function() { maximized = false; onWindowChange(); });
  118. window.on('move', function() haxe.Timer.delay(onWindowChange,100));
  119. window.on('resize', function() haxe.Timer.delay(onWindowChange,100));
  120. window.on('close', function() {
  121. if( hasReloaded ) return;
  122. if( !isDebugger )
  123. for( v in views )
  124. if( !v.onBeforeClose() )
  125. return;
  126. window.close(true);
  127. });
  128. window.on("blur", function() { if( h3d.Engine.getCurrent() != null && !hasReloaded ) hxd.Key.initialize(); });
  129. // handle commandline parameters
  130. nw.App.on("open", function(cmd) {
  131. if( hasReloaded ) return;
  132. ~/"([^"]+)"/g.map(cmd, function(r) {
  133. var file = r.matched(1);
  134. if( sys.FileSystem.exists(file) ) openFile(file);
  135. return "";
  136. });
  137. });
  138. // handle cancel on type=file
  139. var body = window.window.document.body;
  140. body.onfocus = function(_) haxe.Timer.delay(function() new Element(body).find("input[type=file]").change().remove(), 200);
  141. function dragFunc(drop : Bool, e:js.html.DragEvent) {
  142. syncMousePosition(e);
  143. var view = getViewAt(mouseX, mouseY);
  144. var items : Array<String> = [for(f in e.dataTransfer.files) Reflect.field(f, "path")];
  145. if(view != null && view.onDragDrop(items, drop)) {
  146. e.preventDefault();
  147. e.stopPropagation();
  148. return true;
  149. }
  150. return false;
  151. }
  152. body.ondragover = function(e:js.html.DragEvent) {
  153. dragFunc(false, e);
  154. return false;
  155. };
  156. body.ondrop = function(e:js.html.DragEvent) {
  157. if(!dragFunc(true, e)) {
  158. for( f in e.dataTransfer.files )
  159. openFile(Reflect.field(f,"path"));
  160. e.preventDefault();
  161. }
  162. return false;
  163. }
  164. if( subView != null ) body.className +=" hide-subview";
  165. // Listen to FileTree dnd
  166. function treeDragFun(data,drop) {
  167. var nodeIds : Array<String> = cast data.data.nodes;
  168. if(data.data.jstree == null) return false;
  169. for( ft in getViews(hide.view.FileTree) ) {
  170. var paths = [];
  171. @:privateAccess {
  172. if(ft.tree.element[0] != data.data.origin.element[0]) continue;
  173. for(id in nodeIds) {
  174. var item = ft.tree.map.get(id);
  175. if(item != null)
  176. paths.push(item.value);
  177. }
  178. }
  179. if(paths.length == 0)
  180. continue;
  181. var view = getViewAt(mouseX, mouseY);
  182. if(view != null)
  183. return view.onDragDrop(paths, drop);
  184. }
  185. return false;
  186. }
  187. new Element(window.window.document).on("dnd_move.vakata.jstree", function(e, data:Dynamic) {
  188. (data.helper:hide.Element).css(treeDragFun(data,false) ? { filter : "brightness(120%)", opacity : 1 } : { filter : "", opacity : 0.5 });
  189. });
  190. new Element(window.window.document).on("dnd_stop.vakata.jstree", function(e, data) {
  191. treeDragFun(data,true);
  192. });
  193. // dispatch global keys based on mouse position
  194. new Element(body).keydown(function(e) {
  195. var view = getViewAt(mouseX, mouseY);
  196. if(view != null) view.processKeyEvent(e);
  197. });
  198. }
  199. public function getViews<K,T:hide.ui.View<K>>( cl : Class<T> ) {
  200. return [for( v in views ) { var t = Std.downcast(v,cl); if( t != null ) t; }];
  201. }
  202. function getViewAt(x : Float, y : Float) {
  203. var pickedEl = js.Browser.document.elementFromPoint(x, y);
  204. for( v in views ) {
  205. var viewEl = v.element[0];
  206. var el = pickedEl;
  207. while(el != null) {
  208. if(el == viewEl) return v;
  209. el = el.parentElement;
  210. }
  211. }
  212. return null;
  213. }
  214. function syncMousePosition(e:js.html.MouseEvent) {
  215. mouseX = e.clientX;
  216. mouseY = e.clientY;
  217. for( c in new Element("canvas") ) {
  218. var s : hide.comp.Scene = (c:Dynamic).__scene;
  219. if( s != null ) @:privateAccess {
  220. s.window.curMouseX = mouseX;
  221. s.window.curMouseY = mouseY;
  222. }
  223. }
  224. }
  225. function get_isWindows() {
  226. return true;
  227. }
  228. function get_isFocused() {
  229. return js.Browser.document.hasFocus();
  230. }
  231. function onWindowChange() {
  232. if( hasReloaded )
  233. return;
  234. if( ideConfig.windowPos == null ) ideConfig.windowPos = { x : 0, y : 0, w : 0, h : 0, max : false };
  235. ideConfig.windowPos.max = maximized;
  236. if( !maximized ) {
  237. ideConfig.windowPos.x = window.x;
  238. ideConfig.windowPos.y = window.y;
  239. ideConfig.windowPos.w = Std.int(window.window.outerWidth);
  240. ideConfig.windowPos.h = Std.int(window.window.outerHeight);
  241. }
  242. if( subView == null )
  243. config.global.save();
  244. }
  245. function initLayout( ?state : { name : String, state : Config.LayoutState } ) {
  246. initializing = true;
  247. if( layout != null ) {
  248. layout.destroy();
  249. layout = null;
  250. }
  251. defaultLayout = null;
  252. var layoutName = isCDB ? "CDB" : "Default";
  253. var emptyLayout : Config.LayoutState = { content : [], fullScreen : null };
  254. for( p in projectConfig.layouts )
  255. if( p.name == layoutName ) {
  256. if( p.state.content == null ) continue; // old version
  257. defaultLayout = p;
  258. break;
  259. }
  260. if( defaultLayout == null ) {
  261. defaultLayout = { name : layoutName, state : emptyLayout };
  262. projectConfig.layouts.push(defaultLayout);
  263. config.current.sync();
  264. config.user.save();
  265. }
  266. if( state == null )
  267. state = defaultLayout;
  268. if( subView != null )
  269. state = { name : "SubView", state : emptyLayout };
  270. this.currentLayout = state;
  271. var config : golden.Config = {
  272. content: state.state.content,
  273. settings: {reorderEnabled : false, showPopoutIcon : false, showMaximiseIcon : false}
  274. };
  275. var comps = new Map();
  276. for( vcl in hide.ui.View.viewClasses )
  277. comps.set(vcl.name, true);
  278. function checkRec(i:golden.Config.ItemConfig) {
  279. if( i.componentName != null && !comps.exists(i.componentName) ) {
  280. i.componentState.deletedComponent = i.componentName;
  281. i.componentName = "hide.view.Unknown";
  282. }
  283. if( i.content != null ) for( i in i.content ) checkRec(i);
  284. }
  285. for( i in config.content ) checkRec(i);
  286. layout = new golden.Layout(config);
  287. var initViews = [];
  288. function initView(view:hide.ui.View<Dynamic>) {
  289. if( isDebugger ) view.rebuild() else try view.rebuild() catch( e : Dynamic ) error(view+":"+e);
  290. }
  291. for( vcl in hide.ui.View.viewClasses )
  292. layout.registerComponent(vcl.name,function(cont,state) {
  293. var view = Type.createInstance(vcl.cl,[state]);
  294. view.setContainer(cont);
  295. if( initializing )
  296. initViews.push(view);
  297. else
  298. initView(view);
  299. });
  300. layout.init();
  301. layout.on('stateChanged', onLayoutChanged);
  302. var waitCount = 0;
  303. function waitInit() {
  304. waitCount++;
  305. if( !layout.isInitialised ) {
  306. if( waitCount > 20 ) {
  307. // timeout : error recovery if invalid component
  308. state.state = emptyLayout;
  309. initLayout();
  310. return;
  311. }
  312. haxe.Timer.delay(waitInit, 50);
  313. return;
  314. }
  315. if( state.state.fullScreen != null ) {
  316. var fs = state.state.fullScreen;
  317. var found = [for( v in views ) if( v.viewClass == fs.name ) v];
  318. if( found.length == 1 )
  319. found[0].fullScreen = true;
  320. else {
  321. for( f in found )
  322. if( haxe.Json.stringify(f.state) == haxe.Json.stringify(fs.state) ) {
  323. f.fullScreen = true;
  324. break;
  325. }
  326. }
  327. }
  328. initializing = false;
  329. for( v in initViews )
  330. initView(v);
  331. initViews = null;
  332. if( subView == null && views.length == 0 ) {
  333. if( isCDB )
  334. open("hide.view.CdbTable",{}, function(v) v.fullScreen = true);
  335. else
  336. open("hide.view.FileTree",{path:""});
  337. }
  338. if( firstInit ) {
  339. firstInit = false;
  340. for( file in nw.App.argv ) {
  341. if( !sys.FileSystem.exists(file) ) continue;
  342. openFile(file);
  343. }
  344. if( subView != null )
  345. open(subView.component, subView.state);
  346. }
  347. };
  348. waitInit();
  349. hxd.System.setLoop(mainLoop);
  350. }
  351. function mainLoop() {
  352. hxd.Timer.update();
  353. @:privateAccess hxd.Pad.syncPads();
  354. for( f in updates )
  355. f();
  356. }
  357. public function setFullscreen(b : Bool) {
  358. if (b) {
  359. window.maximize();
  360. saveMenu = window.menu;
  361. window.menu = null;
  362. window.enterFullscreen();
  363. } else {
  364. window.menu = saveMenu;
  365. window.leaveFullscreen();
  366. }
  367. }
  368. function set_currentFullScreen(v) {
  369. var old = currentFullScreen;
  370. currentFullScreen = v;
  371. if( old != null ) old.fullScreen = false;
  372. onLayoutChanged();
  373. return v;
  374. }
  375. function onLayoutChanged() {
  376. if( initializing || !ideConfig.autoSaveLayout || isCDB )
  377. return;
  378. defaultLayout.state = saveLayout();
  379. if( subView == null ) this.config.user.save();
  380. }
  381. function saveLayout() : Config.LayoutState {
  382. return {
  383. content : layout.toConfig().content,
  384. fullScreen : currentFullScreen == null ? null : { name : currentFullScreen.viewClass, state : currentFullScreen.state }
  385. };
  386. }
  387. function get_ideConfig() return cast config.global.source.hide;
  388. function get_projectConfig() return cast config.user.source.hide;
  389. function get_currentConfig() return config.user;
  390. function get_appPath() {
  391. if( appPath != null )
  392. return appPath;
  393. var path = js.Node.process.argv[0].split("\\").join("/").split("/");
  394. path.pop();
  395. var hidePath = path.join("/");
  396. if( !sys.FileSystem.exists(hidePath + "/package.json") ) {
  397. var prevPath = new haxe.io.Path(hidePath).dir;
  398. if( sys.FileSystem.exists(prevPath + "/hide.js") )
  399. return appPath = prevPath;
  400. // nwjs launch
  401. var path = Sys.getCwd().split("\\").join("/");
  402. if( sys.FileSystem.exists(path+"/hide.js") )
  403. return appPath = path;
  404. message("Hide application path was not found");
  405. Sys.exit(0);
  406. }
  407. return appPath = hidePath;
  408. }
  409. public function setClipboard( text : String ) {
  410. nw.Clipboard.get().set(text, Text);
  411. }
  412. public function getClipboard() {
  413. return nw.Clipboard.get().get(Text);
  414. }
  415. public function registerUpdate( updateFun ) {
  416. updates.push(updateFun);
  417. }
  418. public function unregisterUpdate( updateFun ) {
  419. for( u in updates )
  420. if( Reflect.compareMethods(u,updateFun) ) {
  421. updates.remove(u);
  422. return true;
  423. }
  424. return false;
  425. }
  426. public function cleanObject( v : Dynamic ) {
  427. for( f in Reflect.fields(v) )
  428. if( Reflect.field(v, f) == null )
  429. Reflect.deleteField(v, f);
  430. }
  431. public function getPath( relPath : String ) {
  432. if( relPath == null )
  433. return null;
  434. relPath = relPath.split("${HIDE}").join(appPath);
  435. if( haxe.io.Path.isAbsolute(relPath) )
  436. return relPath;
  437. return resourceDir+"/"+relPath;
  438. }
  439. public function resolveCDBValue( path : String, key : Dynamic, obj : Dynamic ) : Dynamic {
  440. // allow Array as key (first choice)
  441. if( Std.is(key,Array) ) {
  442. for( v in (key:Array<Dynamic>) ) {
  443. var value = resolveCDBValue(path, v, obj);
  444. if( value != null ) return value;
  445. }
  446. return null;
  447. }
  448. path += "."+key;
  449. var path = path.split(".");
  450. var sheet = database.getSheet(path.shift());
  451. if( sheet == null )
  452. return null;
  453. while( path.length > 0 && sheet != null ) {
  454. var f = path.shift();
  455. var value : Dynamic;
  456. if( f.charCodeAt(f.length-1) == "]".code ) {
  457. var parts = f.split("[");
  458. f = parts[0];
  459. value = Reflect.field(obj, f);
  460. if( value != null )
  461. value = value[Std.parseInt(parts[1])];
  462. } else
  463. value = Reflect.field(obj, f);
  464. if( value == null )
  465. return null;
  466. var current = sheet;
  467. sheet = null;
  468. for( c in current.columns ) {
  469. if( c.name == f ) {
  470. switch( c.type ) {
  471. case TRef(name):
  472. sheet = database.getSheet(name);
  473. var ref = sheet.index.get(value);
  474. if( ref == null )
  475. return null;
  476. value = ref.obj;
  477. case TProperties, TList:
  478. sheet = current.getSub(c);
  479. default:
  480. }
  481. break;
  482. }
  483. }
  484. obj = value;
  485. }
  486. for( f in path )
  487. obj = Reflect.field(obj, f);
  488. return obj;
  489. }
  490. var showErrors = true;
  491. public function error( e : Dynamic ) {
  492. if( showErrors && !js.Browser.window.confirm(e) )
  493. showErrors = false;
  494. js.Browser.console.error(e);
  495. }
  496. function get_projectDir() return ideConfig.currentProject.split("\\").join("/");
  497. function get_resourceDir() return projectDir+"/res";
  498. function setProject( dir : String ) {
  499. fileWatcher.dispose();
  500. if( dir != ideConfig.currentProject ) {
  501. ideConfig.currentProject = dir;
  502. ideConfig.recentProjects.remove(dir);
  503. ideConfig.recentProjects.unshift(dir);
  504. if( ideConfig.recentProjects.length > 10 ) ideConfig.recentProjects.pop();
  505. config.global.save();
  506. }
  507. try {
  508. config = Config.loadForProject(projectDir, resourceDir);
  509. } catch( e : Dynamic ) {
  510. js.Browser.alert(e);
  511. return;
  512. }
  513. var title = config.current.get("hide.windowTitle");
  514. window.title = title != null ? title : ((isCDB ? "CastleDB" : "HIDE") + " - " + dir);
  515. shaderLoader = new hide.tools.ShaderLoader();
  516. hxsl.Cache.clear();
  517. var localDir = sys.FileSystem.exists(resourceDir) ? resourceDir : projectDir;
  518. var fsconf = config.current.get("fs.config", "default");
  519. hxd.res.Loader.currentInstance = new CustomLoader(new hxd.fs.LocalFileSystem(localDir,fsconf));
  520. renderers = [
  521. new hide.Renderer.MaterialSetup("Default"),
  522. new hide.Renderer.PbrSetup("PBR"),
  523. ];
  524. var plugins : Array<String> = config.current.get("plugins");
  525. for ( plugin in plugins )
  526. loadPlugin(plugin, function() {});
  527. databaseFile = config.project.get("cdb.databaseFile");
  528. databaseDiff = config.user.get("cdb.databaseDiff");
  529. var pak = config.project.get("pak.dataFile");
  530. pakFile = null;
  531. if( pak != null ) {
  532. pakFile = new hxd.fmt.pak.FileSystem();
  533. try {
  534. pakFile.loadPak(getPath(pak));
  535. } catch( e : Dynamic ) {
  536. error(""+e);
  537. }
  538. }
  539. loadDatabase();
  540. dbWatcher = fileWatcher.register(databaseFile,function() {
  541. loadDatabase(true);
  542. hide.comp.cdb.Editor.refreshAll(true);
  543. });
  544. if( config.project.get("debug.displayErrors") ) {
  545. js.Browser.window.onerror = function(msg, url, line, col, error) {
  546. var e = error.stack;
  547. e = ~/\(?chrome-extension:\/\/[a-z0-9\-\.\/]+.js:[0-9]+:[0-9]+\)?/g.replace(e,"");
  548. e = ~/at ([A-Za-z0-9_\.\$]+)/g.map(e,function(r) { var path = r.matched(1); path = path.split("$hx_exports.").pop().split("$hxClasses.").pop(); return path; });
  549. e = e.split("\t").join(" ");
  550. this.error(e);
  551. return true;
  552. };
  553. } else
  554. Reflect.deleteField(js.Browser.window, "onerror");
  555. waitScripts(function() {
  556. var extraRenderers = config.current.get("renderers");
  557. for( name in Reflect.fields(extraRenderers) ) {
  558. var clName = Reflect.field(extraRenderers, name);
  559. var cl = try js.Lib.eval(clName) catch( e : Dynamic ) null;
  560. if( cl == null ) {
  561. error(clName+" could not be found");
  562. return;
  563. }
  564. renderers.push(Type.createInstance(cl,[]));
  565. }
  566. var render = renderers[0];
  567. if( projectConfig.renderer == null )
  568. projectConfig.renderer = config.current.get("defaultRenderer");
  569. for( r in renderers ) {
  570. var name = r.displayName == null ? r.name : r.displayName;
  571. if( name == projectConfig.renderer ) {
  572. render = r;
  573. break;
  574. }
  575. }
  576. h3d.mat.MaterialSetup.current = render;
  577. initMenu();
  578. initLayout();
  579. });
  580. }
  581. function waitScripts( f : Void -> Void ) {
  582. if( !isScriptLoading() ) {
  583. f();
  584. return;
  585. }
  586. var wait = scripts.get("");
  587. if( wait == null ) {
  588. wait = [];
  589. scripts.set("",wait);
  590. }
  591. wait.push(f);
  592. }
  593. function isScriptLoading() {
  594. for( s in scripts.keys() )
  595. if( s != "" && scripts.get(s).length > 0 )
  596. return true;
  597. return false;
  598. }
  599. function loadPlugin( file : String, callb : Void -> Void, ?forceType : String ) {
  600. file = getPath(file);
  601. var wait = scripts.get(file);
  602. if( wait != null ) {
  603. if( wait.length == 0 )
  604. callb();
  605. else
  606. wait.push(callb);
  607. return;
  608. }
  609. wait = [callb];
  610. scripts.set(file, wait);
  611. function onLoad() {
  612. scripts.set(file, []);
  613. for( w in wait )
  614. w();
  615. if( !isScriptLoading() ) {
  616. wait = scripts.get("");
  617. scripts.set("",[]);
  618. for( w in wait ) w();
  619. }
  620. }
  621. function onError() {
  622. error("Error while loading "+file);
  623. }
  624. var type = forceType == null ? haxe.io.Path.extension(file).toLowerCase() : forceType;
  625. switch ( type ) {
  626. case "js":
  627. var e = js.Browser.document.createScriptElement();
  628. e.addEventListener("load", onLoad);
  629. e.addEventListener("error", onError);
  630. e.async = false;
  631. e.type = "text/javascript";
  632. e.src = "file://"+file.split("\\").join("/");
  633. js.Browser.document.body.appendChild(e);
  634. case "css":
  635. var e = js.Browser.document.createLinkElement();
  636. e.addEventListener("load", onLoad);
  637. e.addEventListener("error", onError);
  638. e.rel = "stylesheet";
  639. e.type = "text/css";
  640. e.href = "file://" + file.split("\\").join("/");
  641. js.Browser.document.body.appendChild(e);
  642. default: error('Unknown plugin type $type for file $file');
  643. }
  644. fileWatcher.register(file,reload);
  645. }
  646. inline function loadScript( file : String, callb : Void -> Void ) {
  647. loadPlugin(file, callb);
  648. }
  649. public function reload() {
  650. hasReloaded = true;
  651. fileWatcher.dispose();
  652. js.Browser.location.reload();
  653. }
  654. public function fileExists( path : String ) {
  655. if( sys.FileSystem.exists(getPath(path)) ) return true;
  656. if( pakFile != null && pakFile.exists(path) ) return true;
  657. return false;
  658. }
  659. public function getFile( path : String ) {
  660. var fullPath = getPath(path);
  661. try {
  662. return sys.io.File.getBytes(fullPath);
  663. } catch( e : Dynamic ) {
  664. if( pakFile != null )
  665. return pakFile.get(path).getBytes();
  666. throw e;
  667. }
  668. }
  669. function loadDatabase( ?checkExists ) {
  670. var exists = fileExists(databaseFile);
  671. if( checkExists && !exists )
  672. return; // cancel load
  673. database = new cdb.Database();
  674. if( !exists ) return;
  675. if( isDebugger ) {
  676. database.load(getFile(databaseFile).toString());
  677. } else try {
  678. database.load(getFile(databaseFile).toString());
  679. } catch( e : Dynamic ) {
  680. error(e);
  681. return;
  682. }
  683. if( databaseDiff != null ) {
  684. originDataBase = new cdb.Database();
  685. originDataBase.load(getFile(databaseFile).toString());
  686. if( fileExists(databaseDiff) ) {
  687. var d = new cdb.DiffFile();
  688. d.apply(database,parseJSON(getFile(databaseDiff).toString()),config.project.get("cdb.view"));
  689. }
  690. }
  691. }
  692. public function saveDatabase( ?forcePrefabs ) {
  693. hide.comp.cdb.DataFiles.save(function() {
  694. if( databaseDiff != null ) {
  695. sys.io.File.saveContent(getPath(databaseDiff), toJSON(new cdb.DiffFile().make(originDataBase,database)));
  696. fileWatcher.ignorePrevChange(dbWatcher);
  697. } else {
  698. if( !sys.FileSystem.exists(getPath(databaseFile)) && fileExists(databaseFile) ) {
  699. // was loaded from pak, cancel changes
  700. loadDatabase();
  701. hide.comp.cdb.Editor.refreshAll();
  702. return;
  703. }
  704. sys.io.File.saveContent(getPath(databaseFile), database.save());
  705. fileWatcher.ignorePrevChange(dbWatcher);
  706. }
  707. }, forcePrefabs);
  708. }
  709. public function createDBSheet( ?index : Int ) {
  710. var value = ask("Sheet name");
  711. if( value == "" || value == null ) return null;
  712. var s = database.createSheet(value, index);
  713. if( s == null ) {
  714. error("Name already exists");
  715. return null;
  716. }
  717. saveDatabase();
  718. hide.comp.cdb.Editor.refreshAll();
  719. return s;
  720. }
  721. public function makeRelative( path : String ) {
  722. path = path.split("\\").join("/");
  723. if( StringTools.startsWith(path.toLowerCase(), resourceDir.toLowerCase()+"/") )
  724. return path.substr(resourceDir.length+1);
  725. // is already a relative path
  726. if( path.charCodeAt(0) != "/".code && path.charCodeAt(1) != ":".code )
  727. return path;
  728. var resParts = resourceDir.split("/");
  729. var pathParts = path.split("/");
  730. for( i in 0...resParts.length ) {
  731. if( pathParts[i].toLowerCase() != resParts[i].toLowerCase() ) {
  732. if( pathParts[i].charCodeAt(pathParts[i].length-1) == ":".code )
  733. return path; // drive letter change
  734. var newPath = pathParts.splice(i, pathParts.length - i);
  735. for( k in 0...resParts.length - i )
  736. newPath.unshift("..");
  737. return newPath.join("/");
  738. }
  739. }
  740. return path;
  741. }
  742. public function getUnCachedUrl( path : String ) {
  743. return "file://" + getPath(path) + "?t=" + fileWatcher.getVersion(path);
  744. }
  745. public static var IMG_EXTS = ["jpg", "jpeg", "gif", "png", "raw", "dds", "hdr", "tga"];
  746. public function chooseImage( onSelect, allowNull=false ) {
  747. chooseFile(IMG_EXTS, onSelect, allowNull);
  748. }
  749. public function chooseFiles( exts : Array<String>, onSelect : Array<String> -> Void, allowNull=false ) {
  750. var e = new Element('<input type="file" style="visibility:hidden" value="" accept="${[for( e in exts ) "."+e].join(",")}" multiple="multiple"/>');
  751. e.change(function(_) {
  752. var files = [for( f in (""+e.val()).split(";") ) f];
  753. if( files.length == 1 && files[0] == "" ) files.pop();
  754. var files = [for( f in files ) makeRelative(f)];
  755. e.remove();
  756. onSelect(files);
  757. }).appendTo(window.window.document.body).click();
  758. }
  759. public function chooseFile( exts : Array<String>, onSelect : Null<String> -> Void, allowNull = false, workingdir:String = null) {
  760. var path = "";
  761. if (workingdir != null && workingdir != "#MISSING") {
  762. var pathArray = getPath(workingdir).split("/");
  763. var c = isWindows ? "\\" : "/";
  764. path = pathArray.join(c);
  765. }
  766. var e = new Element('<input type="file" style="visibility:hidden" value="" nwworkingdir="$path" accept="${[for( e in exts ) "."+e].join(",")}"/>');
  767. e.change(function(_) {
  768. var file = e.val();
  769. if( file == "" && !allowNull ) return;
  770. e.remove();
  771. onSelect(file == "" ? null : makeRelative(file));
  772. }).appendTo(window.window.document.body).click();
  773. }
  774. public function chooseFileSave( defaultPath : String, onSelect : String -> Void, allowNull=false ) {
  775. var path = getPath(defaultPath).split("/");
  776. var file = path.pop();
  777. var c = isWindows ? "\\" : "/";
  778. var path = path.join(c);
  779. var e = new Element('<input type="file" style="visibility:hidden" value="" nwworkingdir="$path" nwsaveas="$file"/>');
  780. e.change(function(_) {
  781. var file = e.val();
  782. if( file == "" && !allowNull ) return;
  783. e.remove();
  784. onSelect(file == "" ? null : makeRelative(file));
  785. }).appendTo(window.window.document.body).click();
  786. }
  787. public function chooseDirectory( onSelect : String -> Void, ?isAbsolute = false, allowNull=false ) {
  788. var e = new Element('<input type="file" style="visibility:hidden" value="" nwdirectory/>');
  789. e.change(function(ev) {
  790. var dir = ev.getThis().val();
  791. if( dir == "" && !allowNull ) return;
  792. onSelect(dir == "" ? null : (isAbsolute ? dir : makeRelative(dir)));
  793. e.remove();
  794. }).appendTo(window.window.document.body).click();
  795. }
  796. public function parseJSON( str : String ) : Dynamic {
  797. // remove comments
  798. str = ~/^[ \t]+\/\/[^\n]*/gm.replace(str, "");
  799. return haxe.Json.parse(str);
  800. }
  801. public function toJSON( v : Dynamic ) {
  802. var str = haxe.Json.stringify(v, "\t");
  803. str = ~/,\n\t+"__id__": [0-9]+/g.replace(str, "");
  804. str = ~/\t+"__id__": [0-9]+,\n/g.replace(str, "");
  805. return str;
  806. }
  807. public function loadPrefab<T:hrt.prefab.Prefab>( file : String, ?cl : Class<T>, ?checkExists ) : T {
  808. if( file == null )
  809. return null;
  810. var l = hrt.prefab.Library.create(file.split(".").pop().toLowerCase());
  811. try {
  812. var path = getPath(file);
  813. if( checkExists && !sys.FileSystem.exists(path) )
  814. return null;
  815. l.loadData(parseJSON(sys.io.File.getContent(path)));
  816. } catch( e : Dynamic ) {
  817. error("Invalid prefab ("+e+")");
  818. throw e;
  819. }
  820. if( cl == null )
  821. return cast l;
  822. return l.get(cl);
  823. }
  824. public function savePrefab( file : String, f : hrt.prefab.Prefab ) {
  825. var content = f.saveData();
  826. sys.io.File.saveContent(getPath(file), toJSON(content));
  827. }
  828. public function filterPrefabs( callb : hrt.prefab.Prefab -> Bool ) {
  829. var exts = Lambda.array({iterator : @:privateAccess hrt.prefab.Library.registeredExtensions.keys });
  830. exts.push("prefab");
  831. var todo = [];
  832. browseFiles(function(path) {
  833. var ext = path.split(".").pop();
  834. if( exts.indexOf(ext) < 0 ) return;
  835. var prefab = loadPrefab(path);
  836. var changed = false;
  837. function filterRec(p) {
  838. if( callb(p) ) changed = true;
  839. for( ps in p.children )
  840. filterRec(ps);
  841. }
  842. filterRec(prefab);
  843. if( !changed ) return;
  844. todo.push(function() sys.io.File.saveContent(getPath(path), toJSON(prefab.saveData())));
  845. });
  846. for( t in todo )
  847. t();
  848. }
  849. function browseFiles( callb : String -> Void ) {
  850. function browseRec(path) {
  851. if( path == ".tmp" ) return;
  852. for( p in sys.FileSystem.readDirectory(resourceDir + "/" + path) ) {
  853. var p = path == "" ? p : path + "/" + p;
  854. if( sys.FileSystem.isDirectory(resourceDir+"/"+p) ) {
  855. browseRec(p);
  856. continue;
  857. }
  858. callb(p);
  859. }
  860. }
  861. browseRec("");
  862. }
  863. public function initMenu() {
  864. if( subView != null ) return;
  865. var menuHTML = "<content>"+new Element("#mainmenu").html() + config.project.get("menu.extra")+"</content>";
  866. var menu = new Element(menuHTML);
  867. // project
  868. if( ideConfig.recentProjects.length > 0 )
  869. menu.find(".project .recents").html("");
  870. for( v in ideConfig.recentProjects.copy() ) {
  871. if( !sys.FileSystem.exists(v) ) {
  872. ideConfig.recentProjects.remove(v);
  873. config.global.save();
  874. continue;
  875. }
  876. new Element("<menu>").attr("label",v).appendTo(menu.find(".project .recents")).click(function(_){
  877. setProject(v);
  878. });
  879. }
  880. menu.find(".project .open").click(function(_) {
  881. chooseDirectory(function(dir) {
  882. if( dir == null ) return;
  883. if( StringTools.endsWith(dir,"/res") || StringTools.endsWith(dir,"\\res") )
  884. dir = dir.substr(0,-4);
  885. setProject(dir);
  886. }, true);
  887. });
  888. menu.find(".project .clear").click(function(_) {
  889. ideConfig.recentProjects = [];
  890. config.global.save();
  891. initMenu();
  892. });
  893. menu.find(".project .exit").click(function(_) {
  894. Sys.exit(0);
  895. });
  896. menu.find(".project .clear-local").click(function(_) {
  897. js.Browser.window.localStorage.clear();
  898. nw.App.clearCache();
  899. try sys.FileSystem.deleteFile(Ide.inst.appPath + "/props.json") catch( e : Dynamic ) {};
  900. untyped chrome.runtime.reload();
  901. });
  902. menu.find(".build-files").click(function(_) {
  903. var lastTime = haxe.Timer.stamp();
  904. var all = [""];
  905. var done = 0;
  906. var prevTitle = window.title;
  907. function loop() {
  908. while( true ) {
  909. if( all.length == 0 ) {
  910. window.title = prevTitle;
  911. return;
  912. }
  913. if( haxe.Timer.stamp() - lastTime > 0.1 ) {
  914. lastTime = haxe.Timer.stamp();
  915. window.title = '(${Std.int(done*1000/(done+all.length))/10}%) '+all[0];
  916. haxe.Timer.delay(loop,0);
  917. return;
  918. }
  919. var path = all.shift();
  920. var e = try hxd.res.Loader.currentInstance.load(path).entry catch( e : hxd.res.NotFound ) null;
  921. if( e == null && path == "" ) e = hxd.res.Loader.currentInstance.fs.getRoot();
  922. if( e != null ) done++;
  923. if( e != null && e.isDirectory ) {
  924. var base = path;
  925. if( base != "" ) base += "/";
  926. for( f in sys.FileSystem.readDirectory(getPath(path)) ) {
  927. var path = base + f;
  928. if( path == ".tmp" ) continue;
  929. if( sys.FileSystem.isDirectory(getPath(path)) )
  930. all.unshift(path);
  931. else
  932. all.push(path);
  933. }
  934. }
  935. }
  936. }
  937. loop();
  938. });
  939. for( r in renderers ) {
  940. var name = r.displayName != null ? r.displayName : r.name;
  941. new Element("<menu type='checkbox'>").attr("label", name).prop("checked",r == h3d.mat.MaterialSetup.current).appendTo(menu.find(".project .renderers")).click(function(_) {
  942. if( r != h3d.mat.MaterialSetup.current ) {
  943. projectConfig.renderer = name;
  944. config.user.save();
  945. setProject(ideConfig.currentProject);
  946. }
  947. });
  948. }
  949. // view
  950. if( !sys.FileSystem.exists(resourceDir) )
  951. menu.find(".view").remove();
  952. menu.find(".debug").click(function(_) window.showDevTools());
  953. var comps = menu.find("[component]");
  954. for( c in comps.elements() ) {
  955. var cname = c.attr("component");
  956. var cl = Type.resolveClass(cname);
  957. if( cl == null ) error("Missing component class "+cname);
  958. var state = c.attr("state");
  959. if( state != null ) try haxe.Json.parse(state) catch( e : Dynamic ) error("Invalid state "+state+" ("+e+")");
  960. c.click(function(_) {
  961. open(cname, state == null ? null : haxe.Json.parse(state));
  962. });
  963. }
  964. // database
  965. var db = menu.find(".database");
  966. db.find(".dbView").click(function(_) {
  967. open("hide.view.CdbTable",{});
  968. });
  969. db.find(".dbCompress").prop("checked",database.compress).click(function(_) {
  970. database.compress = !database.compress;
  971. saveDatabase();
  972. });
  973. db.find(".dbExport").click(function(_) {
  974. hide.comp.cdb.DataFiles.load();
  975. var lang = new cdb.Lang(@:privateAccess database.data);
  976. var xml = lang.buildXML();
  977. xml = String.fromCharCode(0xFEFF) + xml; // prefix with BOM
  978. chooseFileSave("export.xml", function(f) {
  979. if( f != null ) sys.io.File.saveContent(getPath(f), xml);
  980. });
  981. });
  982. function setDiff(f) {
  983. databaseDiff = f;
  984. config.user.set("cdb.databaseDiff", f);
  985. config.user.save();
  986. loadDatabase();
  987. hide.comp.cdb.Editor.refreshAll();
  988. initMenu();
  989. for( v in getViews(hide.view.CdbTable) )
  990. v.rebuild();
  991. }
  992. db.find(".dbCreateDiff").click(function(_) {
  993. chooseFileSave("cdb.diff", function(name) {
  994. if( name == null ) return;
  995. if( name.indexOf(".") < 0 ) name += ".diff";
  996. sys.io.File.saveContent(getPath(name),"{}");
  997. setDiff(name);
  998. });
  999. });
  1000. db.find(".dbLoadDiff").click(function(_) {
  1001. chooseFile(["diff"], function(f) {
  1002. if( f == null ) return;
  1003. setDiff(f);
  1004. });
  1005. });
  1006. db.find(".dbCloseDiff").click(function(_) {
  1007. setDiff(null);
  1008. }).attr("disabled", databaseDiff == null ? "disabled" : null);
  1009. db.find(".dbCustom").click(function(_) {
  1010. open("hide.view.CdbCustomTypes",{});
  1011. });
  1012. db.find(".dbFormulas").click(function(_) {
  1013. open("hide.comp.cdb.FormulasView",{ path : config.current.get("cdb.formulasFile") });
  1014. });
  1015. // Categories
  1016. {
  1017. function applyCategories() {
  1018. for( v in getViews(hide.view.CdbTable) )
  1019. v.applyCategories(projectConfig.dbCategories);
  1020. initMenu();
  1021. }
  1022. var allCats = hide.comp.cdb.Editor.getCategories(database);
  1023. var showAll = db.find(".dbCatShowAll");
  1024. for(cat in allCats) {
  1025. var isShown = projectConfig.dbCategories == null || projectConfig.dbCategories.indexOf(cat) >= 0;
  1026. new Element("<menu type='checkbox'>").attr("label",cat).prop("checked", isShown).insertBefore(showAll).click(function(_){
  1027. if(projectConfig.dbCategories == null)
  1028. projectConfig.dbCategories = allCats; // Init with all cats
  1029. if(isShown)
  1030. projectConfig.dbCategories.remove(cat);
  1031. else
  1032. projectConfig.dbCategories.push(cat);
  1033. config.global.save();
  1034. applyCategories();
  1035. });
  1036. }
  1037. new Element("<separator>").insertBefore(showAll);
  1038. db.find(".dbCatShowAll").click(function(_) {
  1039. projectConfig.dbCategories = null;
  1040. config.global.save();
  1041. applyCategories();
  1042. });
  1043. db.find(".dbCatHideAll").click(function(_) {
  1044. projectConfig.dbCategories = [];
  1045. config.global.save();
  1046. applyCategories();
  1047. });
  1048. }
  1049. // layout
  1050. var layouts = menu.find(".layout .content");
  1051. layouts.html("");
  1052. if(projectConfig.layouts == null)
  1053. projectConfig.layouts = [];
  1054. for( l in projectConfig.layouts ) {
  1055. if( l.name == "Default" ) continue;
  1056. new Element("<menu>").attr("label",l.name).addClass(l.name).appendTo(layouts).click(function(_) {
  1057. initLayout(l);
  1058. });
  1059. }
  1060. menu.find(".layout .autosave").click(function(_) {
  1061. ideConfig.autoSaveLayout = !ideConfig.autoSaveLayout;
  1062. config.global.save();
  1063. }).prop("checked",ideConfig.autoSaveLayout);
  1064. menu.find(".layout .saveas").click(function(_) {
  1065. var name = ask("Please enter a layout name:");
  1066. if( name == null || name == "" ) return;
  1067. projectConfig.layouts.push({ name : name, state : saveLayout() });
  1068. config.user.save();
  1069. initMenu();
  1070. });
  1071. menu.find(".layout .save").click(function(_) {
  1072. currentLayout.state = saveLayout();
  1073. config.global.save();
  1074. });
  1075. window.menu = new hide.ui.Menu(menu).root;
  1076. }
  1077. public function openFile( file : String, ?onCreate ) {
  1078. var ext = @:privateAccess hide.view.FileTree.getExtension(file);
  1079. if( ext == null ) return;
  1080. // look if already open
  1081. var path = makeRelative(file);
  1082. for( v in views )
  1083. if( Type.getClassName(Type.getClass(v)) == ext.component && v.state.path == path ) {
  1084. if( v.container.tab != null )
  1085. v.container.parent.parent.setActiveContentItem(v.container.parent);
  1086. return;
  1087. }
  1088. open(ext.component, { path : path }, onCreate);
  1089. }
  1090. public function openSubView<T>( component : Class<hide.ui.View<T>>, state : T, events : {} ) {
  1091. var sharedRefs : Map<Int,Dynamic> = untyped global.sharedRefs;
  1092. if( sharedRefs == null ) {
  1093. sharedRefs = new Map();
  1094. untyped global.sharedRefs = sharedRefs;
  1095. }
  1096. var id = 0;
  1097. while( sharedRefs.exists(id) ) id++;
  1098. sharedRefs.set(id,{ state : state, events : events });
  1099. var compName = Type.getClassName(component);
  1100. nw.Window.open("app.html?subView="+compName+"&sid="+id,{ id : compName });
  1101. }
  1102. public function callParentView( name : String, param : Dynamic ) {
  1103. if( subView != null ) Reflect.callMethod(subView.events,Reflect.field(subView.events,name),[param]);
  1104. }
  1105. public function open( component : String, state : Dynamic, ?onCreate : hide.ui.View<Dynamic> -> Void ) {
  1106. if( state == null ) state = {};
  1107. var c = hide.ui.View.viewClasses.get(component);
  1108. if( c == null )
  1109. throw "Unknown component " + component;
  1110. state.componentName = component;
  1111. for( v in views ) {
  1112. if( v.viewClass == component && haxe.Json.stringify(v.state) == haxe.Json.stringify(state) ) {
  1113. v.activate();
  1114. if( onCreate != null ) onCreate(v);
  1115. return;
  1116. }
  1117. }
  1118. var options = c.options;
  1119. var bestTarget : golden.Container = null;
  1120. for( v in views )
  1121. if( v.defaultOptions.position == options.position ) {
  1122. if( bestTarget == null || bestTarget.width * bestTarget.height < v.container.width * v.container.height )
  1123. bestTarget = v.container;
  1124. }
  1125. var index : Null<Int> = null;
  1126. var target;
  1127. if( bestTarget != null )
  1128. target = bestTarget.parent.parent;
  1129. else {
  1130. target = layout.root.contentItems[0];
  1131. if( target == null ) {
  1132. layout.root.addChild({ type : Row, isClosable: false });
  1133. target = layout.root.contentItems[0];
  1134. }
  1135. target.config.isClosable = false;
  1136. }
  1137. var needResize = options.width != null;
  1138. target.on("componentCreated", function(c) {
  1139. target.off("componentCreated");
  1140. var view : hide.ui.View<Dynamic> = untyped c.origin.__view;
  1141. if( onCreate != null ) onCreate(view);
  1142. if( needResize ) {
  1143. // when opening restricted size after free size
  1144. haxe.Timer.delay(function() {
  1145. view.container.setSize(options.width, view.container.height);
  1146. },0);
  1147. } else {
  1148. // when opening free size after restricted size
  1149. var v0 = views[0];
  1150. if( views.length == 2 && views[1] == view && v0.defaultOptions.width != null )
  1151. haxe.Timer.delay(function() {
  1152. v0.container.setSize(v0.defaultOptions.width, v0.container.height);
  1153. },0);
  1154. }
  1155. });
  1156. var config : golden.Config.ItemConfig = {
  1157. type : Component,
  1158. componentName : component,
  1159. componentState : state
  1160. };
  1161. if( options.position == Left ) index = 0;
  1162. if( index == null )
  1163. target.addChild(config);
  1164. else
  1165. target.addChild(config, index);
  1166. }
  1167. public function message( text : String ) {
  1168. js.Browser.window.alert(text);
  1169. }
  1170. public function confirm( text : String ) {
  1171. return js.Browser.window.confirm(text);
  1172. }
  1173. public function ask( text : String, ?defaultValue = "" ) {
  1174. return js.Browser.window.prompt(text, defaultValue);
  1175. }
  1176. public static var inst : Ide;
  1177. static function main() {
  1178. h3d.pass.ShaderManager.STRICT = false; // prevent errors with bad renderer
  1179. hide.tools.Macros.include(["hide.view","h3d.prim","h3d.scene","h3d.pass","hide.prefab","hrt"]);
  1180. new Ide();
  1181. }
  1182. }
  1183. class CustomLoader extends hxd.res.Loader {
  1184. var pathKeys = new Map<String,{}>();
  1185. function getKey( path : String ) {
  1186. var k = pathKeys.get(path);
  1187. if( k == null ) {
  1188. k = {};
  1189. pathKeys.set(path, k);
  1190. }
  1191. return k;
  1192. }
  1193. override function loadCache<T:hxd.res.Resource>( path : String, c : Class<T> ) : T {
  1194. var engine = h3d.Engine.getCurrent();
  1195. var i = Std.downcast(@:privateAccess engine.resCache.get(getKey(path)), c);
  1196. if( i == null ) {
  1197. i = Type.createInstance(c, [fs.get(path)]);
  1198. // i = new hxd.res.Image(fs.get(path));
  1199. @:privateAccess engine.resCache.set(getKey(path), i);
  1200. }
  1201. return i;
  1202. }
  1203. }