View.hx 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. package hide.ui;
  2. enum DisplayPosition {
  3. Left;
  4. Center;
  5. Right;
  6. Bottom;
  7. }
  8. typedef ViewOptions = { ?position : DisplayPosition, ?width : Int }
  9. @:keepSub @:allow(hide.Ide)
  10. class View<T> extends hide.comp.Component {
  11. var container : golden.Container;
  12. var watches : Array<{ keep : Bool, path : String, callb : Void -> Void }> = [];
  13. public var fullScreen(get,set) : Bool;
  14. public var keys(get,null) : Keys;
  15. public var state(default, null) : T;
  16. public var undo(default, null) = new hide.ui.UndoHistory();
  17. public var config(get, null) : Config;
  18. public var viewClass(get, never) : String;
  19. public var defaultOptions(get,never) : ViewOptions;
  20. var contentWidth(get,never) : Int;
  21. var contentHeight(get,never) : Int;
  22. public function new(state:T) {
  23. super(null,null);
  24. element = null;
  25. this.state = state;
  26. ide = Ide.inst;
  27. @:privateAccess ide.currentFullScreen = null;
  28. }
  29. public function watch( filePath : String, onChange : Void -> Void, ?opts : { ?checkDelete : Bool, ?keepOnRebuild : Bool } ) {
  30. if( opts == null ) opts = {};
  31. ide.fileWatcher.register(filePath, onChange, opts.checkDelete);
  32. var w = { keep : opts.keepOnRebuild, path : filePath, callb : onChange };
  33. watches.push(w);
  34. return w;
  35. }
  36. public function unwatch(w) {
  37. if( watches.remove(w) )
  38. ide.fileWatcher.unregister(w.path, w.callb);
  39. }
  40. function get_config() {
  41. if( config == null )
  42. config = ide.currentConfig;
  43. return config;
  44. }
  45. function get_keys() {
  46. if( keys == null ) {
  47. keys = new Keys(null);
  48. keys.register("view.fullScreen", function() fullScreen = !fullScreen);
  49. }
  50. return keys;
  51. }
  52. public function getTitle() {
  53. return viewClass.split(".").pop();
  54. }
  55. public function onBeforeClose() {
  56. return true;
  57. }
  58. function get_viewClass() {
  59. return Type.getClassName(Type.getClass(this));
  60. }
  61. public function setClipboard( v : Dynamic, ?type : String ) {
  62. nw.Clipboard.get().set(ide.toJSON({ type : type == null ? viewClass : type, value : v }));
  63. }
  64. public function hasClipboard( ?type : String ) {
  65. if( type == null ) type = viewClass;
  66. var v : Dynamic = try haxe.Json.parse(nw.Clipboard.get().get()) catch( e : Dynamic ) null;
  67. return v != null && v.type == type;
  68. }
  69. public function getClipboard( ?type : String ) : Dynamic {
  70. if( type == null ) type = viewClass;
  71. var v : Dynamic = try haxe.Json.parse(nw.Clipboard.get().get()) catch( e : Dynamic ) null;
  72. return v == null || v.type != type ? null : v.value;
  73. }
  74. function syncTitle() {
  75. container.setTitle(getTitle());
  76. }
  77. public function processKeyEvent( e : js.jquery.Event ) {
  78. var active = js.Browser.document.activeElement;
  79. if( active != null && (active.nodeName == "INPUT" || active.nodeName == "TEXTAREA") ) {
  80. e.stopPropagation();
  81. return true;
  82. }
  83. for( el in element.find("[haskeys=true]").add(element).elements() ) {
  84. if(el.has(active).length == 0 && el[0] != active)
  85. continue;
  86. var keys = hide.ui.Keys.get(el);
  87. if( keys == null ) continue;
  88. if( keys.processEvent(e,config) )
  89. return true;
  90. }
  91. // global keys
  92. return keys.processEvent(e,config);
  93. }
  94. public function setContainer(cont) {
  95. this.container = cont;
  96. @:privateAccess ide.views.push(this);
  97. syncTitle();
  98. container.on("resize",function(_) {
  99. container.getElement().find('*').trigger('resize');
  100. onResize();
  101. });
  102. container.on("destroy",function(e) {
  103. if( !onBeforeClose() ) {
  104. e.preventDefault();
  105. return;
  106. }
  107. destroy();
  108. });
  109. container.on("show", function(_) {
  110. // we are dragging the container tab
  111. if( container.parent.parent.config == null ) return;
  112. haxe.Timer.delay(onActivate,0);
  113. });
  114. container.getElement().keydown(function(e) {
  115. processKeyEvent(e);
  116. });
  117. container.on("tab", function(e) {
  118. container.tab.element.contextmenu(function(e) {
  119. var menu = buildTabMenu();
  120. if( menu.length > 0 ) new hide.comp.ContextMenu(menu);
  121. e.preventDefault();
  122. });
  123. });
  124. untyped cont.parent.__view = this;
  125. element = cont.getElement();
  126. }
  127. public function rebuild() {
  128. if( container == null ) return;
  129. for( w in watches.copy() )
  130. if( !w.keep ) {
  131. ide.fileWatcher.unregister(w.path, w.callb);
  132. watches.remove(w);
  133. }
  134. syncTitle();
  135. element.empty();
  136. element.off();
  137. onDisplay();
  138. }
  139. public function onDisplay() {
  140. element.text(viewClass+(state == null ? "" : " "+state));
  141. }
  142. public function onResize() {
  143. }
  144. public function onActivate() {
  145. }
  146. public function onDragDrop(items : Array<String>, isDrop : Bool) {
  147. return false;
  148. }
  149. function toString() {
  150. return Type.getClassName(Type.getClass(this)) + (this.state == null ? "" : "("+haxe.Json.stringify(this.state)+")");
  151. }
  152. /**
  153. Gives focus if part of a tab group
  154. **/
  155. public function activate() {
  156. if( container != null ) {
  157. var cur = container.parent.parent.getActiveContentItem();
  158. if( cur != container.parent )
  159. container.parent.parent.setActiveContentItem(container.parent);
  160. }
  161. }
  162. public function saveState() {
  163. container.setState(state);
  164. }
  165. public function close() {
  166. if( container != null )
  167. container.close();
  168. }
  169. function destroy() {
  170. for( w in watches.copy() )
  171. ide.fileWatcher.unregister(w.path, w.callb);
  172. watches = [];
  173. @:privateAccess ide.views.remove(this);
  174. for( c in container.getElement().find("canvas") ) {
  175. var s : hide.comp.Scene = Reflect.field(c, "__scene");
  176. if( s != null )
  177. s.dispose();
  178. }
  179. element = null;
  180. }
  181. function buildTabMenu() : Array<hide.comp.ContextMenu.ContextMenuItem> {
  182. if( @:privateAccess ide.subView != null )
  183. return [];
  184. return [
  185. { label : "Close", click : close },
  186. { label : "Close Others", click : function() for( v in @:privateAccess ide.views.copy() ) if( v != this && v.container.tab.header == container.tab.header ) v.close() },
  187. { label : "Close All", click : function() for( v in @:privateAccess ide.views.copy() ) if( v.container.tab.header == container.tab.header ) v.close() },
  188. ];
  189. }
  190. function get_contentWidth() return container.width;
  191. function get_contentHeight() return container.height;
  192. function get_defaultOptions() return viewClasses.get(Type.getClassName(Type.getClass(this))).options;
  193. function get_fullScreen() return container != null && container.getElement().is(".fullScreen");
  194. function set_fullScreen(v) {
  195. if( fullScreen == v )
  196. return v;
  197. if( container != null ) {
  198. new Element(".fullScreen").removeClass("fullScreen");
  199. container.getElement().toggleClass("fullScreen", v);
  200. new Element("body").toggleClass("fullScreenMode",v);
  201. }
  202. @:privateAccess if( v ) ide.currentFullScreen = this else ide.currentFullScreen = null;
  203. return v;
  204. }
  205. public static var viewClasses = new Map<String,{ name : String, cl : Class<View<Dynamic>>, options : ViewOptions }>();
  206. public static function register<T>( cl : Class<View<T>>, ?options : ViewOptions ) {
  207. var name = Type.getClassName(cl);
  208. if( viewClasses.exists(name) )
  209. return null;
  210. if( options == null )
  211. options = {}
  212. if( options.position == null )
  213. options.position = Center;
  214. viewClasses.set(name, { name : name, cl : cl, options : options });
  215. return null;
  216. }
  217. }