Jump to content

Refresh Part menu to show new KSPField


Recommended Posts

Alright, I'm looking at a method to refresh a part's right click window.

The KSPField I want to show/hide is the UI_FloatEdit from KSPAPI Extentions.

Without any code of my own, when I change the UI_FloatEdit from .guiActive = false to .guiActive = true, the part window refreshes automatically and starts showing the UI_FloatEdit field.

However, when I change the UI_FloatEdit's .guiActive from true to false, the UI_FloatEdit stays visible until I refresh the right-click window manually by reopening it by right-clicking on the part again.

Does anyone know what is going on here? I need to either make it so the window refreshes itself both ways, or I need the code to manually refresh the part's right-click window myself.

Anyone have any ideas?

D.

Link to comment
Share on other sites

The main problem is that the list of opened windows is hidden so you can't access it without breaking some rules, but since the window prefab itself is exposed you can edit that to build yourself a way in:

// tracks open part windows
class PartActionWindows : MonoBehaviour
{
private static readonly List<UIPartActionWindow> Windows = new List<UIPartActionWindow>();

private void Start() { Windows.Add(gameObject.GetComponent<UIPartActionWindow>()); }

private void OnDestroy() { Windows.Remove(gameObject.GetComponent<UIPartActionWindow>()); }

public static List<UIPartActionWindow> Opened
{
get { return new List<UIPartActionWindow>(Windows); }
}

public static void UpdateWindows() { Opened.ForEach(window => window.displayDirty = true); }

public static void UpdateWindow(Part part)
{
var window = Opened.SingleOrDefault(w => ReferenceEquals(w.part, part));
if (window != null) window.displayDirty = true;
}
}


// test it on the mk1pod
[KSPAddon(KSPAddon.Startup.MainMenu, true)]
class InstallModule : MonoBehaviour
{
void Awake()
{
PartLoader.getPartInfoByName("mk1pod").partPrefab.AddModule("FloatEditTest");
}
}



[KSPAddon(KSPAddon.Startup.EditorAny, false)]
class AddWindowTracker : MonoBehaviour
{
void Start()
{
var prefab = UIPartActionController.Instance.windowPrefab;

if (prefab.GetComponent<PartActionWindows>() == null)
prefab.gameObject.AddComponent<PartActionWindows>();
}
}



class FloatEditTest : PartModule
{
[KSPField(isPersistant = true, guiActive = false, guiActiveEditor = false, guiName = "Test Name", guiUnits = "%",guiFormat = "F0"),
KSPAPIExtensions.UI_FloatEdit(minValue = 0f,
maxValue = 100f,
incrementLarge = 25f,
incrementSmall = 5f
)]
public float floatValue = 0f;

[KSPEvent(guiActive = true, guiName = "Toggle FloatEdit", guiActiveEditor = true)]
public void FloatEditToggle()
{
Fields["floatValue"].guiActiveEditor = !Fields["floatValue"].guiActiveEditor;
//PartActionWindows.UpdateWindows();
PartActionWindows.UpdateWindow(part);
}
}

I'm not sure if this is a bug with KSPAPI extensions or not (or even stock) but it seems that UI_FloatEdit will initially always be visible even if you set guiActive[Editor] to false (as in above code: the field is initially visible) so you might have to handle that case yourself

Edited by xEvilReeperx
Link to comment
Share on other sites

Thanks for that, will test as soon as I get home.

The odd thing is I'm actually getting inconsistent behavior which makes me suspect I've missed something.

My tests last night (after rewriting pretty much from scratch) showed different behavior that it no longer automatically showed itself when I went from .guiShowEditor = false to true like it did in my original tests. (It still did not show automatically on guiActive true to false so that did not change.)

I'm now wondering what I did different.

I was also running those tests after getting home from a big family dinner so I suspect it is something that is going to make me /headdesk when I figure it out.

D.

Link to comment
Share on other sites

  • 2 weeks later...

Alright, I've got this working.

Rather then doing Evil's approach above of hooking into the window so it executes as a window method, I set it up so I manually call the window refresh when I want to update.


//other code here that needs to update the window
refreshPartWindow();
//continue other code

private void refreshPartWindow() //AGX: Refresh right-click part window to show/hide Groups slider
{
UIPartActionWindow[] partWins = FindObjectsOfType<UIPartActionWindow>();
foreach(UIPartActionWindow partWin in partWins)
{
partWin.displayDirty = true;
}
}

Note that only open windows will be returned by the find objects line, 99% of the time there will only the one open so this is not a significant process load I don't think.

D.

Link to comment
Share on other sites

Alright, I've got this working.

Rather then doing Evil's approach above of hooking into the window so it executes as a window method, I set it up so I manually call the window refresh when I want to update.

Just to clarify: mine doesn't hook into a window method, it does what yours does (.displayDirty = true). It just avoids using the very slow FindObjectsOfType (11.5ms per call on my machine) method by keeping a static list of active windows.

Might be the paranoid C++ programmer in me in this case though ;)

Edited by xEvilReeperx
Link to comment
Share on other sites

Really? Hmmm.

I'll have another look at your code snippet, I don't think I fully understood it then.

Having said that, for this specific use I'm going to leave it as is because I'm editing someone else's mod I'd rather use the method I can encapsulate within the code I'm adding.

I will run some high partcount ships through as a test to make sure the performance hit is not a big deal though.

D.

Link to comment
Share on other sites

As long as you're not running it every frame, you'll be okay. High part count ships shouldn't matter that much; it's a matter of searching ~18,000 items for a 1 part ship versus maybe ~18,900-~20,000 for a fairly large ship.

The problem comes when somebody uses it in an Update(): 11.5ms is enough to take a game running at 50 fps down to 31 fps all for the sake of a little button

Link to comment
Share on other sites

Ah, no. It runs once when the UI Slider is set to action groups to show the second slider to select a group, and once when the UI Slider moves to something else to hide the second slider.

Sounds like I'll be okay for now then. Still going to take another look at your code to actually understand it, FindObjectsOfType is something I'd rather not have as my go-to option.

D.

Link to comment
Share on other sites

This thread is quite old. Please consider starting a new thread rather than reviving this one.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...