#Make a mod with a UITK GUI

1 messages · Page 3 of 1

dusty berry
#

radio buttons

shadow tree
#

lmao

dusty berry
#

munix can you make the unity package for me pls MisatoPray

marble shale
#

I get that this may not be a "good UX design", but I also want continuity between what players get today in FP and what I will deliver in a UITK FP

dusty berry
#

i'll send u the file with the exposed controls

shadow tree
#

I might as well package the KerbalUI theme along with it since I wanted to split it off into a Unity package, too

dusty berry
#

yeah makes sense, that way anyone can just make a new unity proj, add UITK and add the package

#

and it will be same as a template

shadow tree
#

yeah exactly

#

and since I already have code for UitkForKsp2 1.3 ready, I can go ahead and push those all out at once

dusty berry
#

idk if the way i did it is the best way
ie RadioButtons you have to add a RadioButtonGroup
and then go to the zHelpers>RadioButton

#

fget im dumb

#

actually you just put the choices you want on the RadioButtonGroup separated by commas

#

so choice A, choice B, choice C

#

and it auto generates

shadow tree
#

alright, so like the dropdown

#

what if you want to put some non-text content into the radio buttons, for example an image?

dusty berry
#

no can do

#

thats what i was gonna allow on my dropdown

#

and it is working, but still not good enough for use

#

the Unity's builtins only allow text

shadow tree
#

I mean, this works just fine

#

don't mind the "mod-icon" thing, Copilot was just hyper lmao

dusty berry
#

Oh ok like that

#

tho i think inthe UI Builder shoulndt work? maybe?

#

maybe with the controls under zHelper you can tho

shadow tree
#

works fine, I can put anything inside the radio button

#

even from the editor

#

and if you want the content to be on the left of the radio button circle instead of on the right, you can just change flex direction

dusty berry
#

even with the builder generated ones (choice A, choice B, etc)?

#

if so they did some cool magic with their controls damn

shadow tree
#

lmao it does this

dusty berry
#

yeah as i thought

#

can you check if the radio button works fine if you add it manually?

shadow tree
dusty berry
#

oh ok then its ok like that

#

i though the manually added one wouldnt work

#

tho for dropdowns i think you cant add images, just text

shadow tree
#

challenge accepted

dusty berry
#

i think the dropdown item control is on the exposed controls i sent u

shadow tree
#

it isn't

#

and I can't see one in the IDE suggestions either

dusty berry
#

yeah, then i'd need to go into the code to see how they're generated

shadow tree
#

yeah no problem, it's not important

dusty berry
#

it is generated at runtime too iirc

#

yeah either way it would be only after the 28th xD

shadow tree
#

there's a PopupTextElement inside the dropdown

#

but it has no children

dusty berry
#

yeah, i iirc the options appear as a child of that

tough jacinth
#

I'm trying to center a window in the controller's Start() method, but root.transform doesn't have any position set and boundingbox doesn't have any value. After a couple of seconds it's initialized. I remember reading that you @shadow tree had this issue. What was the fix? Where would I need to change the position, what method?

dusty berry
#

_container.CenterByDefault()

shadow tree
#

not yet released

#

that's in 1.3

#

but I'm trying to get it released today

#

so if you wait a bit, all you'll need to do is that

tough jacinth
#

so CenterByDefault() isn't release yet?

shadow tree
#

nope

dusty berry
#

i think @marble shale is using it

tough jacinth
#

ok, I'll wait, thanks

shadow tree
#

OH

#

yeah you're right lmao

#

I got the drag disabling mixed up with this

#

then yeah, you can use it right away

dusty berry
#

tho anyone with an outdated version of UITK for KSP2 will not be able to see your window

#

it will give a "method doesnt exist" exception

#

if thats the case just tell them to update their UITK

shadow tree
#

there's also a second, more customizable method, element.SetDefaultPosition, which is what the CenterByDefault method calls in the background like this:

element.SetDefaultPosition(windowSize => new Vector2(
    (ReferenceResolution.Width - windowSize.x) / 2,
    (ReferenceResolution.Height - windowSize.y) / 2
));
#

you provide a callback inside which you can use the actual window size to compute the position from it

tough jacinth
#

I don't seem to have CenterByDefault, nor SetDefaultPosition

#

maybe I need to update?

shadow tree
#

it's in version 1.2

tough jacinth
#

oops, I'm on 0.5.1

dusty berry
#

you're on what husK

#

btw munix

#

for that log that he has

#

wouldnt be better on Debug

#

since Debug is usually hidden for players, while Info is shown?

shadow tree
#

the issue is that the rootVisualElement is not the VisualElement you have as the .root in your UXML, it gets wrapped inside a TemplateContainer element when instantiated from a VisualTreeAsset

#

and your actual root element is the only child of the TemplateContainer, which spans the whole width and height of the screen usually

tough jacinth
#

yes, I've seen that

shadow tree
#

and changing the position of the TemplateContainer can lead to some stuff like dragging not working properly on some parts of the screen etc

tough jacinth
shadow tree
#

hm, I guess that might work, too?

#

but anyway, if you notice any issues with the positioning and other stuff, that's why

#

I felt like it was better to just manipulate the inner element

tough jacinth
shadow tree
#

oh got it

#

yeah, then you should just call the extension methods on that element, instead of on the rootVisualElement

#

and it should be fine

dusty berry
#

oh yeah thats what ur suposed to do

#

actually munix

#

i think that .rootVisualElement

#

would work well if we didnt put our canvas sizes to 1920.1080

#

cuz then the .rooVisualElement would be the right size

#

tho i need ot test that

shadow tree
#

I've never used a canvas size of 1920x1080

#

modlist is this for example

#

I don't think the template container has anything to do with that

#

it's always the full size of the screen afaik

dusty berry
#

hmm well tbh i havent tested so yeah it's probably just the screen size

#

idk why they dont just follow the canvas size when instantiating

shadow tree
#

I don't even know where the canvas size is saved

#

it's not in the UXML and it's not in its meta file

#

so I don't think that information goes into the bundle at all

tough jacinth
#

Yesterday when I upgraded to 1.2.0, Root[0].CenterByDefault(); was working correctly. Today, after I changed something else in the code it's not working anymore, window is still being created at 0, 0. I can't find out what's happening, no error is being thrown, nothing in the log, like everything's fine. It's not because of 1.3.0 as both versions are giving me the same result. I did have issue installing 'UITK for KSP2' package into unity and had broken uss/themes until I (somehow) fixed them, but that couldn't create issues with CenterByDefault(), could it?
Do you have an idea what might be issue?

shadow tree
#

huh, that's weird

#

yeah, the Unity project stuff should have no effect on that, since it's pretty much the same files, just in a package

dusty berry
#

usually we call it on InitializeDocument

tough jacinth
#

I haven't changed that since yesterday. It's being called in the Start() method of the controller script attached to the UIDocument. Code is something like this:

(flight scene entered)
MainGui = Window.CreateFromUxml(...)
MainGuiController mainGuiController = MainGui.gameObject.AddComponent<MainGuiController>(); 
...
public class MainGuiController : MonoBehaviour
public void Start()
...
MainGui = GetComponent<UIDocument>();
Root = MainGui.rootVisualElement;
Root[0].CenterByDefault();
shadow tree
#

you could try to replace the method call with what it does and add some debug logs to see if you're given the wrong sizes:

element.SetDefaultPosition(windowSize => 
{
    Logger.Log($"width: {windowSize.x}, height: {windowSize.y}");
    return new Vector2((ReferenceResolution.Width - windowSize.x) / 2, ReferenceResolution.Height - windowSize.y) / 2);
});
marble shale
#

@dusty berry is there a way with the dropdown element to make the label take less or no space? When I include a label, I lose the down arrow in the dropdown. Also, I'd like to have more control over the space allocated for the label as well as it's horizontal alignement.

#

Here's what I've got without the dropdown label specified

#

In the top example there's a button labeled Celestial, and in the bottom example it's just an ordinary label. I'd like the dropdown bit to take up at least 1/2 the allowable window width after margin and to be right justified with the other visual element left justified.

dusty berry
#

check the uss class of the label

#

and edit it

#

its the easiest way to do it

#

i'd advise you to only target the dropdown tho, else you'll edit everything

#

so something like

#

DropdownField > [ussClass of label here]

tough jacinth
# shadow tree you could try to replace the method call with what it does and add some debug lo...
_logger.LogDebug($"Before CenterByDefault()");
//Root[0].CenterByDefault();
Root[0].SetDefaultPosition(windowSize =>
{
   _logger.LogDebug($"ReferenceResolution.Width: {ReferenceResolution.Width}, ReferenceResolution.Height: {ReferenceResolution.Height}");
   _logger.LogDebug($"width: {windowSize.x}, height: {windowSize.y}");
   return new Vector2((ReferenceResolution.Width - windowSize.x) / 2, (ReferenceResolution.Height - windowSize.y) / 2);
});
_logger.LogDebug($"After CenterByDefault()");

and this is what the log says:

[Debug  :MicroEngineer.MainGuiController] Before CenterByDefault()
[Debug  :MicroEngineer.MainGuiController] After CenterByDefault()

I'm confused. How is this possible?

dusty berry
shadow tree
#

that's totally fine, that should happen, since SetDefaultPosition registers an event handler

#

so it won't get executed right away

dusty berry
#

Oh yeah true sorry 🙏

#

it should happen after

shadow tree
#

it should only get executed when the window first gets displayed

dusty berry
shadow tree
#

here's the implementation

tough jacinth
#

ok but loggers inside the function aren't being triggered at all

shadow tree
#

I can't see why the geometry would never change, that's weird

#

where/when do you set the window as hidden/shown?

tough jacinth
#

I don't? It just shows when MainGui = Window.CreateFromUxml(Uxmls.Instance.MainGui, "MainGui", MicroEngineerMod.Instance.transform, true); is executed

#

and now that I typed this, could it be that I passed the transfrom of the plugin class?

shadow tree
#

oh so you never hide it? it's just displayed as soon as the mod gets loaded?

tough jacinth
#

yes, I'm testing it right now, so I just set it up that it automatically triggers when the scene is loaded

marble shale
shadow tree
#

it might have to do with the handler only being bound to the element after the geometry changes, aka the window is already drawn

tough jacinth
#

ok, I'll try that

dusty berry
#

you're targeting the c# chass

#

tho again maybe its better for you to target the actual dropdown

marble shale
#

Here are the styles that are applied to the Label in the dropdown

#

The new one is not showing up as applied

shadow tree
#

shouldn't it be Dropdown? @dusty berry

marble shale
#

That one is defined with Grow = 0 and Width = 0

shadow tree
#

at least if it's using the ExposedControls one

#

I don't know how USS works with C# inheritance

marble shale
#

Interestingly changing it to just Dropdown does fix the loss of the down arrow when a label is set.

shadow tree
#

yeah that's what I thought, you can't target a base C# class in a selector

#

(Dropdown is a class extending DropdownField)

marble shale
#

If doing this makes the dropdown able to show the down arrow with a label set then maybe the C# class needs a minor tweak so it can do that without this?

#

Though it doens't (yet) solve my issue

shadow tree
#

if anything, we need to provide default styles

#

for these exposed controls

#

I just really didn't have the time to do it for the 1.3 release

dusty berry
shadow tree
#

you wrote the class though

#

which he's using

#

and you called it Dropdown

dusty berry
#

oh but you can still target the UITK class no?

shadow tree
#

apparently not

dusty berry
#

oh wtf thats wierd

#

cuz it uses the same constructor

#

its literally public Dropdown() : base()

#

maybe it doesnt take into account inheriteds

shadow tree
#

yeah, but typeof(Dropdown) =/= typeof(DropdownField) is what I'm assuming is the issue

marble shale
#

Ooo! I figured it out (maybe)

dusty berry
#

huh

marble shale
#

I'm getting about what I want and all I need to do was tell it not to display the Label

dusty berry
#

to provide uniformity to your UI

#

i think that 50% would be a good starting point

#

wait what

#

wtf

#

OHHHHHHHHHHHHH

marble shale
#

I tried setting min width and width both to 0, no effect

dusty berry
#

