import ScriptWidget = require("ui/ScriptWidget"); import DataBinding = require("./DataBinding"); import InspectorUtils = require("./InspectorUtils"); import EditorUI = require("ui/EditorUI"); class ComponentInspector extends Atomic.UISection { constructor() { super(); this.subscribeToEvent("WidgetEvent", (data) => this.handleWidgetEvent(data)); } handleWidgetEvent(ev: Atomic.UIWidgetEvent) { var handled = false; for (var i = 0; i < this.bindings.length; i++) { if (this.bindings[i].handleWidgetEvent(ev)) { handled = true; } } // return if handled return handled; } inspect(component: Atomic.Component) { this.component = component; this.text = component.typeName; // For JSComponents append the filename if (component.typeName == "JSComponent") { var jsc = component; if (jsc.componentFile) { var pathInfo = Atomic.splitPath( jsc.componentFile.name); this.text = "JS - " + pathInfo.fileName; } } // don't expand by default this.value = 0; var fd = new Atomic.UIFontDescription(); fd.id = "Vera"; fd.size = 11; var nlp = new Atomic.UILayoutParams(); nlp.width = 304; // atttribute name layout param var atlp = new Atomic.UILayoutParams(); atlp.width = 100; var attrsVerticalLayout = new Atomic.UILayout(Atomic.UI_AXIS_Y); attrsVerticalLayout.spacing = 3; attrsVerticalLayout.layoutPosition = Atomic.UI_LAYOUT_POSITION_LEFT_TOP; attrsVerticalLayout.layoutSize = Atomic.UI_LAYOUT_SIZE_AVAILABLE; this.contentRoot.addChild(attrsVerticalLayout); var attrs = component.getAttributes(); for (var i in attrs) { var attr = attrs[i]; if (attr.mode & Atomic.AM_NOEDIT) continue; var binding = DataBinding.createBinding(component, attr); if (!binding) continue; var attrLayout = new Atomic.UILayout(); attrLayout.layoutDistribution = Atomic.UI_LAYOUT_DISTRIBUTION_GRAVITY; var name = new Atomic.UITextField(); name.textAlign = Atomic.UI_TEXT_ALIGN_LEFT; name.skinBg = "InspectorTextAttrName"; name.layoutParams = atlp; if (attr.type == Atomic.VAR_VECTOR3 || attr.type == Atomic.VAR_COLOR || attr.type == Atomic.VAR_QUATERNION) { attrLayout.axis = Atomic.UI_AXIS_Y; attrLayout.layoutPosition = Atomic.UI_LAYOUT_POSITION_LEFT_TOP; attrLayout.skinBg = "InspectorVectorAttrLayout"; } var bname = attr.name; if (bname == "Is Enabled") bname = "Enabled"; name.text = bname; name.fontDescription = fd; attrLayout.addChild(name); attrLayout.addChild(binding.widget); attrsVerticalLayout.addChild(attrLayout); this.bindings.push(binding); } // custom component UI if (component.typeName == "PrefabComponent") { this.addPrefabUI(attrsVerticalLayout); } if (component.typeName == "Light") { this.addLightCascadeParametersUI(attrsVerticalLayout); } if (component.typeName == "CollisionShape") { this.addCollisionShapeUI(attrsVerticalLayout); } if (component.typeName == "JSComponent") { // auto expand JSComponents this.value = 1; } if (component.typeName == "TileMap2D") { this.addTilemap2DUI(attrsVerticalLayout); } if (component.typeName == "StaticModel" || component.typeName == "AnimatedModel" || component.typeName == "Skybox") { this.addModelUI(attrsVerticalLayout, component.typeName); } if (component.typeName == "StaticSprite2D" || component.typeName == "AnimatedSprite2D") { this.addSpriteUI(attrsVerticalLayout, component.typeName); } var deleteButton = new Atomic.UIButton(); deleteButton.text = "Delete Component"; deleteButton.fontDescription = fd; deleteButton.onClick = () => { var node = this.component.node; this.component.remove(); // refresh entire inspector, fix this... this.sendEvent("EditorActiveNodeChange", { node: node }); return true; } attrsVerticalLayout.addChild(deleteButton); for (var i in this.bindings) { this.bindings[i].setWidgetValueFromObject(); this.bindings[i].objectLocked = false; } } // Move these to a mixing class addPrefabUI(layout: Atomic.UILayout) { } acceptAssetDrag(importerTypeName: string, ev: Atomic.DragEndedEvent): ToolCore.AssetImporter { var dragObject = ev.dragObject; if (dragObject.object && dragObject.object.typeName == "Asset") { var asset = dragObject.object; if (asset.importerTypeName == importerTypeName) { return asset.importer; } } return null; } createMaterialClosure(layout: Atomic.UILayout, staticModel: Atomic.StaticModel, index: number) { var o = InspectorUtils.createAttrEditFieldWithSelectButton("Material " + index, layout); var materialField = o.editField; materialField.readOnly = true; var select = o.selectButton; select.onClick = () => { EditorUI.getModelOps().showResourceSelection("Select Material", "MaterialImporter", function(asset: ToolCore.Asset) { staticModel.setMaterialIndex(index, Atomic.cache.getResource("Material", asset.path)); if (staticModel.getMaterial()) materialField.text = staticModel.getMaterial().name; else materialField.text = ""; }); } var material = staticModel.getMaterial(); if (material) { materialField.text = material.name; } // handle dropping of material on field materialField.subscribeToEvent(materialField, "DragEnded", (ev: Atomic.DragEndedEvent) => { if (ev.target == materialField) { var importer = this.acceptAssetDrag("MaterialImporter", ev); if (importer) { var materialImporter = importer; var asset = materialImporter.asset; var material = Atomic.cache.getResource("Material", asset.path); if (material) { staticModel.setMaterialIndex(index, material); ev.target.text = material.name; } } } }); } addModelUI(layout: Atomic.UILayout, typeName: string) { var staticModel = this.component; var numGeometries = staticModel.numGeometries; if (typeName == "Skybox") { numGeometries = 1; } for (var x = 0; x < numGeometries; x++) { this.createMaterialClosure(layout, staticModel, x); } } addSpriteUI(layout: Atomic.UILayout, typeName: string) { var spriteComponent = this.component; var o = InspectorUtils.createAttrEditFieldWithSelectButton("Sprite", layout); var field = o.editField; field.readOnly = true; field.text = spriteComponent.sprite ? spriteComponent.sprite.name : ""; var select = o.selectButton; select.onClick = () => { // this should allow selecting of sprite sheets as well EditorUI.getModelOps().showResourceSelection("Select Sprite", "TextureImporter", function(asset: ToolCore.Asset) { spriteComponent.sprite = Atomic.cache.getResource("Sprite2D", asset.path); if (spriteComponent.sprite) field.text = spriteComponent.sprite.name; }); } // handle dropping of component on field field.subscribeToEvent(field, "DragEnded", (ev: Atomic.DragEndedEvent) => { if (ev.target == field) { var importer = this.acceptAssetDrag("TextureImporter", ev); if (importer) { spriteComponent.sprite = Atomic.cache.getResource("Sprite2D", importer.asset.path); if (spriteComponent.sprite) field.text = spriteComponent.sprite.name; } } }); } addTilemap2DUI(layout: Atomic.UILayout) { var tilemap = this.component; var o = InspectorUtils.createAttrEditFieldWithSelectButton("TMX File", layout); var field = o.editField; field.readOnly = true; field.text = tilemap.tmxFile ? tilemap.tmxFile.name : ""; var select = o.selectButton; select.onClick = () => { // this should allow selecting of sprite sheets as well EditorUI.getModelOps().showResourceSelection("Select TMX File", "TMXImporter", function(asset: ToolCore.Asset) { tilemap.tmxFile = Atomic.cache.getResource("TmxFile2D", asset.path); if (tilemap.tmxFile) field.text = tilemap.tmxFile.name; }); } // handle dropping of component on field field.subscribeToEvent(field, "DragEnded", (ev: Atomic.DragEndedEvent) => { if (ev.target == field) { var importer = this.acceptAssetDrag("TextureImporter", ev); if (importer) { tilemap.tmxFile = Atomic.cache.getResource("TmxFile2D", importer.asset.path); if (tilemap.tmxFile) field.text = tilemap.tmxFile.name; } } }); } addLightCascadeParametersUI(layout: Atomic.UILayout) { var light = this.component; var cascadeInfo = light.getShadowCascade(); var container = InspectorUtils.createContainer(); container.gravity = Atomic.UI_GRAVITY_ALL; layout.addChild(container); var panel = new Atomic.UILayout(); panel.axis = Atomic.UI_AXIS_Y; panel.layoutSize = Atomic.UI_LAYOUT_SIZE_PREFERRED; panel.layoutPosition = Atomic.UI_LAYOUT_POSITION_LEFT_TOP; container.addChild(panel); var label = InspectorUtils.createAttrName("CSM Splits:"); panel.addChild(label); function createHandler(index, light, field) { return function(data: Atomic.UIWidgetEvent) { if (data.type == Atomic.UI_EVENT_TYPE_CHANGED) { this.light.setShadowCascadeParameter(this.index, Number(this.field.text)); } }.bind({ index: index, light: light, field: field }); } var field = InspectorUtils.createAttrEditField("Split 0", panel); field.text = cascadeInfo[0].toString(); field.subscribeToEvent(field, "WidgetEvent", createHandler(0, light, field)); field = InspectorUtils.createAttrEditField("Split 1", panel); field.text = cascadeInfo[1].toString(); field.subscribeToEvent(field, "WidgetEvent", createHandler(1, light, field)); field = InspectorUtils.createAttrEditField("Split 2", panel); field.text = cascadeInfo[2].toString(); field.subscribeToEvent(field, "WidgetEvent", createHandler(2, light, field)); field = InspectorUtils.createAttrEditField("Split 3", panel); field.text = cascadeInfo[3].toString(); field.subscribeToEvent(field, "WidgetEvent", createHandler(3, light, field)); } addCollisionShapeUI(layout: Atomic.UILayout) { var shape = this.component; var button = new Atomic.UIButton(); button.fontDescription = InspectorUtils.attrFontDesc; button.gravity = Atomic.UI_GRAVITY_RIGHT; button.text = "Set from Model"; button.onClick = () => { var model = shape.node.getComponent("StaticModel"); if (model) { var box = model.boundingBox; shape.setBox([box[3] - box[0], box[4] - box[1], box[5] - box[2]]); } }; layout.addChild(button); } component: Atomic.Component; bindings: Array = new Array(); } export = ComponentInspector;