I'm trying to use dat.gui in a three.js project to allow the visible property of various elements in the scene to be toggled on and off. Functionally, this works fine. However, the issue that I am having is because I am creating a checkbox for the visible property of each child in the scene, I end up with a long list of check boxes all labeled 'visible'.
Basically, this:
var visFolder = gui.addFolder('Components');
for (var comp in scene.children[i].children){
visFolder.add(scene.children[i].children[comp],'visible');
}
Results in something like this:
{'visible' : true,
'visible' : true,
'visible' : true,
'visible' : true,
...
}
With all the gui elements correctly referenced to each child's visible property, but not very helpful to the user.
Is there anyway to provide an alias that will be displayed to the user instead of the property name (I want to use the name or id of the element)?
Maybe you mean something like this:
gui.add(properties, "x").min(10).max(20).name("X coord");
gui.add(properties, "visible").name("Show image A");
#Mikhail
Thanks! Unfortunately the API documentation isn't clear that this method/assignment will set the display name of a controller as well as a folder. It states:
gui.name : String
The name of GUI. Used for folders. i.e a folder's name
Kind: instance property of GUI
Correction (edited after original posting): '.name' is a property for folders. '.name()' is part of the new GUI constructor as detailed here: https://github.com/dataarts/dat.gui/blob/master/API.md#new_GUI_new
I built a quick codepen to illustrate the use of the 'name()' assignment when dynamically creating folders from a data object with the same property found in multiple folders. It also dynamically assigns the folder name, just to demonstrate the difference between name assignments for folders vs controllers:
Code:
var datGui = new dat.GUI();
var data = {Folder_1: {setting:true},
Folder_2: {setting:false}
} //data
var datController ={};
for (var folder in data){
var newFolder = datGui.addFolder(folder.replace("_"," "))
for (var setting in data[folder]){
var datUniqueProperty = folder + "_" + setting;
datController[datUniqueProperty] = data[folder][setting];
var test = newFolder.add(datController,datUniqueProperty).name(setting);
} //for setting
} //for folder
for folder
Related
I've searched a lot but can't find a clear answer anywhere for string list -> enum.
I've got a list of strings that I want to turn into an enum that I can select from in Unity inspector.
Specifically, I'm trying to make an enum list of all the currently set-up Input buttons from project settings. I've got all the names, just don't know how to make it an enum or similar. Ideally showing up like a KeyCode variable in inspector.
Currently trying (and failing) with:
foreach (string s in names)
{
if (Enum.TryParse(s, true, out list))
Debug.Log(list);
else Debug.Log("FAILED");
}
"names" = static List<string> names;
"list" = static MyList list;
"MyList" = enum MyList { Null }
Returns "FAILED" 58 times for only 29 Input axis.
I want a simple solution, so if its not possible or relatively simple, I'll work out something else.
Code for getting the "names" list of strings (Works correctly):
var inputManager = AssetDatabase.LoadAllAssetsAtPath("ProjectSettings/InputManager.asset")[0];
SerializedObject obj = new SerializedObject(inputManager);
SerializedProperty axisArray = obj.FindProperty("m_Axes");
if (axisArray.arraySize == 0)
Debug.Log("No Axes");
for (int i = 0; i < axisArray.arraySize; ++i)
{
var axis = axisArray.GetArrayElementAtIndex(i);
var name = axis.FindPropertyRelative("m_Name").stringValue;
names.Add(name);
}
Normally you can do
foreach (string colorName in Enum.GetNames(typeof(Colors))) which will iterate the names of the enums.
In your code above you havent shown what list is, nor where names has come from. However.
enum Things
{
Item1 = 0,
Item2 = 1
}
You can get the name from string name = Enum.GetName(typeof(Things), (int)Things.Item2) and you can get values from names with int value = (int)Enum.Parse(typeof(Things), nameOfThing)
So depending on what you actually want in a list and what you start with, iterate through and pick the relevant one
I ended up making my own solution, since (and please correct me if I'm wrong) the TryParse() and Parse() methods appear to need the enum to already contain entries with the same name (or index int) as the string to parse. This defeats the purpose for me, since I am doing this because I don't have the names in there already.
My solution ended up being to switch to having a single string input variable instead of an enum, then use Odin Inspector's ValidateInput attribute to check (for spelling errors, and) if the input variable matches any of the string entries in my dynamic list of InputManager input names (which I update manually using Odin Inspector's Button attribute and the code in the original post).
It's slightly less clean than I wanted, but does the job, so I'm satisfied.
In the affected application is a responsive table whose ColumnListItems are added via JavaScript code. Now the lines should be highlighted by the highlighting mechanism depending on their state. The first idea was to control the whole thing via a normal controller function. I quickly discarded the idea, since the formatter is intended for such cases. So I created the appropriate Formatter function and referenced it in the JavaScript code. The call seems to work without errors, because the "console.log" is triggered in each case. Also the transfer of fixed values is possible without problems. However, the values I would have to transfer are located within customData of each line...
No matter how I try to form the path I get an "undefined" or "null" output.
I have already tried the following paths:
"/edited"
"/customData/edited"
"mAggregations/customData/0/mProperties/value"
"/mAggregations/items/0/mAggregations/customData/0/mProperties/value"
The code from Controller.js (with consciously differently indicated paths):
var colListItem = new sap.m.ColumnListItem({
highlight: {
parts: [{
path: "/mAggregations/items/0/mAggregations/customData/0/mProperties/value"
}, {
path: "/edited"
}],
formatter: Formatter.setIndication
},
cells: [oItems]
});
// first parameter to pass while runtime to the formatter
colListItem.data("editable", false);
// second paramter for the formatter function
colListItem.data("edited", false);
oTable.addItem(colListItem);
The code from Formatter.js:
setIndication: function (bEditable, bEdited) {
var sReturn;
if (bEditable && bEdited) {
// list item is in edit mode and edited
sReturn = "Error";
} else if (bEditable || bEdited) {
// list item is in edit mode or edited
sReturn = "Success";
} else {
sReturn = "None";
}
return sReturn;
}
The goal would also be for the formatter to automatically use the value of the model in order to avoid its own implementation of a listener, etc.
I hope one of you has a good/new idea that might bring me a solution :)
Many thanks in advance!
You cannot bind against the customData. Because the customData is located in the element, it is like a property.
Thats why you defined it here on colListItem: colListItem.data("key", value)
You only can bind against a model.
So I see three solutions
Store the information in a separate local JSON model whereof you can speficy your binding path to supply the values to your formatter
Do not supply the information via a binding path to the formatter, but read a model/object/array from a global variable in the controller holding the information via this (=controller) in formatter function
Store the information in the customData of each element and access the element reference in the formatter function via this(=ColumnListItem).data().
Passing the context to the formatter similar to this formatter: [Formatter.setIndication, colListItem]
Cons of 1. and 2: you need a key for a respective lookup in the other model or object.
From what I understand I would solve it with solution 3.
I would like to know which property in the JSON model has changed when modified by a view.
For a test I took OpenUI5 walkthrough example and added the following lines in the application controller
oProductModel.attachPropertyChange( function(oEvent){
console.log("event: ", oEvent);
}, this);
When I change a property in the text input, the function in the attachPropertyChange is called but oEvent object is empty as I print it in console.
I know I could connect to text input change event, but I would like to use attachPropertyChange in case there would be multiple views of the same model.
As far as I understood, you'd like to avoid using the change event of the Input control because there is no information about which property in the model has changed. However, you can still get all the relevant information within the change handler via:
oControl.getBinding(/*controlPropertyName*/).getPath() to get the name of the bound property, or
oControl.getBindingContext(/*modelName*/).getPath(/*suffix*/) to get the path of the bound context. The getPath here awaits an optional suffix that will be appended to the context path with a "/" in between.
Combine those two APIs to get an absolute path in case the property binding was relative. E.g.:
onInputChange: function (event) {
const inputControl = event.getSource();
const property = inputControl.getBinding("value").getPath(); // "myProperty"
const absolutePath = inputControl.getBindingContext(/*modelName*/).getPath(property) // "/0/myProperty"
// ...
},
You can use change event for all input field in UI, and write event handling method in the controller. You will get the property as well as value in the oEvent of the event handling method easily. I hope you understood.
Is there an easy way to automatically generate a form panel (I mean the fields and the values), given a model and a store?
Create an instance of your model, then iterate through the empty data object adding input fields to the form panel, this code won't work because the Form.Panel isn't added to anything but you should be able to get the idea.
var objModel = Ext.create('app.model.objModel'),
fp = Ext.create('Ext.form.Panel');
Ext.iterate(objModel.data, function (item) {
fp.add({xtype: 'textfield', name: item, label: item});
}
I have a custom publishing page content type, based on the Publishing Article Page content type. On this content type, I have a custom field named "PageContentCategory". In my code to create new pages, I tried this:
PublishingPage newPublishingPage = this.currentPublishingWeb.GetPublishingPages().Add(pageName, newPageSelectedLayout);
if (pageContent.IsEmpty())
{
pageContent = Properties.Resources.EAWorldArticleHandler_CreateNewArticlePage_DefaultPageContent;
}
newPublishingPage.ListItem[new Guid("{93496B35-7EC3-4132-B0D0-3BDC5606F5EF}")] = pageContentCategory;
newPublishingPage.ListItem[FieldId.PublishingPageContent] = pageContent;
newPublishingPage.Title = pageTitle;
newPublishingPage.Update();
I have also tried to set it by the field name:
PublishingPage newPublishingPage = this.currentPublishingWeb.GetPublishingPages().Add(pageName, newPageSelectedLayout);
if (pageContent.IsEmpty())
{
pageContent = Properties.Resources.EAWorldArticleHandler_CreateNewArticlePage_DefaultPageContent;
}
newPublishingPage.ListItem["PageContentCategory"] = pageContentCategory;
newPublishingPage.ListItem[FieldId.PublishingPageContent] = pageContent;
newPublishingPage.Title = pageTitle;
newPublishingPage.Update();
Both of these methods throw an error. Is there any way for me to set my custom field's value in code like this?
Try calling the Update method on newPublishingPage.Listitem not on newPublishingPage itself.
Like this:
newPublishingPage.ListItem["PageContentCategory"] = pageContentCategory;
newPublishingPage.ListItem.Update();
and then you maybe also need some of these lines, depending in the configuration of your page library
newPublishingPage.Checkin();
newPublishingPage.Publish();
newPublishingPage.Approve();
So, the solution to my problem was that I had to programmatically add the content type to the pages list instead of letting it be added automatically the first time a page with that content type was added. Apparently if you let SharePoint automatically add the content type to the pages list then it somehow doesn't get bound properly. So adding the content type first solved my problem.