these are not the dropdowns labels?

#

i didnt know u were using custom labels

marble shale
#

Correct! They are not

shadow tree
#

I mean, you could also just circumvent the bug by not giving the dropdown any label, probably?

dusty berry
#

well that explains a lot

marble shale
dusty berry
#

or using the dropdowns given labels

marble shale
#

See posts above

dusty berry
marble shale
dusty berry
#

you can pretty easly

#

its just a matter of targetting the class that they have

marble shale
#

Ok, more accurately, none of the things I tried worked

dusty berry
#

oh ok xD

#

i mean sure now that's working you can keep it like that shrug

marble shale
#

yep

dusty berry
#

tho (dw its not at this scale) but as any other thing in programmin, less elements = better performance

#

the console ie has a max of 1000 entries, each entry has 3 labels, when you have 1000 entries it lags quite a bit

marble shale
#

Hah! Perfecto!

dusty berry
#

but these are BIG numbers

marble shale
#

This is interesting! I was aiming for something like this

#

And got this!

#

So, apparently using a forward slash gives a sub menu? Who knew!

#

Perhaps I can use this in the celestial object and vessel selection for moons and docking ports?

#

But what would I get if you try to pick the thing to the left of the slash instead of the thing after it?

#

Well, in preview it doesn't let you pick the thing to the left, but I think I've got a way around that...

#

@dusty berry is there any documentation for how the dropdown parses the Choices string?

dusty berry
#

not rlly

#

that i know of

#

btw i im not sure those submenus will work in game

#

im 99% sure they wont

#

by try it in play mode

marble shale
#

So far I've found that trying to make a list of submenu items, the sub items are not parsed by | or ;, and using another / gives you a third level. Using a , gives you the next row

#

Also not \

dusty berry
#

yeah then its just like unity's parsing

#

but again

#

im pretty sure that wont work in game

#

unity parsing is "TopLevel/submenu1/submenu2/item"

marble shale
#

Ahh, found it! Very tedious, but it does display something nice. Whether it works in game is unknown

#

Moho,Eve,Eve's Moon/Gilly,Kerbin,Kerbin's Moon/Mun,Kerbin's Moon/Minums,Duna,Duna's Moon/Ike,Dres,Jool

#

You have to list it as Top, Top/one, Top/two, Top/three, ...

#

This will take fewer rows to display than the old way

tough jacinth
#

@shadow tree ok, so GeometryChangedEvent does trigger, but it won't for CenterByDefault() or SetDefaultPosition

Root[0].RegisterCallback<GeometryChangedEvent>(CenterWindow);
_logger.LogDebug($"Before CenterByDefault()");
//Root[0].CenterByDefault();
Root[0].SetDefaultPosition(windowSize =>
{
   _logger.LogDebug($"ReferenceResolution.Width: {ReferenceResolution.Width}, ReferenceResolution.Height: {ReferenceResolution.Height}");
   _logger.LogDebug($"width: {windowSize.x}, height: {windowSize.y}");
   return new Vector2((ReferenceResolution.Width - windowSize.x) / 2, (ReferenceResolution.Height - windowSize.y) / 2);
   });
_logger.LogDebug($"After CenterByDefault()");
private void CenterWindow(GeometryChangedEvent evt)
{
   _logger.LogDebug("GeometryChangedEvent triggered.");
   if (evt.newRect.width == 0 || evt.newRect.height == 0)
        return;

   Root[0].transform.position = new Vector2((ReferenceResolution.Width - evt.newRect.width) / 2, (ReferenceResolution.Height - evt.newRect.height) / 2);
   Root[0].UnregisterCallback<GeometryChangedEvent>(CenterWindow);
   _logger.LogDebug("GeometryChangedEvent finished.");
}

and log says:

[Debug  :MicroEngineer.MainGuiController] Before CenterByDefault()
[Debug  :MicroEngineer.MainGuiController] After CenterByDefault()
[Debug  :MicroEngineer.MainGuiController] GeometryChangedEvent triggered.
[Debug  :MicroEngineer.MainGuiController] GeometryChangedEvent finished.

and window is now correctly positioned at the center of the screen.

shadow tree
#

that's really weird

tough jacinth
#

must be something on my side, cause I know it was working before, but anyway, my problem is solved for now. If anyone else doesn't have this, it'll be ok

shadow tree
#

I mean I was thinking I may have messed something up in the UitkForKsp2 1.3 update, but the SpaceWarp mod list still gets centered fine

tough jacinth
#

I tried it with 1.3 and 1.2, same

marble shale
#

Font question @shadow tree . I'm nearly done with building the basic layout of the FP UI in Unity and I'm working on the Resonant Orbits tab. What I've got now is this

#

Which as you can see has some undisplayed characters that look like square boxes. What I'd like is something like this

#

Which uses the "⦾" character

#

apparently that's not mapped in the font I've got. What's the default font for IMGUI that I've presumably been using? Maybe I can just switch to that for the visual element where I need that character

#

Also, separate question. Is there a way to make the toggle light appear to teh left of the label instead of to the right as it is in my current UITK layout above?

marble shale
#

I believe this is HTML code &#10686, aka circled white bullet

marble shale
marble shale
#

Confirmed!

#

@shadow tree, why would Unity be looking for a font in an OSX folder? I'm booted into Windows, not OSX. This may be why I'm having trouble changing fonts...

shadow tree
#

huh?

marble shale
#

This warning/caution note at the bottom

shadow tree
#

nah that doesn't mean anything, afaik it just has some default fallback font assets for each OS

#

it's only when you specifically try to use OS fonts, which you aren't

#

what we mostly use are the dynamic font assets

marble shale
#

I just tried to build my FP asset bundle with this in assets

#

And I got this

#

I cloned my FP UITK off the work I did in MNC, but the first thing I did was to change the file name to FP_UI and resave

#

Then I changed the uss to FlightPlanTheme.uss and resaved

#

Now I build and it makes mnc_ui.bundle?

shadow tree
#

I mean, it comes down to what bundle your assets are assigned to

#

It doesn't have anything to do with their filenames

marble shale
#

So i missed a step and need to reassign my assets to a new bundle?

shadow tree
#

Yes, in the bottom right corner

#

When you click on a file

#

You should see mnc_ui.bundle

#

And you need to change that to whatever you want the new bundle name to be

#

For all the files that should go in

marble shale
#

I did it wrong

#

Wait, I think I figured it out. I needed to click on things in the asset's folder and tell it they're in the new bundle!

#

So, step 1 - make new bundle in the list. Step 2 assign assets to new bundle. Step 3 build?

#

Which assets do I need to include? I've just added the .uss and the .uxml

#

I need to add my icons, too, don't I?

#

Awww fuck me... Now this?

#

What is this bitch up to?

#

I haven't changed any files, just added things to the bundle.

#

@shadow tree , what do I do with this?

#

I've closed/saved/reopened and confirmed my assets are in fp_ui.bundle

shadow tree
#

No clue, I've never seen that

#

Unity is a mystery to me

marble shale
#

For some reason mnc_ui.bundle is in my AssetBundles.manifest, and not fp_ui.bundle

marble shale
#

And I somehow had a ModList scene in a folder that was marked for the bundle. Why that hadn't been a problem with mnc_ui.bundle I have no idea.

tough jacinth
#

Seriously tho, unity is giving me all kinds of warnings and errors all the time which I can dismiss by clearing the console and most of the time they don't come back... and it's making me nervous as I'm not used to getting "red" errors which you just dismiss and continue as if nothing happened. But that's unity I guess?

dusty berry
#

usually just add/remove a empty line in any c# script

#

to force unity to reload the assembly

tough jacinth
#

I'm seeing some strange behavior when creating windows with Window.CreateFromElement. I'm iterating through a list of windows and creating each one with CreateFromElement.
Each loop has:
EntryWindowController ewc = new EntryWindowController(poppedOutWindow);
and inside EntryWindowController there's: Root = Uxmls.Instance.EntryWindow.CloneTree();
then back outside there's var w = Window.CreateFromElement(ewc.Root, poppedOutWindow.Name, null, true);
It appears that each created window is connected to the previous one, as they're being added to hierarchy of the same tree. I can drag individual windows normally, but each successive window reacts to the DisplayStyle.None of the previous one.

Also, before I'm iterating to create these poppedout windows, I'm creating the MainGui window with MainGui = Window.CreateFromUxml(Uxmls.Instance.MainGui, "MainGui", MicroEngineerMod.Instance.transform, true); and attaching the controller component MainGuiController mainGuiController = MainGui.gameObject.AddComponent<MainGuiController>();, which then internally again calls the EntryWindowController and adds its root to MainGui's #body visual element. And MainGui isn't affected.

I can't find a logical reason for this (or I'm misinterpreting how CreateFromElement should function), so I'm guessing there's an issue with how windows are created with CreateFromElement?

#

oh and, as you can see in the video, each created window is created at the position that is right below the previous one, so it looks like they're definitely being added to the same fantom visual element

shadow tree
#

is the video supposed to be showing that bug with the collective hiding of the windows?

#

and I mean you can look at the code of CreateFromElement for yourself

#

but in short, it takes the element you give it, creates a new game object, attaches a new UI Document to the game object, and attaches the element to the UI Document, and the game object is attached either to the parent transform you specify, or to the game's Main UI Canvas object if not specified

#

there should be 0 connections between the various UI Documents created in different calls of the CreateFromElement method

tough jacinth
#

strange...

shadow tree
#

oh I finally get what you mean

tough jacinth
#

I pass null for the transform, so they get attached to the Main Canvas. But still, MainGui isn't affected by this and it's also connected to the Main Canvas

marble shale
#

@shadow tree , I previously had this error from Unity: "Cannot mark assets and scenes in one AssetBundle", which I cleared by deleting the ModListScene from the Scenes folder. Now, bizarely, the ModListScenes.unity file has reappeared. I can delete it again and presumably will be able to build again, but I'm wondering if there's some handy thing tucked away in my unity project which is setting up me the bomb.

#

Yep, deleting the mofo allows me to build again. Who or what is putting that thing in there for me when my back is turned?

shadow tree
#

no clue why it would reappear

#

do you have that scene open in the editor maybe?

#

try to make a new empty scene, open it, and delete the old one

#

idk

marble shale
#

There is definitely something in here that's forking me.

#

I need there to be 0 scenes...

bronze crater
#

that’s not possible

#

your project is a scene

#

what i think is happening, is that your are in this “ModListScene” and you try to delete it

#

when you save, it just recreates it

marble shale
#

When that scene exists it refuses to build the asset

#

When ANY scene exists, I mean

#
using UnityEditor;
using System.IO;

