Follow along with the video below to see how to install our site as a web app on your home screen.
Note: This feature currently requires accessing the site using the built-in Safari browser.
Hi Guest!
We have posted a new VaM2 dev log on Patreon, starting a monthly cadence of written progress updates between Beta releases. Highlights include the new Gizmos System, Selection Carousel, and Modes System with Context-Specific Editing. Beta1.2 is 15 of 21 items complete.
CustomUI - This is a plugin simple development tool.
※ Reporting bugs or issues will help me improve the plugin and help others. CustomUI ● This .cs for plugin UI implementation library for developer. ● This library doesn't aim to offer something novel, but rather simplifies and standardizes components that are commonly implemented by developers. ● Of course...
● fix : some minor bug fix
● fix : callbacks issue through the alpha channel of ColorPickerRGBA.
● add : implementation of InputTextScrollBoxUI functionality, it is both scrollable and selectable.
Hi 14MHz, I stumbled over a minor problem I cannot solve for now. I use a CustomUI.addSliderSimple Layout with an added Default button which itself is in a tab layout which will be reloaded on clicking on the tab. This will load the current value into the slider, which is great.
C#:
public static JSONStorableFloat erectionmorph1_min_JSON = new JSONStorableFloat("Penis Length Flaccid", 2.2f, -5.0f, 10.0f, false);
//Init value, min value, max value in the GUI
value = new float[][] {
new float[] {erectionmorph1_min_JSON.val, erectionmorph1_min_JSON.min, erectionmorph1_min_JSON.max},
...
BaseLabelUI ui01 = CustomUI.addLabel(this, true, titleLabel).setTextFontSize(26).setBackgroundColor(Color.clear).setTextColor(Color.white);
ui01.setTextAlign(TextAnchor.MiddleLeft);
BaseSliderSimpleUI ui02 = CustomUI.addSliderSimple(this, true, name, _val[0], _val[1], _val[2]).setLabelTextWeight(0.0f).setSliderWeight(0.75f).setCallback(callbackEvent).register();
UIDynamicSlider u = ui02.uid as UIDynamicSlider;
if (u != null)
{
u.defaultButtonEnabled = true;
Transform btnTransform = u.transform.Find("DefaultValueButton");
if (btnTransform != null)
{
RectTransform rt = btnTransform.GetComponent<RectTransform>();
rt.anchoredPosition = new Vector2(-40f, 13f);
}
}
In this situation, however, the default value is always overwritten with the current value as the slider is created. Do you have any idea how to make the default stick to the static default value of the JSONStorableFloat (2.2f in this case)? Thank you in advance for any help!!
● fix : Embedding the Chooser inside CustomLayoutUI causes its popup to be visually obstructed by other UIDynamic/CustomUI components.
● fix : SliderToggleUI and DonutSliderUI are overflowing beyond the scrollable area of the plugin window.
Hi 14MHz, I stumbled over a minor problem I cannot solve for now. I use a CustomUI.addSliderSimple Layout with an added Default button which itself is in a tab layout which will be reloaded on clicking on the tab. This will load the current value into the slider, which is great.
C#:
public static JSONStorableFloat erectionmorph1_min_JSON = new JSONStorableFloat("Penis Length Flaccid", 2.2f, -5.0f, 10.0f, false);
//Init value, min value, max value in the GUI
value = new float[][] {
new float[] {erectionmorph1_min_JSON.val, erectionmorph1_min_JSON.min, erectionmorph1_min_JSON.max},
...
BaseLabelUI ui01 = CustomUI.addLabel(this, true, titleLabel).setTextFontSize(26).setBackgroundColor(Color.clear).setTextColor(Color.white);
ui01.setTextAlign(TextAnchor.MiddleLeft);
BaseSliderSimpleUI ui02 = CustomUI.addSliderSimple(this, true, name, _val[0], _val[1], _val[2]).setLabelTextWeight(0.0f).setSliderWeight(0.75f).setCallback(callbackEvent).register();
UIDynamicSlider u = ui02.uid as UIDynamicSlider;
if (u != null)
{
u.defaultButtonEnabled = true;
Transform btnTransform = u.transform.Find("DefaultValueButton");
if (btnTransform != null)
{
RectTransform rt = btnTransform.GetComponent<RectTransform>();
rt.anchoredPosition = new Vector2(-40f, 13f);
}
}
In this situation, however, the default value is always overwritten with the current value as the slider is created. Do you have any idea how to make the default stick to the static default value of the JSONStorableFloat (2.2f in this case)? Thank you in advance for any help!!
Hi 14mhz! No, I dont think anything changed in this regard (did you change anything?).
I think its a VaM specific behaviour that the default values are set each time a slider is created. Since this happens every time the sub UI is (re)created, the default values will be overwritten with the current active value. Maybe I have to prevent the slider from being created each time the UI is called?
<-- In my opinion, it seems to be an issue with the implementation method.
-----
I think that in various other button-based Tab implementations, it is often done like this.
The following implementation leads to many issues because it deletes the object when a tab is selected and recreates it every time.
C#:
if select tab
foreach alltab
close(tab elements)
new(tab elements) <-- Actually, it is not advisable to implement it in this way (This is not the :) right way)
As an alternative, I suggest making only the elements within the selected Tab visible. By doing so, the problems you mentioned should not arise.
C#:
if select tab
foreach alltab
if (t is tab)
visiable(tab elements)
else
invisiable(tab elements)
The CustomTabUI I implemented is designed in this way.
In addition, in your code,
C#:
public static JSONStorableFloat erectionmorph1_min_JSON = new JSONStorableFloat("Penis Length Flaccid", 2.2f, -5.0f, 10.0f, false);
//Init value, min value, max value in the GUI
value = new float[][] {
new float[] {erectionmorph1_min_JSON.val, erectionmorph1_min_JSON.min, erectionmorph1_min_JSON.max},
...
BaseLabelUI ui01 = CustomUI.addLabel(this, true, titleLabel).setTextFontSize(26).setBackgroundColor(Color.clear).setTextColor(Color.white);
ui01.setTextAlign(TextAnchor.MiddleLeft);
BaseSliderSimpleUI ui02 = CustomUI.addSliderSimple(this, true, name, _val[0], _val[1], _val[2]).setLabelTextWeight(0.0f).setSliderWeight(0.75f).setCallback(callbackEvent).register();
UIDynamicSlider u = ui02.uid as UIDynamicSlider;
if (u != null)
{
u.defaultButtonEnabled = true;
Transform btnTransform = u.transform.Find("DefaultValueButton");
if (btnTransform != null)
{
RectTransform rt = btnTransform.GetComponent<RectTransform>();
rt.anchoredPosition = new Vector2(-40f, 13f);
}
}
when register() is called with name as the key, a JSONStorableFloat is generated automatically.
Apart from sharing the initial value, it is not connected to "erectionmorph1_min_JSON"
<-- In my opinion, it seems to be an issue with the implementation method.
-----
I think that in various other button-based Tab implementations, it is often done like this.
The following implementation leads to many issues because it deletes the object when a tab is selected and recreates it every time.
C#:
if select tab
foreach alltab
close(tab elements)
new(tab elements) <-- Actually, it is not advisable to implement it in this way (This is not the :) right way)
As an alternative, I suggest making only the elements within the selected Tab visible. By doing so, the problems you mentioned should not arise.
C#:
if select tab
foreach alltab
if (t is tab)
visiable(tab elements)
else
invisiable(tab elements)
The CustomTabUI I implemented is designed in this way.
In addition, in your code,
C#:
public static JSONStorableFloat erectionmorph1_min_JSON = new JSONStorableFloat("Penis Length Flaccid", 2.2f, -5.0f, 10.0f, false);
//Init value, min value, max value in the GUI
value = new float[][] {
new float[] {erectionmorph1_min_JSON.val, erectionmorph1_min_JSON.min, erectionmorph1_min_JSON.max},
...
BaseLabelUI ui01 = CustomUI.addLabel(this, true, titleLabel).setTextFontSize(26).setBackgroundColor(Color.clear).setTextColor(Color.white);
ui01.setTextAlign(TextAnchor.MiddleLeft);
BaseSliderSimpleUI ui02 = CustomUI.addSliderSimple(this, true, name, _val[0], _val[1], _val[2]).setLabelTextWeight(0.0f).setSliderWeight(0.75f).setCallback(callbackEvent).register();
UIDynamicSlider u = ui02.uid as UIDynamicSlider;
if (u != null)
{
u.defaultButtonEnabled = true;
Transform btnTransform = u.transform.Find("DefaultValueButton");
if (btnTransform != null)
{
RectTransform rt = btnTransform.GetComponent<RectTransform>();
rt.anchoredPosition = new Vector2(-40f, 13f);
}
}
when register() is called with name as the key, a JSONStorableFloat is generated automatically.
Apart from sharing the initial value, it is not connected to "erectionmorph1_min_JSON"
Thanks for your help! I am aware that this method is not perfect, but I cannot restructure the entire UI. I also did not succeed putting the entire layout into a container and hiding it without leaving empty boxes. So I coutinue working with the create and destroy method, but now found a way to add consistent defaultValues for your SliderSimples.
I added the following function to your CustomUI.cs to reset the DefaultValue to the initial value of the JSONStorableFloat each time the UI is created:
C#:
public BaseSliderSimpleUI setDefaultValue(float def) //Added by RunRudolf
{
UIDynamicSlider u = uid as UIDynamicSlider;
if (u != null)
{
u.defaultValue = def;
u.defaultButtonEnabled = true; //Optional, if button was deactivated
}
return this;
}
I then call this in a for with the .setDefaultValue() included:
defaultValue = new float[][] {
new float[] {erectionmorph1_min_JSON.defaultVal},
new float[] {erectionmorph1_max_JSON.defaultVal},
...
It seems to solve the problem of changing default values for me. BTW, I also left the .register(), its not needed here apparently. Thanks again for your feedback!
Good to hear from you, bill_prime. I'm away from my computer at the moment, so I can't be exact. SetActive normally works fine, but when it fails, in my experience it's usually due to interference from another routine. (I turned it off, but another process is turning it back on). Rather than calling it in Init() or Start(), try testing it in Update().
Good to hear from you, bill_prime. I'm away from my computer at the moment, so I can't be exact. SetActive normally works fine, but when it fails, in my experience it's usually due to interference from another routine. (I turned it off, but another process is turning it back on). Rather than calling it in Init() or Start(), try testing it in Update().
Hey @14mhz, i'm considering using your library for my next companion plugin for VAMStory, and with the demo, after adding the demo plugin on an empty. Saving the scene and reloading it.
I get this in the log:
!> Exception NullReferenceException: Object reference not set to an instance of an object CustomUI14mhz.UIUtil+<assign>c__Iterator0.MoveNext ()
UnityEngine.SetupCoroutine.InvokeMoveNext (IEnumerator enumerator, IntPtr returnValueAddress)
!> Exception NullReferenceException: Object reference not set to an instance of an object CustomUI14mhz.UIUtil+<assign>c__Iterator0.MoveNext ()
UnityEngine.SetupCoroutine.InvokeMoveNext (IEnumerator enumerator, IntPtr returnValueAddress)
This seems to be an error I have never encountered before. -..- (maybe seems to lie in the coroutine section of my code)
Could you kindly provide me with the scene.json so that I can better understand the circumstances under which this error occurs? ^o^
This seems to be an error I have never encountered before. -..- (maybe seems to lie in the coroutine section of my code)
Could you kindly provide me with the scene.json so that I can better understand the circumstances under which this error occurs? ^o^
Sure! It's just very basic, I simply loaded the thing on an empty and edited a couple of fields.
So that you don't forget since I confirmed: it's a silent error, so you need to load Acid's Log Forward plugin to see it
Sure! It's just very basic, I simply loaded the thing on an empty and edited a couple of fields.
So that you don't forget since I confirmed: it's a silent error, so you need to load Acid's Log Forward plugin to see it
Hey I have a question out of curiosity, is it possible to do "sub tabs", or if you prefer, a main tab list and inside of each children tabs.
Not that I need them right now, but just out of curiosity to plan my plugin properly in term of UI design ^^
Ho btw! One idea, the lists/chooser take SetPopList which sets "choices". But list also allows displayChoices, which is super handy in some situation (I'm using it often recently). You could add them if you wanted?
Ho btw! One idea, the lists/chooser take SetPopList which sets "choices". But list also allows displayChoices, which is super handy in some situation (I'm using it often recently). You could add them if you wanted?
The displayChoices feature has been implemented, and will release the next version within this week.
Additionally, the Tab‑inner‑Tab feature has been implemented and will be released along with a demo.