public class CreateAssetBundles
{
    [MenuItem("Assets/Build AssetBundles")]
    static void BuildAllAssetBundles()
    {
        string assetBundleDirectory = "Assets/AssetBundles";
        if(!Directory.Exists(assetBundleDirectory))
        {
            Directory.CreateDirectory(assetBundleDirectory);
        }
        BuildPipeline.BuildAssetBundles(assetBundleDirectory, 
                                        BuildAssetBundleOptions.None, 
                                        BuildTarget.StandaloneWindows);
    }
}```
#

Clicking on the error takes me to this code

shadow tree
marble shale
shadow tree
#

You can have as many scenes as you want, they are in no way tied to projects

bronze crater
#

no yeah

#

i mean the hierarchy

marble shale
#

And googling that error led me took me to this: #1114994858017423460 message

#

Which is where I learned that if I delete the scene I can build - which is true

shadow tree
#

But in there it says that you cannot have a scene flagged for inclusion in a bundle

#

That's a pretty different problem

#

Unless that's the case in your project, and if it is, you just need to remove it from the bundle

marble shale
shadow tree
#

So you're sure that the scene isn't included in any bundles?

marble shale
#

I clicked on the gd scene and made sure it was removed. Until I dleted it I got no joy

shadow tree
#

It's just weird that nobody who cloned the same SpaceWarpUI project encountered the issue

#

Fun with Unity™️

marble shale
#

Also, where is the ghost in the machine making ModListScene? Why wouldn't it be FP_UIscene or something like that?

marble shale
shadow tree
#

Because the scene is opened by default when you open the project, so I'm assuming that when you try to close the project, the currently open scene tries to save

marble shale
#

I've created a new scene (called appropriately New Scene), and now when I attempt to build I get this

#

So I took zero actions to add that scene to the bundle. Just Create > Scene.

#

And if I delete it I can build

#

It is showing as not part of any bundle

#

Also, the Scenes folder where it lives is not in any bundle

#

My AssetBundles shows this

shadow tree
# marble shale

Why does it say you're trying to include scripts and built bundles into a bundle?

marble shale
#

Looking in Fp_ui.bundle I see this

#

There are also scripts in the Kerbalui bundle

shadow tree
#

No there aren't, it's impossible to put them into a bundle

#

Scriptable objects/game objects are not scripts

marble shale
#

OK, I saw "Script:" and just assumed it was, well, a script...

shadow tree
#

No clue what it means, I can't really read Unity manifests

#

Could you maybe zip your Assets folder and send it to me to take a look at?

marble shale
#

Oh crap, now I've really done it... The game is stuck on loading UI ToolKit

#

Weird. closed it and restarted and made it in...

shadow tree
#

lmao that's a new one

shadow tree
#

alright, let me take a look at the assets, just had to answer a work call

marble shale
#

That said, in a UITK UI, why are key presses from the numpad affecting my sound? Is this a You Need BANANA thing?

#

If so, I may need to make that a required dependency...

shadow tree
#

affecting sound?

#

as in, lowering/increasing volume?

marble shale
#

play the video and watch

shadow tree
#

oh alright

#

will do

marble shale
#

as in 0 and 1 mute and unmute

#

sound and music

shadow tree
#

huh

#

interesting

#

and that didn't happen with IMGUI?

#

or did you have to block input there?

#

because if so, you'll probably also have to block it in UITK

marble shale
#

It did until I added the disable game input when clicking into a text field part

shadow tree
#

yeah I figured

bronze crater
#

yeah you have to block

#

i had the same thing i remember

shadow tree
#

I can add an API for it in the library

#

and do it by default for TextFields

#

same as with the drag issues

marble shale
#

Rats. I was hoping that maybe UITK was immune to that and I wouldn't need it...

shadow tree
#

I'm assuming it's due to KSP 2 using the InputLegacy module

#

and not the "modern" one

marble shale
#

That would be fantastic!

shadow tree
#

adding it to my to-do™️

marble shale
#

Joy, without input blocking then naturally '.' and ',' play with timewarp too. And so many inputs are numeric...

#

In the meantime I'll see if I can translate the input blocking I was doing in IMGUI to my UITK text fields.

#

I've got some more work to do with those as they are not turning themselves red when the input field can't be parsed as a number - which is what I want them to do

#
    NewPeValueOSM.RegisterValueChangedCallback((evt) =>
    {
      if (float.TryParse(evt.newValue, out float newFloat))
      {
        NewPeValueOSM.style.color = Color.white;
        _newPeValue = newFloat;
      }
      else
      {
        NewPeValueOSM.style.color = Color.red;
      }
    });```
#

I've got code like this to prevent dragging, which does work, but my coloring code does not

    NewPeValueOSM.RegisterCallback<PointerDownEvent>(evt => evt.StopPropagation());
    NewPeValueOSM.RegisterCallback<PointerUpEvent>(evt => evt.StopPropagation());
    NewPeValueOSM.RegisterCallback<PointerMoveEvent>(evt => evt.StopPropagation());```
shadow tree
#

I'm just too lazy to go searching for it lmao

shadow tree
marble shale
#

GameInputState = !InputFields.Contains(GUI.GetNameOfFocusedControl());

#

What I've done before is to add the names of the controls that I want to affect to a list and then check this

marble shale
shadow tree
#

or just a log line

#

GameInputState? that seems to be a property of something

#

ah got it, Game.Input.Enable/Disable();

#
document.rootVisualElement.Query<TextField>().ForEach(textField =>
{
    textField.RegisterCallback<FocusInEvent>(_ => GameManager.Instance?.Game?.Input.Disable());
    textField.RegisterCallback<FocusOutEvent>(_ => GameManager.Instance?.Game?.Input.Enable());
});

so technically this should help

marble shale
#

Hang on, here's the trace
OnGUI calls this at the end

      // check editor focus and unset Input if needed
      UI_Fields.CheckEditor();```
CheckEditor is just this
```cs
    static public void CheckEditor()
    {
        GameInputState = !InputFields.Contains(GUI.GetNameOfFocusedControl());
    }```
InputFields is this
```cs
public static List<string> InputFields = new List<string>();```
shadow tree
marble shale
#

Ahhh, yeah. You're so much faster than me!

shadow tree
marble shale
#

so like this then?

  public void SetupDocument()
  {
    var document = GetComponent<UIDocument>();
    if (document.TryGetComponent<DocumentLocalization>(out var localization))
    {
      localization.Localize();
    }
    else
    {
      document.EnableLocalization();
    }

    _container = document.rootVisualElement;
    _container[0].CenterByDefault();
    _container.style.display = DisplayStyle.None;

    document.rootVisualElement.Query<TextField>().ForEach(textField =>
    {
      textField.RegisterCallback<FocusInEvent>(_ => GameManager.Instance?.Game?.Input.Disable());
      textField.RegisterCallback<FocusOutEvent>(_ => GameManager.Instance?.Game?.Input.Enable());
    });
  }```
#

Or would that need to be _container.rootVisualElement?

shadow tree
#

yeah, should work

marble shale
#

Hmmm... I've got multiples of these

    // pass = float.TryParse(NewPeValue.value, out _newPeValue);
    NewPeValueOSM.RegisterValueChangedCallback((evt) =>
    {
      if (float.TryParse(evt.newValue, out float newFloat))
      {
        NewPeValueOSM.style.color = Color.white;
        _newPeValue = newFloat;
      }
      else
      {
        NewPeValueOSM.style.color = Color.red;
      }
    });
    NewPeValueOSM.value = _newPeValue.ToString();
    NewPeValueOSM.RegisterCallback<PointerDownEvent>(evt => evt.StopPropagation());
    NewPeValueOSM.RegisterCallback<PointerUpEvent>(evt => evt.StopPropagation());
    NewPeValueOSM.RegisterCallback<PointerMoveEvent>(evt => evt.StopPropagation());

    FlightPlanPlugin.Logger.LogInfo($"InitializeElements: {testLog++}: NewPeValue.RegisterValueChangedCallback event initialized.");

    // pass = float.TryParse(NewApValue.value, out _newPeValue);
    NewApValueOSM.RegisterValueChangedCallback((evt) =>
    {
      if (float.TryParse(evt.newValue, out float newFloat))
      {
        NewApValueOSM.style.color = Color.white;
        _newApValue = newFloat;
      }
      else
      {
        NewApValueOSM.style.color = Color.red;
      }
    });
    NewApValueOSM.value = _newApValue.ToString();
    NewApValueOSM.RegisterCallback<PointerDownEvent>(evt => evt.StopPropagation());
    NewApValueOSM.RegisterCallback<PointerUpEvent>(evt => evt.StopPropagation());
    NewApValueOSM.RegisterCallback<PointerMoveEvent>(evt => evt.StopPropagation());```
#

Would there be some way to do this too like for the input blocking so I can just do it for all TextFields in one spot?

#

Maybe not for the value setting part, but for the color?

shadow tree
#

oh yeah, the Query method gets you a list of all elements in the hierarchy that fit what you search for, which can either be just the type in <...>, or the other arguments of the method - it takes the name of element or a class of the element

#

so you can either do it for all TextFields, or if you want to only apply it to some specific ones, you could give them all a class like .verify-number and then do something like document.rootVisualElement.Query<TextField>(className: "verify-number").ForEach(textField => DoSomething(textField));

#

it's basically the same method as element.Q, but it gives you all found elements instead of just the first one

#

there's more about it here, including examples

marble shale
#

This mostly works

    document.rootVisualElement.Query<TextField>().ForEach(textField =>
    {
      textField.RegisterCallback<FocusInEvent>(_ => GameManager.Instance?.Game?.Input.Disable());
      textField.RegisterCallback<FocusOutEvent>(_ => GameManager.Instance?.Game?.Input.Enable());
      textField.RegisterValueChangedCallback((evt) =>
      {
        if (float.TryParse(evt.newValue, out _))
        {
          textField.style.color = Color.white;
          textField.contentContainer.style.color = Color.white;
          FlightPlanPlugin.Logger.LogInfo($"TryParse success for {textField.name}. nValue = {evt.newValue}. setting color to white");
        }
        else
        {
          textField.style.color = Color.red;
          textField.contentContainer.style.color = Color.red;
          FlightPlanPlugin.Logger.LogInfo($"TryParse failure for {textField.name}. nValue = {evt.newValue}. setting color to red");
        }
      });
      textField.RegisterCallback<PointerDownEvent>(evt => evt.StopPropagation());
      textField.RegisterCallback<PointerUpEvent>(evt => evt.StopPropagation());
      textField.RegisterCallback<PointerMoveEvent>(evt => evt.StopPropagation());
    });```
#

It definitely hits the code and reports back that it's changing the color, but there's no actual effect in the GUI

#

That's in SetupDocument, and this code in InitializeElemets seems to also work in that I'm getting appropriate log messages when I edit this field.

    NewApValueOSM.RegisterValueChangedCallback((evt) =>
    {
      if (float.TryParse(evt.newValue, out float newFloat))
      {
        _newApValue = newFloat;
        FlightPlanPlugin.Logger.LogInfo($"NewApValueOSM: {_newApValue}");
      }
    });```
#

@shadow tree , @bronze crater , I've got two threories. Either I'm trying to set the wrong thing for color (in which case it would help me to learn to find the right thing), or maybe I'm setting it but it's being stepped on by some other style. In the former case I need to modify my plugin code, in the latter presumably I need to moify the styles being applied to the visual element in the asset bundel - which means in the unity editor I think.

#

But the keyboard input blocking and preventing of dragging parts work fine

shadow tree
#

thanks for testing the input blocking part, I'll put it into UitkForKsp2 then

#

as for your style issue, it should definitely not be the second case, inline element-scoped styles should have precedence over any USS styles as far as I know

#

at least that's how it works in CSS and from what I've seen so far, I haven't had any reason to think it's otherwise here

bronze crater
marble shale
#

Thanks guys. This helps as it rules out a line of inquiry.

#

I'll just need to sort out what is the right thing to poke and then procede to poke it as needed.

shadow tree
#

I mean I can't be 100% sure but call it an educated guess

marble shale
#

If poking doesn't work I may prod...

shadow tree
#

oh and by the way, I tried out building the bundles from the files you sent me and I had no issues

marble shale
#

@shadow tree where can I find any info about what to do with dropdown menus? I mean I can create them, but I'm not sure what to do to get info out of them. Apparently I can set up a handler for things like this TargetSelectionDropdown.RegisterValueChangedCallback(evt => { _selectedTarget = evt.currentTarget}), but what I'm doing for that event is a pure WAG. Is there documentation on how to use a dropdown? How to know it's been toyed with by the user and how to get the value they've selected?

shadow tree
#

I don't think you can do anything else than that event

#

though I don't get _selectedTarget = evt.currentTarget in your example

#

evt.currentTarget gives you the element on which the event was triggered, so in this case the dropdown

#

I would assume you probably want evt.newValue and evt.previousValue?

marble shale
#

Thanks I'll give that a shot

marble shale
#

@shadow tree / @dusty berry , is there any way to affect the un-clicked display of a dropdown? The Label property is just text that displays to the left of the dropdown, and in the case of my target selector dropdown that space is occupied by a button. What I'd like is to have the currently selected option shown in the gray box with the dropdown arrow if possible, or replacing the dropdown arrow if necessary.

shadow tree
#

the selected text should already be showing up there

#

(though with my in-editor testing the text was white and barely visible, so you just need to change its colors)

marble shale
#

Ahhh, I'll look more closely then and see if it's actually there. Thanks

shadow tree
#

you can just start the live preview and try to choose an option to see it

#

(you can just set the choices attribute for testing)

#

oh nevermind, I see you already have it filled in

marble shale
#

I'm not seeing anything

#

Even with font color set to bright blue, still nothing

shadow tree
#

well that's weird

#

the only thing that seems wrong there is the styles

marble shale
#

It must be something in my styles then, as what I've got is not working like what you're seeing...

marble shale
# shadow tree well that's weird

OK, I've found it - or something that positively affects it. The solution I found was to add a style selector for .unity-base-popup-field__input and configure it like this

#

The only weird thing now is the clipping on the text as seen in the burn time option dropdown. There I picked "at cheapest Eq. node" from the list and you can see it displays only "at cheapest " and then a sliver of the "E" in "Eq. node"

shadow tree
#

I mean it has a set width in the image you sent

marble shale
#

There's a right margin padding of 40!

shadow tree
#

oh 😄

marble shale
#

But why???? I override that!

#

The grayed out Dropdown element for PopupTextElement shows it's right margin as 40

#

That's this part

#

Which is supposed to have these styles applied

#

Found it! Another style selector: .unity-base-popup-field__text. I'm able to control that stupid thing now too

marble shale
#

@shadow tree While I can control the dropdown to show fine in preview by setting .unity-base-popup-field__text, it's not working in the actual game. I can pick things, and see in my debug logging that things are getting picked, but it acts like I haven't got this control applied at all. So, fine in unity preview, stomped on in the game. Is there anything I can to to try to convince the UI that it really really really should use the setting I'm giving it?

tough jacinth
#

@marble shale, this is how I've done it, works good:

CategoryDropdown = Root.Q<DropdownField>("category__dropdown"); //get a reference to the control
CategoryDropdown.choices = Enum.GetNames(typeof(MicroEntryCategory)).ToList(); //define a list of strings to populate the control
CategoryDropdown.RegisterValueChangedCallback(BuildAvailableEntries); //specify method that will trigger on value changes
 if (CategoryDropdown.value == null) ... //value property holds the selected value
tough jacinth
#

or wait, are you talking about setting a style to the control?

tough jacinth
#

for the styling, these 2 elements control how to text is displayed. I overrode .unity-popup-field__input and .unity-base-popup-field__text to get what I want.
Though I'm curious how to set the style for hovering list items you get when you're selecting something, since I cannot see visual elements for those in the hierarchy... but I didn't dig into this more deeply yet

marble shale
#

But in the game I get this:

#

My dropdown menues work in that you can use them to select something, and what you've selected will be known to the mod and can take effect, but they also don't work in that there's no visual feedback that what you've selected is selected except to go back into the dropdown and see there's now a check mark beside the selected option.

#

I've got these in my selectors. I'm not sure what's going on with the Dropdown > .unity-base-field__label one. I think that's one @dusty berry helped me with and has to do with getting the Dropdown to not show a label beside it as I need to set that separately. The bottom two are where I override .unity-popup-field__input and .unity-base-popup-field__text

tough jacinth
#

well there is a visual feedback, text color is very very dark blue so it's hard to see 🙂

#

and what did you put in those 2 styles?

marble shale
#

This for the first

tough jacinth
#

this is what I have:

.unity-base-popup-field__text {
    font-size: 14px;
    -unity-text-align: middle-center;
    color: rgb(192, 199, 213);
}

.unity-popup-field__input {
    padding-left: 0;
    padding-right: 0;
    padding-top: 0;
    padding-bottom: 0;
    width: 90%;
    margin-left: 0;
    margin-right: 0;
    margin-top: 0;
    margin-bottom: 0;
    font-size: 10px;
    -unity-text-align: middle-center;
    border-top-left-radius: 5px;
    border-bottom-left-radius: 5px;
    border-top-right-radius: 5px;
    border-bottom-right-radius: 5px;
    border-left-width: 1px;
    border-right-width: 1px;
    border-top-width: 1px;
    border-bottom-width: 1px;
    border-left-color: var(--yellowish-translucent-1);
    border-right-color: var(--yellowish-translucent-1);
    border-top-color: var(--yellowish-translucent-1);
    border-bottom-color: var(--yellowish-translucent-1);
    height: 20px;
}
marble shale
#

And this for the second

tough jacinth
#

what about text color in .unity-base-popup-field__text ?

marble shale
#

Seems like it's not set. I thought I had set it though...

tough jacinth
#

set it manually, don't trust what it says it is 😛

marble shale
#

I think I may be setting it with this...

#

Nope, never mind, that doesn't set text color either

tough jacinth
# marble shale

I mean - here, click on the color and change it to something else

#

it says it's light blue right now, but don't trust it

marble shale
tough jacinth
#

try it in game when it's set. Should be ok

marble shale
#

I think I was able to find the color I'm using in the .unity-label selector and I've set it in thei selector now. I'll try rebuilding it with this

#

Yay! It works!

#

Though it's interesting that the text is coming up centered when in my preview it's left justified. I don't think I mind, but it's interesting.

tough jacinth
#

yes, I too have some slight issues with alignment. Not everything is how it appears in unity

marble shale
tough jacinth
#

I'm just using LEDCounter7 for window title, but that's it.

#

and these are special characters I copy-pasted from some website

#

but in your case, I'd say it would be easier to just convert that character to an imate. That circle thingy in MNC, right?

#

no, it was in resonant orbit calc.

#

oh it's in flight plan now, got it 🙂

#

yeah, those are fairly simple. You could even do it yourself in paint, photoshop or wherever in a minute

marble shale
marble shale
#

@shadow tree, I've got some of my target selection using dictionaries approach working, but I'm getting NREs on a Clear() operation on the dictionary and that confuses me. What I do is this (within my FpUiController class)

  private static List<VesselComponent> allVessels;
  private static List<PartComponent> allPorts;
  private static List<CelestialBodyComponent> allBodies;
  private static List<string> targets;
  private static Dictionary<string, VesselComponent> targetVessels;
  private static Dictionary<string, PartComponent> targetPorts;
  private static Dictionary<string, CelestialBodyComponent> targetBodies;
  private static SimulationObjectModel thisVessel = null;
  public static bool SelectTarget, doNewList;
  public static bool SelectDockingPort = false;

  void ListBodies()
  {
    CelestialBodyComponent _rootBody = _activeVessel.mainBody;
    while (_rootBody.referenceBody != null)
    {
      _rootBody = _rootBody.referenceBody;
    }
    // allBodies.Clear();
    targetBodies.Clear();
    ListSubBodies(_rootBody, 0);
  }
  void ListSubBodies(CelestialBodyComponent body, int level)
  {
    foreach (CelestialBodyComponent sub in body.orbitingBodies)
    {
      string tabs = new string('\t', level);
      // allBodies.Add(sub);
      targetBodies.Add(tabs + sub.Name, sub);
      ListSubBodies(sub, level + 1);
    }
  }```
#

It's barfing on the targetBodies.Clear(); line, NREs

shadow tree
#

well I don't see you initializing the field with a value anywhere

#

so it's null

marble shale
#

Ahh, so wrap that in a test for null, then after the first time it will be set.

shadow tree
#

not really, you aren't setting the value for it anywhere

#

there is no targetBodies = ...

marble shale
#

what about this? targetBodies.Add(tabs + sub.Name, sub);

shadow tree
#

that doesn't initialize the field, you're calling an Add method on null

#

you need to first assign a value to the field to be able to do anything with it
private static Dictionary<string, CelestialBodyComponent> targetBodies = new();

#

if there's no =, it's null

#

it's basically a glorified pointer, and if you don't create a new object and assign its reference to the field, it is basically a null pointer

marble shale
#

With ports and vessels I do this, so maybe those are OK? targetPorts = allPorts.ToDictionary(x => x.Name, x => x);

shadow tree
#

yes, that is an assignment

#

so that's fine

marble shale
#

Cool. Testing now. I'll have this thing working in UITK soon

shadow tree
#

though it needs to happen before you try to call "Clear" on it

#

if you do

#

but you probably don't need that

marble shale
#

I don't call Clear on those, just assign to them

marble shale
# shadow tree but you probably don't need that

Is there a way to make the BepInEx logger spit out a list of strings or dictionary keys? I'm getting this from my foolish attempt to logg the results of what I'm doing:
[Info :Flight Plan] TargetType: Setting to Target Type to 'Vessel' [Info :Flight Plan] Choices: System.Collections.Generic.List1[System.String]
[Error : Unity Log] NullReferenceException: Object reference not set to an instance of an object
Stack trace:
FlightPlan.FpUiController.TargetType () (at C:/KSP2Mods/FlightPlan/FlightPlanProject/FlightPlanPlugin.cs:2198)`

shadow tree
#

no, you need to convert it to a string

marble shale
#

from this code

      else
      {
        TargetTypeButton.text = "Vessel";
        ListVessels();
        TargetSelectionDropdown.choices = new List<string>(targetVessels.Keys);
        FlightPlanPlugin.Logger.LogInfo($"TargetType: Setting to Target Type to 'Vessel'");
        FlightPlanPlugin.Logger.LogInfo($"Choices: {TargetSelectionDropdown.choices}");
        FlightPlanPlugin.Logger.LogInfo($"Keys: {targetPorts.Keys}");
      }```
#

like this?

        FlightPlanPlugin.Logger.LogInfo($"Choices: {TargetSelectionDropdown.choices.ToString()}");
        FlightPlanPlugin.Logger.LogInfo($"Keys: {targetPorts.Keys.ToString()}");```
shadow tree
#

that's exactly the same thing as before

marble shale
#

Yeah, I was afraid of that...

shadow tree
#

if you try to put any object inside a string, ToString() will get called automatically in the background

#

so that was the result you got

#

just call string.Join("your separator", targetPorts.Keys)

marble shale
#

Close! That works great on the list of strings, but not working on the keys. I'll fiddle with it, but at least I've confirmed the right stuff seems to be going into choices now

shadow tree
#

aren't your Keys strings?

marble shale
#

they are.

#

argetPorts = allPorts.ToDictionary(x => x.Name, x => x);

#

The first lambda is the key, right?

shadow tree
#

yes

#

so I don't see why it would work for one list of strings but not the other

marble shale
#

I think I see the problem, but I also think it's moot. When I set TargetSelectionDropdown.choices = new List<string>(targetVessels.Keys) I need to wrap targetVessels.Keys inside a List<string>(). I may need to do the same with the logger, but what's the point since I'm setting choices to this anyway. It would just be redundant.

shadow tree
#

btw you can also just use
TargetSelectionDropdown.choices = targetVessels.Keys.ToList();

#

that method should be available on any IEnumerable

marble shale
#

@shadow tree , I need to be able to programmatically set the color and alpha of a label in my FP UI. When I try googling how to do this I get info on IMGUI. How can I do this, and also where can I find info like this so I don't just keep pinging you?

#

nvm! Figured it out. Thios is workiong for me

    // Indicate Status of last GUI function
    float _transparency = 1;
    if (_UT > FPStatus.StatusTime) _transparency = (float)MuUtils.Clamp(1 - (_UT - FPStatus.StatusTime) / FPStatus.StatusFadeTime.Value, 0, 1);

    Color textColor = new Color(1,1,1,1);

    if (FPStatus.status == FPStatus.Status.OK)
      textColor = new Color(0, 1, 0, _transparency);
    if (FPStatus.status == FPStatus.Status.WARNING)
      textColor = new Color(1, 1, 0, _transparency);
    if (FPStatus.status == FPStatus.Status.ERROR)
      textColor = new Color(1, 0, 0, _transparency);

    Status.text = FPStatus.StatusText;
    Status.style.color = textColor;```
#

The color and transparency seem to work fine with this method.

tough jacinth
#

I'd suggest creating a new style in Unity and then add it in runtime with status.AddToClassList("your-class-name"); That way you keep all the styles in the uss file.

marble shale
tough jacinth
#

You define styles you'd like to use in runtime. For example .warning, .ok, .error, you define color you want in those 3 styles (in uss). And then in runtime you add or remove them when you need to with AddToClassList("warning"); and RemoveFromClassList("warning");

marble shale
# tough jacinth You define styles you'd like to use in runtime. For example `.warning`, `.ok`, `...

If all all I wanted to do was pick a color and set it, that would work - but it's more complicated than that. In this case I have a status message that I display in some color (red, yellow, green), but in addition to the color I also dynamically vary the transparency so that it starts out fully visible for FPStatus.StatusTime seconds, then after it's been displayed for that long it begins to fade out over the next FPStatus.StatusFadeTime.Value seconds. Nifty, huhj? So, the transparency is literally changing on every update between those two times.

#

New (bizzare) issue. My UITK GUI for FP is nearly complete. I'm at the point where I can test it and see that everything (well... almost everything) is working. One odd thing is that no matter what I set the new inclination value to be, it assumes it's zero. I've been up and dowm my code making strong use of vs's Find All References feature and I'll be damned if I can figure out why this one bugger doesn't work when all the others do. It could be a (must be?) a dumn typo staring me in the face - but I've not found it yet.

tough jacinth
#

Interesting. If color (transparency) needs to change every frame and slowly fade out, then yes, I'd to it in runtime as well. Though I'm curious if it could be also handled by uss somehow too. I'm guessing it can't

marble shale
#

I can plug numbers into any of these fields (well, I've not tested New LAN yet, but it's next) and I get what I expect.

#

I also get my log spammed with styupid unity warnings that I definitely don't need

#

When I call MakeNode (press Make Node button) it's running this code

      case ManeuverType.newInc:// Working
        double.TryParse(NewIncValueOSM.value, out double stupidInc);
        if (stupidInc != FPSettings.TargetInc_deg)
        {
          FlightPlanPlugin.Logger.LogInfo($"WTF MF? stupidInc = {stupidInc} =/= FPSettings.TargetInc_deg = {FPSettings.TargetInc_deg}");
          FPSettings.TargetInc_deg = stupidInc;
        }
        _pass = FlightPlanPlugin.Instance.SetInclination(_requestedBurnTime, FPSettings.TargetInc_deg, -0.5);
        break;```
#

If the NewIncValueOSM field were different than the FPSettings.TargetInc_deg it would tell me, but it doesn't and I get 0 when I can plainly see it's 30.

#

And the logging above also shows that 30 get's in - which happens here:

    NewIncValueOSM.RegisterValueChangedCallback((evt) =>
    {
      if (float.TryParse(evt.newValue, out float newFloat))
      {
        FPSettings.TargetInc_deg = newFloat;
        FlightPlanPlugin.Logger.LogInfo($"NewIncValueOSM: {FPSettings.TargetInc_deg}");
      }
      else
        FlightPlanPlugin.Logger.LogInfo($"NewIncValueOSM: unable to parse '{evt.newValue}'");
    });
#

There's another place it's effectively checked, too which is here

      textField.RegisterValueChangedCallback((evt) =>
      {
        if (float.TryParse(evt.newValue, out _))
        {
          textField.style.color = Color.white;
          textField.contentContainer.style.color = Color.white;
          FlightPlanPlugin.Logger.LogInfo($"TryParse success for {textField.name}. nValue = {evt.newValue}. setting color to white");
        }
        else
        {
          textField.style.color = Color.red;
          textField.contentContainer.style.color = Color.red;
          FlightPlanPlugin.Logger.LogInfo($"TryParse failure for {textField.name}. nValue = {evt.newValue}. setting color to red");
        }
      });```
#

Which, BTW does NOT set the color to red when the value can't be parsed - a separate issue...

#

I've hunted through the code for every place where FPSettings.TargetInc_deg is written to and accounted for them all. How can this one thing not be working when all the others work perfectly?

#

@tough jacinth , you know - your color suggestion may help with setting the color of fields that are not parsing correctly. Certainly the code I've got is failing to fix it - no clue why.

tough jacinth
#

Hard to figure out by just reading through this... what type are NewIncValueOSM and FPSettings.TargetInc_deg?

marble shale
#
    public static double TargetInc_deg
    {
        get => KBaseSettings.SFile.GetDouble("TargetInc_deg", 0);
        set { KBaseSettings.SFile.SetDouble("TargetInc_deg", value); }
    }```
#
NewIncValueOSM = _container.Q<TextField>("NewIncValueOSM");```
tough jacinth
#

try NewIncValueOSM.text

#

instead of NewIncValueOSM.value

marble shale
#

Worth a shot.

#

.text is the label for the input I think. Both .value and .text are type string

tough jacinth
#

I'm using .text for my TextFields. I remember a while ago trying with .value and something wasn't working

#

Oh and I'm also close to finishing UITK rewrite for MicroEngineer. Hoping to release a prerelease soon. It took waaay much longer than I anticipated.

marble shale
#

Same!

#

MNC was easy comparted to FP.

#

Starting from scratch isn't so bad, but refactoring soooo much stuff...

tough jacinth
#

Yeah, and I'm rewriting part of the logic since it was sometimes coupled with UI

marble shale
#

Yeah, stuff gets woven the first time through and then you have to untangle it..

marble shale
#

It's intermittent for me, but I could probably make a video of it

tough jacinth
#

Nope, can't say that I am

marble shale
tough jacinth
#

UIDocument.rootVisualElement[0].transform.position

#

you can also try with RectTransform rectTransform = UIDocument.GetComponent<RectTransform>(); (replace UIDocument with the instance of your UIDocument class.

#

but again, haven't tried it

#

and I'm off for the night, cya

marble shale
#

@shadow tree , I seems I'm doing something really bad in my target selection code. Currently I've got this:

#
    TargetSelectionDropdown.RegisterValueChangedCallback(evt =>
    {
      if (TargetTypeButton.text == "Celestial")
      {
        _activeVessel.SetTargetByID(targetBodies[evt.newValue].GlobalId);
        _currentTarget = _activeVessel.TargetObject;
      }
      else if (TargetTypeButton.text == "Vessel")
      {
        _activeVessel.SetTargetByID(targetVessels[evt.newValue].GlobalId);
        _currentTarget = _activeVessel.TargetObject;
      }
      else if (TargetTypeButton.text == "Port")
      {
        _activeVessel.SetTargetByID(targetPorts[evt.newValue].GlobalId);
        _currentTarget = _activeVessel.TargetObject;
      }

      FlightPlanPlugin.Logger.LogInfo($"Selected Target: {_currentTarget.Name}");

    });```
#

Where targetBodies is set like this

  void ListBodies()
  {
    CelestialBodyComponent _rootBody = _activeVessel.mainBody;
    while (_rootBody.referenceBody != null)
    {
      _rootBody = _rootBody.referenceBody;
    }
    // allBodies.Clear();
    if (targetBodies != null)
      targetBodies.Clear();
    ListSubBodies(_rootBody, 0);
  }
  void ListSubBodies(CelestialBodyComponent body, int level)
  {
    foreach (CelestialBodyComponent sub in body.orbitingBodies)
    {
      string tabs = new string(' ', level * 2);
      // allBodies.Add(sub);
      targetBodies.Add(tabs + sub.Name, sub);
      ListSubBodies(sub, level + 1);
    }
  }```
#

All three of the target selection branches seem to be broken, this is just how a celestial target is set - which seems provoke an endless stream of warnings in map view vs. and endless stream of NREs

shadow tree
#

I don't see the value of targetBodies being set anywhere

#

do you set it in the field definition line?

marble shale
#

yes

 private static Dictionary<string, CelestialBodyComponent> targetBodies = new();```
shadow tree
#

ok, then that should be fine

#

so what exactly are your exceptions?

marble shale
#

#🔴mod-dev message

#

I'd have to go back and double check, but I believe what I'm doing here is basically the same thing I did in the IMGUI version in that there's a call to _activeVessel.SetTargetByID followed by setting the _currentTarget = _activeVessel.TargetObject;

#

Is this possibly a problem? When I set allVessels to the return from GetAllVessels() am I getting a new fewsh copy of that list, or am I possibly grabbing the actual list and stomping on it?

    else
    {
      // Make a list of all vessels other than this one
      // allVessels = GameManager.Instance.Game.SpaceSimulation.UniverseModel.GetAllVessels();
      allVessels = Game.SpaceSimulation.UniverseModel.GetAllVessels();
      allVessels.Remove(_activeVessel);
      allVessels.RemoveAll(v => v.IsDebris());
      targetVessels = allVessels.ToDictionary(x => x.Name, x => x);
    }
#

should it be something like allVessels = new Game.SpaceSimulation.UniverseModel.GetAllVessels();

shadow tree
#

well have you tried debugging what you're getting in the individual steps? like evt.newValue, targetBodies[evt.newValue], targetBodies[evt.newValue].GlobalId etc

marble shale
#

Not yet, but of course I can.

shadow tree
marble shale
#
    public List<VesselComponent> GetAllVessels()
    {
      return _allVessels.ValuesList;
    }```
shadow tree
#

I'm not sure but it's possible you're removing it from the game's vessel list

marble shale
#

That was my thought just now. It could explain some of the insanity I'm seeing.

shadow tree
#

if anything, you should probably just be calling allVessels.Filter to get a new copy of the list without some elements

#

rather than modifying the original with .Remove

marble shale
#

Oh, that might do it.

#

I've not used Filter before, but I'll give that a try

#

Where can I find info on how to use the Filter method?

#

There doesn't seem to be a .Filter method on this list...

shadow tree
#

oh it's called Where

#

yeah you really shouldn't be asking me this stuff lmao

marble shale
#

Ahh!

shadow tree
#

I've been working with C# about as long as you

#

so I'm often just guessing

#

😅

marble shale
#

Really?

#

Wow...

shadow tree
#

I guess it's just easier to get into with (some amount of) knowledge of Java, C++, PHP, etc

marble shale
#

How's this look?

    else
    {
      // Make a list of all vessels other than this one
      allVessels = Game.SpaceSimulation.UniverseModel.GetAllVessels();
      // allVessels.Remove(_activeVessel);
      // allVessels.RemoveAll(v => v.IsDebris());
      targetVessels = allVessels.Where(v => !v.IsDebris()).Where(v => v.GlobalId != _activeVessel.GlobalId).ToDictionary(x => x.Name, x => x);
    }```
#

I assume I just have multiple Where() calls to filter like this

shadow tree
#

it should work as well, but I think that will make it iterate through the list twice, where you could just have allVessels.Where(v => !v.IsDebris() && v.GlobalId != _activeVessel.GlobalId) to iterate once

marble shale
#

Ahh, that would be better! Thanks!

shadow tree
#

though it's also possible that there's some optimizations in the background for these LINQ queries, I can't say for sure

marble shale
#

Is Where a LINQ query?

#

Yep, that fixed the vessel targeting part!

shadow tree
# marble shale Is Where a LINQ query?

yeah, they are like a generic API for querying/transforming IEnumerables, is my understanding of it, and you can either use this functional style, or you could also write it in the query form like

targetVessels = 
            (from vessel in allVessels
            where !vessel.IsDebris()
                  && vessel.GlobalId != _activeVessel.GlobalId
            select vessel).ToDictionary(v => v.Name, v => v);
#

it's basically an SQL-like language for dealing with .NET collections

marble shale
# shadow tree it's basically an SQL-like language for dealing with .NET collections

I think I've got things working well in FlightPlan now, though I do still get spammed with Unity debug warnings whenever in map view with a celestial body selected. Not really sure why that is, but I suspect it's outside my code. Is there a way to suppress those debug warnings in the console? I thought I'd turned off the debug log level in the BepInEx config.

shadow tree
#

Well that only applies to BepInEx logs

#

And these come from the game/Unity engine instead

#

So BepInEx has nothing to do with them really

#

You'd have to probably do something like Harmony patch the Unity logging methods to get rid of it

marble shale
#

I'll run a test unmodded to see what happens when I select a celestial target in the normal way. If this spam doesn't show up that way, then presumably I'm doing it differently, and thus perhaps wrong, in FP. At least the vessel/part selection is working better now!

marble shale
#

FYI, with all mods disabled I see the unity debug spam in map mode with a celestial target selected. I haven't tried this in a completely unmodded game, just with all mods disabled, as it's a minor PITA to branch off a copy of the unmodded game and make that a debug version with a console - not really a big deal, just annoying enough that I haven't done it... yet.

#

@shadow tree / @dusty berry , I'm still struggling to get a tryparse test of text input fields that will actually have the effect I want. In the IMGUI version of the mod I can do this pretty easily and turn the text in the input field as well as the border around the text red as a visual clue to the player that what they've typed doesn't parse. I'm easily able to perform the necessary try parse test in the UITK version, but so far completely unable to have even the slightest impact on the color the god damn text input field. @tough jacinth suggested creating a custom style in the Unity editor and applying that, but I've not figured out how to make that work. Right now, what I've got is this.

#
document.rootVisualElement.Query<TextField>().ForEach(textField =>
{
  textField.RegisterCallback<FocusInEvent>(_ => GameManager.Instance?.Game?.Input.Disable());
  textField.RegisterCallback<FocusOutEvent>(_ => GameManager.Instance?.Game?.Input.Enable());
  textField.RegisterValueChangedCallback((evt) =>
  {
    bool pass = false;
    FlightPlanPlugin.Logger.LogInfo($"TryParse attempt for {textField.name}. Tooltip = {textField.tooltip}");
    if (textField.tooltip != "Time in hh:mm:ss format")
      pass = float.TryParse(evt.newValue, out _);
    else
      pass = TimeSpan.TryParse(evt.newValue, out _);
    if (pass)
    {
      // textField.style.color = Color.white;
      // textField.contentContainer.style.color = Color.white;
      textField.style.backgroundColor = Color.black;
      textField.style.borderBottomColor = Color.white;
      textField.style.borderTopColor = Color.white;
      textField.style.borderLeftColor = Color.white;
      textField.style.borderRightColor = Color.white;
      textField.style.unityTextOutlineColor = Color.white;
      FlightPlanPlugin.Logger.LogInfo($"TryParse success for {textField.name}. nValue = {evt.newValue}. setting color to white");
    }
    else
    {
      // textField.style.color = Color.red;
      // textField.contentContainer.style.color = Color.red;
      textField.style.backgroundColor = Color.red;
      textField.style.backgroundColor = Color.black;
      textField.style.borderBottomColor = Color.white;
      textField.style.borderTopColor = Color.white;
      textField.style.borderLeftColor = Color.white;
      textField.style.borderRightColor = Color.white;
      textField.style.unityTextOutlineColor = Color.white; FlightPlanPlugin.Logger.LogInfo($"TryParse failure for {textField.name}. nValue = {evt.newValue}. setting color to red");
    }
  });```
#

I first tied the commented out lines, but they had no effect, so I tried the new lines that follow those - which similarly have no effect.

#

Is there something in a textField that I can poke to set the color? I've explored around inside that stucture and not found anything yet. There's a customStyle field, but all I can to is get it, not set it. There's a Children() method, but it applied to VisualElements and I'm not sure how to use that.

shadow tree
#

have you tried just making a new class with the desired styles, making sure the text field with the class looks like you want it to in the builder, and then just adding/removing the class itself during runtime?

#

that's what I do in the mod list

marble shale
#

I have not. I'm not entirely certain I understand what you're suggesting.

#

Is this something that replaces TextField in the unity editor?

#

Like making my own custom control and then using that?

shadow tree
#

no, not at all

#

just a class

#

.red-textfield or whatever

marble shale
#

Oh good, that sounded like a lot of work.

shadow tree
#

USS class, not C# class

marble shale
#

I think you're suggesting something along the lines of what Falki suggested - possibly the exact same thing

#

I think I can make such a class, but I'm unclear what to do with it. Suppose I play around in the editor and make one and see in preview that it has the effect I want, what then?

#

How can I programmatically apply it?

shadow tree
#

element.AddToClassList("class-name");

#

and RemoveFromClassList

#

I'm assuming

#

you can just google if that exists, I'm not sure

marble shale
#

Ok, but I want to apply it to only the input field and not the label, however I've only got access to the whole enchilada.

shadow tree
#

well then just write the class so it affects only the input field

marble shale
marble shale
#

If I can accomplish that in the unity editor then I think I may actually be able to make this work. I'm going to go work on that.

shadow tree
#

yeah you can just do something like .unity-text-field.invalid > .unity-text-field__input {...}

#

maybe will need more specificity, not sure

#

gotta experiment with it

marble shale
#

Well, that's a good clue to get me started. As I tend to be pretty clueless with the stylesheet this helps me a lot.

#

OK! Getting somewhere! I've got this that seems to work when applied.

#

No effect...

    document.rootVisualElement.Query<TextField>().ForEach(textField =>
    {
      textField.RegisterCallback<FocusInEvent>(_ => GameManager.Instance?.Game?.Input.Disable());
      textField.RegisterCallback<FocusOutEvent>(_ => GameManager.Instance?.Game?.Input.Enable());
      textField.RegisterValueChangedCallback((evt) =>
      {
        bool pass = false;
        FlightPlanPlugin.Logger.LogInfo($"TryParse attempt for {textField.name}. Tooltip = {textField.tooltip}");
        if (textField.tooltip != "Time in hh:mm:ss format")
          pass = float.TryParse(evt.newValue, out _);
        else
          pass = TimeSpan.TryParse(evt.newValue, out _);
        if (pass)
        {
          textField.RemoveFromClassList(".unity-text-field-invalid");
          FlightPlanPlugin.Logger.LogInfo($"TryParse success for {textField.name}. nValue = {evt.newValue}. setting color to white");
        }
        else
        {
          textField.AddToClassList(".unity-text-field-invalid");
          textField.style.unityTextOutlineColor = Color.white; FlightPlanPlugin.Logger.LogInfo($"TryParse failure for {textField.name}. nValue = {evt.newValue}. setting color to red");
        }
      });
      textField.RegisterCallback<PointerDownEvent>(evt => evt.StopPropagation());
      textField.RegisterCallback<PointerUpEvent>(evt => evt.StopPropagation());
      textField.RegisterCallback<PointerMoveEvent>(evt => evt.StopPropagation());
    });```
#

I may be very close to getting this to work, but there's something I'm doing wrong here. I can drop that style onto the visual element I want it to effect and see the effect in preview, but in game nothing.

marble shale
#

With my new style class applied to one of the input text fields in the unity editor, the UI starts with that field red, but also doesn't remove the class when the field is parsing correctly

#

Similarly when messing with another text field that doesn't start with this class applied in the unity editor I get this

#

It seems I can apply this class in the unity editor and see exactly the effect I want, but I'm unable to add or remove it from the element in a way that makes the mod behave as I want. The logic for when to apply or remove is working fine, just not the AddToClassList or RemoveFromClassList

#
      textField.RegisterValueChangedCallback((evt) =>
      {
        bool pass = false;
        FlightPlanPlugin.Logger.LogInfo($"TryParse attempt for {textField.name}. Tooltip = {textField.tooltip}");
        if (textField.tooltip != "Time in hh:mm:ss format")
          pass = float.TryParse(evt.newValue, out _);
        else
          pass = TimeSpan.TryParse(evt.newValue, out _);
        if (pass)
        {
          textField.RemoveFromClassList(".unity-text-field-invalid");
          FlightPlanPlugin.Logger.LogInfo($"TryParse success for {textField.name}. nValue = '{evt.newValue}': Removed .unity-text-field-invalid from class list");
        }
        else
        {
          textField.AddToClassList(".unity-text-field-invalid");
          FlightPlanPlugin.Logger.LogInfo($"TryParse failure for {textField.name}. nValue = '{evt.newValue}': Added .unity-text-field-invalid to class list");
        }
      });```
#

Tried changing the Add/Remove to this, still no effect.

      textField.RegisterValueChangedCallback((evt) =>
      {
        bool pass = false;
        FlightPlanPlugin.Logger.LogInfo($"TryParse attempt for {textField.name}. Tooltip = {textField.tooltip}");
        if (textField.tooltip != "Time in hh:mm:ss format")
          pass = float.TryParse(evt.newValue, out _);
        else
          pass = TimeSpan.TryParse(evt.newValue, out _);
        if (pass)
        {
          textField.RemoveFromClassList(".unity-text-field-invalid > .unity-base-text-field__input");
          FlightPlanPlugin.Logger.LogInfo($"TryParse success for {textField.name}. nValue = '{evt.newValue}': Removed .unity-text-field-invalid from class list");
        }
        else
        {
          textField.AddToClassList(".unity-text-field-invalid > .unity-base-text-field__input");
          FlightPlanPlugin.Logger.LogInfo($"TryParse failure for {textField.name}. nValue = '{evt.newValue}': Added .unity-text-field-invalid to class list");
        }
      });```
#

@shadow tree / @dusty berry / @tough jacinth : Huzzah! It works! The trick, which wasn't apparent to me at first, is that you must not include the leading "." in the style name! This works!

      textField.RegisterValueChangedCallback((evt) =>
      {
        bool pass = false;
        FlightPlanPlugin.Logger.LogInfo($"TryParse attempt for {textField.name}. Tooltip = {textField.tooltip}");
        if (textField.tooltip != "Time in hh:mm:ss format")
          pass = float.TryParse(evt.newValue, out _);
        else
          pass = TimeSpan.TryParse(evt.newValue, out _);
        if (pass)
        {
          textField.RemoveFromClassList("unity-text-field-invalid");
          FlightPlanPlugin.Logger.LogInfo($"TryParse success for {textField.name}. nValue = '{evt.newValue}': Removed unity-text-field-invalid from class list");
        }
        else
        {
          textField.AddToClassList("unity-text-field-invalid");
          FlightPlanPlugin.Logger.LogInfo($"TryParse failure for {textField.name}. nValue = '{evt.newValue}': Added unity-text-field-invalid to class list");
          List<string> classList = new(textField.GetClasses());
          // FlightPlanPlugin.Logger.LogInfo($"{textField.name} classList = {classList}");
          for (int i = 0; i < classList.Count(); i++)
            FlightPlanPlugin.Logger.LogInfo($"{textField.name} Class {i} = {classList[i]}");
        }
      });```
#

Only by looking at all the classes applied was I able to deduce that the name in the Unity editor maps to a slightly different name in the game, and all that was needed was to remove the leading "." that I had to get this to work.

tough jacinth
#

nice!

marble shale
#

@shadow tree, I'm in the home stretch getting FP converted to UITK. The one thing remaining is in the Advanced Planetary Transfer option (which wasn't completely working before, but was at least generating porkchop plots). I've got things where if you click that button it will make a part of the UI visible that looks like what was being displayed previously, and even better it will report the "worker" progress in % as it computed the porkchop, but it's at that point that it falls appart.

#

I'm generating a 2D texture, and the opld IMGUI code is no beuno with the new UITK GUI. I'm looking for a way to assign the texture generated to be the background image of the visual element I've created for the plot.

#

Is that more or less the right approach?

shadow tree
#

no idea

#

but probably?

marble shale
#

Yeah, it's my guess and worth a shot, but so far I don't know how to even find where to set the background image

dusty berry
#

if im understanding it correctly

#

its pretty easy

marble shale
#

I can set it in Unity Editor obviously

dusty berry
#

so you have a texture2D generated at runtime and you can't seem to get it onto the visual element?

marble shale
#

Yes!

dusty berry
#

oh thats easy

#

i just need to get the right way

#

but basically

#

you just have to convert your texture2d Into a background image

marble shale
#
    public void DoGUI()
    {
      // old IMGUI way - don't do this!
      GUILayout.Box(_texture, GUIStyle.none, GUILayout.Width(_texture.width), GUILayout.Height(_texture.height));
      // do stuff to convert texture2d to background image
      // assign background image to visual element
      FpUiController.PorkchopDisplay.contentContainer.?```
#

So, DoGUI get's called to put the plot on there when event is repaint

#

The VisualElement I want to affect is FpUiController.PorkchopDisplay

dusty berry
#

Background.FromTexture2D(your texture here)

marble shale
#

something like this?

FpUiController.PorkchopDisplay.Background.FromTexture2D(_texture);```
#

Right now it's telling me there's no such thing as .Background in PorkchopDisplay

dusty berry
#

FpUiController.PorkchopDisplay.style.backgroundImage = Background.FromTexture2D(_texture);

marble shale
#

OK, cool! We're getting somewhere! What would the using be to get Background? It's not using UitkForKsp2.API;

#

Found it! using UnityEngine.UIElements;

#

No I just need to figure out how to get the mouse position in the visual element. The old IMGUI way was this...

      if (Event.current.type == EventType.Repaint)
      {
        HoveredPoint = null;
        Rect rect = GUILayoutUtility.GetLastRect();
        rect.x += 1;
        rect.y += 2;
        Vector2 mouse = Event.current.mousePosition;
        if (rect.Contains(mouse))
        {
          Vector2 pos = mouse - rect.position;
          HoveredPoint = new[] { (int)pos.x, (int)(rect.height - pos.y - 1) };
        }
        else
        {
          if (_mouseDown && _lastHoveredPoint != null)
          {
            // zoom the selection box if we leave the area when mouse is down
            ZoomSelectionBox(_lastHoveredPoint);
          }
        }```
#

I'm guessing there's a way to get the rect from the VisualElement, and then maybe the rest is about the same

#

This perhaps? We'll see

        // Rect rect = GUILayoutUtility.GetLastRect();
        Rect rect = FpUiController.PorkchopDisplay.contentRect;
dusty berry
#

is it a click

#

or do you want to know it at all times?

marble shale
#

At all time. As the user moves the mouse over the porkchop plot I'll be displaying the deltaV needed if they were to select that point

#

So I also need to know when the click a point, where did they click - but that should be the same as where is the mouse rn

#

There is this in the old MJ code

        if (_mouseDown)
        {
          //GUI.Box(new Rect(rect.x + Math.Min(SelectedPoint[0], HoveredPoint[0]),
          //    rect.y + rect.height - Math.Max(SelectedPoint[1], HoveredPoint[1]),
          //    Math.Abs(SelectedPoint[0] - HoveredPoint[0]),
          //    Math.Abs(SelectedPoint[1] - HoveredPoint[1])), "", _selectionStyle);
          FpUiController.PorkchopDisplay.contentRect = new Rect(rect.x + Math.Min(SelectedPoint[0], HoveredPoint[0]),
              rect.y + rect.height - Math.Max(SelectedPoint[1], HoveredPoint[1]),
              Math.Abs(SelectedPoint[0] - HoveredPoint[0]),
              Math.Abs(SelectedPoint[1] - HoveredPoint[1])), "", _selectionStyle);
        }```
#

Where I commented out the old MJ way and attempted to make it do the same in UITK - this is wrong...

#

I see that it doesn't want to let me set contentRect only get.

dusty berry
#

that

#

theres probably an easy way

#

with probably an event

#

but i havent played with it yet

marble shale
#

PROGRESS! And not the Russian spacecraft kind, either...

dusty berry
#

:D

#

its probably easy to follow the mouse's position btw

#

i can look at it in a bit

marble shale
#

Getting a lot closer! This works for getting the mouse position in the VisualElement

      if (Event.current.type == EventType.Repaint)
      {
        HoveredPoint = null;
        // Rect rect = GUILayoutUtility.GetLastRect();
        Rect rect = FpUiController.PorkchopDisplay.contentContainer.worldBound;
        rect.x += 1;
        rect.y += 2;
        Vector2 mouse = Event.current.mousePosition;
        if (rect.Contains(mouse))
        {
          Vector2 pos = mouse - rect.position;
          HoveredPoint = new[] { (int)pos.x, (int)(rect.height - pos.y - 1) };
          FlightPlanPlugin.Logger.LogInfo($"HoveredPoint: ({HoveredPoint[0]}, {HoveredPoint[1]})");
        }
        else
        {
          if (_mouseDown && _lastHoveredPoint != null)
          {
            // zoom the selection box if we leave the area when mouse is down
            ZoomSelectionBox(_lastHoveredPoint);
          }
        }
#

Turns out Rect rect = FpUiController.PorkchopDisplay.contentRect just get's you the size of the rect, but not where it is in the game's screen. By using .contentContainer.worldBound I can get where the VisualElement is on the screen and then use that to see if the mouse is inside it. I'm able to get logging out for the mouse position, and already it's updating the deltaV displaid accordingly, but so far no action when clicked.

marble shale
#

I need to make my FpUiController.PorkchopDisplay not draggable, but still able to let me know when the mouse is up or down. I'm doing something about like that with all my TextField objects in SetupDocument like this:

    document.rootVisualElement.Query<TextField>().ForEach(textField =>
    {
      textField.RegisterCallback<FocusInEvent>(_ => GameManager.Instance?.Game?.Input.Disable());
      textField.RegisterCallback<FocusOutEvent>(_ => GameManager.Instance?.Game?.Input.Enable());
      textField.RegisterValueChangedCallback((evt) =>
      {
        bool pass = false;
        FlightPlanPlugin.Logger.LogDebug($"TryParse attempt for {textField.name}. Tooltip = {textField.tooltip}");
        if (textField.tooltip != "Time in hh:mm:ss format")
          pass = float.TryParse(evt.newValue, out _);
        else
          pass = MyTryParse(evt.newValue, out _);
        if (pass)
        {
          textField.RemoveFromClassList("unity-text-field-invalid");
          FlightPlanPlugin.Logger.LogInfo($"TryParse success for {textField.name}, nValue = '{evt.newValue}': Removed unity-text-field-invalid from class list");
        }
        else
        {
          textField.AddToClassList("unity-text-field-invalid");
          FlightPlanPlugin.Logger.LogInfo($"TryParse failure for {textField.name}, nValue = '{evt.newValue}': Added unity-text-field-invalid to class list");
          FlightPlanPlugin.Logger.LogInfo($"document.rootVisualElement.transform.position.z = {document.rootVisualElement.transform.position.z}");
        }
      });
      textField.RegisterCallback<PointerDownEvent>(evt => evt.StopPropagation());
      textField.RegisterCallback<PointerUpEvent>(evt => evt.StopPropagation());
      textField.RegisterCallback<PointerMoveEvent>(evt => evt.StopPropagation());
    });```
#

Would it be possibly that all I need is something like PorkchopDisplay.RegisterCallback<PointerMoveEvent>(evt => evt.StopPropagation())?

#

Nope...

#

Curiously... This seems to be working, or getting me closer. I'm still able to get hovered points out and the zoom window code is trying to do something, but it's also bogging down with recalculation.

#
    PorkchopDisplay.RegisterCallback<PointerDownEvent>(evt => evt.StopPropagation());
    PorkchopDisplay.RegisterCallback<PointerUpEvent>(evt => evt.StopPropagation());
    PorkchopDisplay.RegisterCallback<PointerMoveEvent>(evt => evt.StopPropagation());```
shadow tree
#

well, you should probably have all the code inside those handlers, not split across multiple ones

#

so if you want something to keep happening while the mouse is down, do it in the first handler and then call StopPropagation

#

I think

#

well actually not really while the mouse is down, but you know what I mean

marble shale
#

Yeah... I see. I've been kinda focused on making what I've got work, but that gives me a bastardized blend of things since what I've got for this part was built to work with IMGUI

#

It's quite a mess right now. Due, in large part, to my not fully understanding what all of the MJ code is really trying to do and so I just try to find a UITK equivalent when what I probably need here is a full overhaul to just do it the new way period.

#

This is curious..

#

The interesting things here are that (a) the worker is getting called a lot to recalculate stuff, ans well as (b) that I'm able to zoom in - though it takes a lot longer than it should. The Reset button will get you back, though it takes longer than it should too

#

I had thought I was turning off the display for the worker when it wasn't needed, but maybe not?

tough jacinth
#

Offtopic, but, how do you get BepInEx's log in a separate window like that?

dusty berry
#

in its configuration

#

theres an option for that

#

idk if it shows in game, i always change that in the config folder

dusty berry
tough jacinth
marble shale
#

Hey, I've switched my font from JetBrains to Ariel, and added the ariel.ttf file to my font assets, but I'm getting this warning spamming my log
[Warning: Unity Log] Font not found for path: FontAssets/DynamicOSFontAssets/GlobalFallback/OSX/Arial SDF [Warning: Unity Log] Font not found for path: FontAssets/DynamicOSFontAssets/GlobalFallback/OSX/Arial SDF

#

This is kinda curious since it says it's using something from OSX, but I'm booted into Windows and my Windows install can't even see the OSX install I've got - but whatever.

#

I suspect what I need to do is to make or find and install an Ariel SDF, but I don't know how.

#

I expect I'll need to do that with another TTF I've installed.

#

@shadow tree what do I need to do here to make Unity happy?

#

Oh wait.. I think I found it! Create > Text > Font Asset, right?

shadow tree
#

yeah

#

the dynamic OS font assets stuff doesn't really mean anything

#

it just means that if a user has macOS and the font you want to use is not available, it will try to use the Arial font from the system

#

or something like that

marble shale
#

Curiously, as soon as I created the Ariel SDF it seemed to have picked that up. I didn't need to change this in the inspector.

#

But I did for my use of Orbitron Black here

shadow tree
#

by the way, I'm not 100% sure, but I think you shouldn't redistribute Arial and you'd need to buy a license to use the font that way

#

the fact that it comes for free with your OS only means that the maker of the OS paid for the license, but not you

marble shale
#

No, wait. I see what's going on... There's an Ariel.SDF that's in Unity, but I'm not sure it works. The one I made is ariel.SDF (lowercase)

shadow tree
#

you should be able to use the system-installed variant

marble shale
shadow tree
#

Liberation Sans might be better, since it's made to look the same as Arial, but it's free

marble shale
#

I saw that one, and it's a possibility

#

Here's a wierd thing. When I set the Font Asset in the inspector for a sytle I've got (.unity-label), it seems to be there, but if I move off that an back to it then it's gone and I see this.

#

I see the same thing wehn inspecting something that has .unity-label applied to it

shadow tree
#

by the way if you're setting Font Asset, you shouldn't/don't need to set the Font

shadow tree
marble shale
#

Why do they have both? Is it preferred or better to set the asset?

shadow tree
#

this explains it a bit

#

and just in general, I haven't had any luck getting "Font" to work, while "Font Asset" works just fine in-game

marble shale
#

OK, so use font assets is preferred, but it should work seemlessly regardless.

#

This is frustraiting. Setting Font Asset just does not take. I can set it, and it looks set, but even if I close with save, and reopen the GD thing is set to None

shadow tree
#

just try setting it manually in the USS then

marble shale
#

Setting Font is the only reliable way I've got to set it in the editor and actually have it stay f-ing set

marble shale
shadow tree
#

open your USS file, find the selector that you want to apply it to, and add -unity-font-definition: url("/Assets/your/path/font-asset-file.asset");

marble shale
#

So doing that in the editor may not work, but I should be able to hand jam it?

shadow tree
#

yeah I mean I can't help much with the editor, I've only written the USS by hand

marble shale
#

OMG, this stupid thing fucked over my title! Gaaaaaa!

#

Worse, it fucked it over before I did the close and save, so no amount of Ctrl Z will save me now...

#

I know now what was fucking it. It was setting the Font Asset to the one I created from the Orbitron TTF. Unsetting that make it work fine.

marble shale
#

@shadow tree , I've removed the ariel.ttf and SDF from my package, and hand edited FlightPlanTheme.uss to have zero references to ariel, replacing them all with references to LiberationSans (which is installed in the /Assets/Themes/Fonts folder). I'm getting a massive number of warnings (201) and some errors (7) when I build the project, and some of them refer to Ariel SDF. I'm kind of at a loss for how to even track these down. Double clicking on one of the Ariel warnings takes me to SetPropertyReader.cs.

#

I don't appear to have any references to ariel in the uxml either

#

loading the project gives me a smaller number of warnings (42), but a larger number of errors (13). Not sure what to do to track these down.

#

Oh, this is bizzare... the warning count is climbing, currently up to 132, and nearly every bit of text has now vanished in the Unity Editor Viewport...

#

Seems to be that it really doesn't like when I specify the font asset...

shadow tree
#

I mean I can see some references to Arial in the UXML file

#

Try to remove those

marble shale
#

That's weird, I did a search in it and didn't find them. I'll have to do that again - must have done it wrong

#

I see those now.

#

Must have typoed the search string

shadow tree
#

And styles set in UXML have precedence over the ones in USS files, so it would probably have an effect

marble shale
# shadow tree And styles set in UXML have precedence over the ones in USS files, so it would p...

This is really odd. the uxml says I've got arial in three places, two of which are my gui frame, and one is the tab heading. When I go into the Unity Editor though it doesn't show that in either of these. I could maybe hand edit these, but I'm not sure quite how to do that. Is it ok/safe to just delete the -unity-font-definition: resource(&apos;FontAssets/DynamicOSFontAssets/GlobalFallback/OSX/Arial SDF&apos;); portion of something like style="-unity-font-definition: resource(&apos;FontAssets/DynamicOSFontAssets/GlobalFallback/OSX/Arial SDF&apos;); -unity-font-style: bold;"

shadow tree
#

yeah, you can definitely delete that

marble shale
#

I've got a bunch of the Invalid value for font Keyword...

#

And building it I just got these

shadow tree
#

already built bundles and .cs files can't go into asset bundles

marble shale
#

Do you mean I shouldn't be putting my fonts into a folder like this within the project?

shadow tree
#

no, the files that are mentioned in the warnings such as Assets/ExposedControls.cs, Assets/Editor/CreateAssetBundles.cs, Assets/AssetBundles/kerbalui etc

#

they have an assigned bundle to be built into, but they can't go in it

bronze crater
#

there shouldn’t be anything from assetbundles included

marble shale
#

I honestly have no idea how those got into the bundle or where they are.

shadow tree
#

it's this thing in the inspector window

bronze crater
#

at the bottom*

shadow tree
#

there mustn't be any bundle assigned to those folders/files

marble shale
#

That's all I got

shadow tree
#

on the folders containing the files, too?

marble shale
#

Hmmm... I've got this

#

That's one of them found

bronze crater
#

what is the asset label for the “AssetBundle” folder

shadow tree
#

there could even be one on the Assets folder as a whole, technically

marble shale
#

I'm probably not understanding the question...

#

Or how to get the answer...

#

Going back to ExposedControls.cs, I believe I've got that (and need it) for radio buttons. Do I have it in the wrong folder or something?

#

kerbalui seems to be in the fp_ui.bundle.

#

Well... kerbalui.manifest that is

#

Should I be assigning the files in my AssetBundles folder to asset bundles?

shadow tree
#

no, what Unity is saying is that you are assigning files in AssetBundles to bundles, which you're not supposed to

#

and that you're doing that with the .cs files as well, which shouldn't go into bundles

#

in the first case it's because you can't put already compiled bundles into other bundles, and you can't put code into asset bundles, since that needs to be compiled into DLLs, not into asset bundles

shadow tree
# marble shale None?

here you clicked on the AssetBundles file, but try clicking just on the folder itself to see if it has a bundle assigned

#

and try to do the same for the other folders in which the issues pop up

#

so Assets, AssetBundles, Editor

marble shale
#

The folder itself is apparently unassigned

shadow tree
#

or if you don't mind, you can zip up the Assets folder and I can take a quick look for you

marble shale
#

Walking through the folders in Assets it seems UI TooKit is assigned to fp_ui.bundle, as is FlightPlanTheme.uss and FP_UI.uxml, but the others are all 'None'

shadow tree
#

so from what I can see, you have the file Assets/AssetBundles/kerbalui.manifest assigned to fp_ui.bundle

#

but that's all I could find

#

the rest should not be an issue as far as I can tell

marble shale
shadow tree
#

I mean, I don't think it will be an issue, but it doesn't belong in there

marble shale
#

Should I assign it to kerbalui?

shadow tree
#

nope, it's just file containing metadata about the already built kerbalui bundle

#

so it shouldn't go into any bundles

marble shale
#

OK it's set to None now

shadow tree
#

alright, so now the only way I can imagine those warnings popping up is if you had your whole Assets folder assigned to a bundle

#

no clue otherwise why they would be there

shadow tree
#

just click on Assets

marble shale
#

Yeah, I did that, but nothing opens in the inspector.

shadow tree
#

huh that's weird

marble shale
# shadow tree

Hey, I'm still stuck in font hell, or at least font purgatory... The copy of LiberationSans I first downloaded seemed to have been borked in that selecting any of the SDFs other than regular (bold, bolditallic, and itallic) would render fonts, but selecting regular would not - though specifiying the ttf would work as long as you don't also point to the SDF. I found a different (larger files) version that seems to work as an SDF, but I still get Invalid value for font Keyword warnings on opening the UI project in Unity editor, and also get spam in the log like this any time I move my mouse over various elements in the mod's UI
[Warning: Unity Log] Font not found for path: [Warning: Unity Log] Invalid value for font Keyword [Warning: Unity Log] Font not found for path: [Warning: Unity Log] Invalid value for font Keyword [Warning: Unity Log] Font not found for path: [Warning: Unity Log] Invalid value for font Keyword [Warning: Unity Log] Font not found for path: [Warning: Unity Log] Invalid value for font Keyword [Warning: Unity Log] Font not found for path: [Warning: Unity Log] Invalid value for font Keyword [Warning: Unity Log] Font not found for path: [Warning: Unity Log] Invalid value for font Keyword

#

They're only warnings, and the mod does render, but I'm not certain if it's rendering right.

dusty berry
#

why? any visual bugs?

shadow tree
#

are you setting only Font Asset or also Font?

marble shale
shadow tree
#

it should probably never be both at the same time, and Font Asset is preferred

marble shale
#

I'll try unsetting the Font. The last time I tried that I was using the borked SDF, so maybe that's it.

#

Though there's definitely a difference in how the UI renders in game vs. in the editor

marble shale
#

It seems like it may be my other font, Orbitron, that could be causing this. That's a shame. I really liked that font for the title bar.

shadow tree
#

I mean, if it works in-game, just ignore the warnings

marble shale
marble shale
# shadow tree I mean, if it works in-game, just ignore the warnings

Can I (should I) get rid of font assets I'm not using and have no intention of using like the JetBrains fonts? I may want to also get rid of the various LiberationSans and Obritron variants I'm not using, but I definitely don't want to use JetBrains and it's hanging out in my Fonts folder

shadow tree
#

oh your project is a customized clone of SpaceWarpUI right?

marble shale
#

Yep

#

Is that a bad way to go?

shadow tree
#

the newer and better way to do it is just to have an empty Unity project and install UitkForKsp2 as a Unity package

#

that way you'll only have your own files in your project

#

but it'd require you to make a new project and migrate your files over there

#

technically it shouldn't be too difficult, but it is some extra work

marble shale
#

I'm not completely opposed to that. I assume I could litterally drag the uxml and uss files over into the new project to jump start it.

shadow tree
#

yeah, along with all the corresponding manifest/meta files

marble shale
#

yes, of course those too. Just make a new project, drag over the old files, and press on?

#

I'm probably missing some bits in Step 1 (make a new project), but I think I understand steps 2 and 3

shadow tree
#

and then in File->Build Settings go to Player Settings and there switch color space to Linear

hollow tiger
#

(Or else you'll go insane)

shadow tree
#

ah don't even remind me of those literal months we spent trying to figure out the wrong colors

#

lmao

marble shale
#

For the new project, should I select 2D core or what for the template?

shadow tree
#

I think I just click on 3D empty

#

or core

#

or whatever it says

marble shale
#

Yeah, it was core. OK, I'll give this a shot. Seems like it should be easy.

#

FYI, that git is telling me it's v 1.3.0... Should it be 1.4.x?

shadow tree
#

oh I don't think the package had any updates in 1.4

#

so I didn't have to update it

marble shale
#

OK, cool. Steps 1, 2, and 3 complete. For bringing things over how much of what's in my old Assets folder should I be bringing over to the new one? Presumably the Icons folder for sure, and the Theme\Fonts folder. What about the other things? The old Scenes folder is actually empty, so nothing there to bring.

shadow tree
#

well, just everything that you added

#

no need to copy over anything that was already in there

#

you probably just need Editor (it has the script to build bundles), Icons, and a folder with your own Fonts (doesn't need to be in Theme)

#

and then of course all your uxml/uss files and their metadata

marble shale
#

Hmmm

#

What about things like Theme.meta?

shadow tree
#

well, ignore for now and see what the console says

#

the errors are in C# files

#

but Unity seems to be a bitch about it sometimes and all I needed to do to fix my issues last time was to add a space, let it recompile, and then go back and remove the space

#

lmao

marble shale
#

LOL, still have the Font keyword issues, but it seems to have loaded otherwise

#

I did have to fix the canvas size, not sure why

shadow tree
#

it doesn't carry over, I didn't even manage to find in which file it's actually set when I was looking for it

marble shale
#

And things that were docked are not... Do you hjappen to know how to dock UE windows? I don't recall now

#

Figured it out, just drag...

#

Canvas is definitely a bit goofed, but it seems to look OK otherwise

#

I'll try building the asset and see what I get!

#

Can't find the build asset thing when right clicking in the project. I closed and reopened and I've got the dumb warning dialog again...

#

I think I may be missing a step...

shadow tree
#

did you copy over the Editor folder?

marble shale
#

Also reopening sets the canvas size back down to 350 x 450....

#

I did

shadow tree
#

and the action is not in the Assets menu in the toolbar?

#

weird

marble shale
#

There's just one file Create Asset

shadow tree
marble shale
#

Nope, that option does not show up in the Assets menu or when right clicking in the project

shadow tree
#

any errors in the console that might be related?

marble shale
#

I've got Open C# Project though...

#

Very possibly

shadow tree
#

oh yeah that's the issue that I was talking about

#

honestly have no clue how to reliably get rid of that, since everything can actually compile fine, but Unity refuses to do it

#

what I did (I think) was I went and opened that file, modified it a couple of times and let Unity recompile, and then at some point it just started working

#

@dusty berry sorry for bothering you but any idea how to get rid of this in some better way?

dusty berry
#

let me check

shadow tree
#

what I usually do is create an assembly definition and remove it, or try editing some code back and forth to get Unity to recompile it properly

#

and in the end it always somehow fixes itself

dusty berry
#

you could try 2 things

  • add a line on some script thats on unity
  • reimport the uitkforksp2 package
#

if those works its just unity being dumb and import stuff in tthe wrong order

shadow tree
#

honestly this sort of stuff is why working with Unity is so frustrating to me

dusty berry
#

i think that maybe settings uitk as a dependency of uitkforksp2 might solve

shadow tree
#

it is

dusty berry
#

well, it doesnt happen normally

#

on normal projects none of this is a problem

shadow tree
#

why does it happen with all my Unity projects then nooooooooo

dusty berry
#

also UITK is experimental at this version so

shadow tree
#

SpaceWarpUI, KerbalUI, UitkForKsp2.Controls, now AppBar

#

lmao

#

all of them I had these issues, and many others

dusty berry
#

Well they are all mod projects xD

#

if you're building a game these usually dont happen

shadow tree
#

yeah but it's not like I have ThunderKit or anything

#

so it should be the same as building a game

dusty berry
#

still, you have a experimental package

shadow tree
#

I even did build the player version of the "game" couple of times to test

#

hm, true

dusty berry
#

you cant really blame unity if you're using an experimental package xD

#

thus me wanting so much to migrate to the 1.0 version

#

but its under a license

shadow tree
#

but still, this seems to me like a deeper underlying issue, since it's just Unity not being able to find referenced types and namespaces from a package that's installed

#

smh

dusty berry
#

agreed

#

but unity was never meant to work with multiple dlls

#

they kidna hacked its way into it

#

and only recently made it adn actual, properly implemented feature

shadow tree
#

I mean it's not even DLLs

#

the UITK package has the source code

#

not a DLL

dusty berry
#

huh true wtf

#

theres probably ways to fix this.

#

wait a sec

#

    "com.bbepis.bepinex": {
      "version": "file:BepInEx_KSP2",
      "depth": 0,
      "source": "embedded",
      "dependencies": {}
#

this is the package-lock

#

maybe if we set uitk as a dependency for uitkforksp2

#

tho im not sure how to do that

marble shale