Example #1
0
        /// <summary>
        /// Update a blended color.
        /// </summary>
        private void UpdateBlendColor()
        {
            Color32 newColor = Color32.Lerp(passiveColor, activeColor, currentBlend);

            textObj.SetColor(newColor);

            textObj.material.SetFloat(emissiveFactorIndex, currentBlend);
        }
 /// <summary>
 /// Enable and position the appropriate text object for rendering.
 /// </summary>
 /// <param name="showPage">Are we showing the page (true) or hiding it (false)?</param>
 internal void RenderPage(bool showPage)
 {
     if (showPage)
     {
         if (enabled)
         {
             if (active)
             {
                 activeText.SetRenderEnabled(true);
                 // Since I alias activeText and passiveText, I have to update
                 // the colors here.  Maybe I should simple create active and
                 // passive instances from the activeText, but that can
                 // double the number of texts that need updated.
                 activeText.SetColor(activeColor);
             }
             else
             {
                 passiveText.SetRenderEnabled(true);
                 passiveText.SetColor(passiveColor);
             }
         }
         else
         {
             if (usesDisabled)
             {
                 disabledText.SetRenderEnabled(true);
             }
             else
             {
                 if (active)
                 {
                     activeText.SetRenderEnabled(true);
                     activeText.SetColor(activeColor);
                 }
                 else
                 {
                     passiveText.SetRenderEnabled(true);
                     passiveText.SetColor(passiveColor);
                 }
             }
         }
     }
     else
     {
         activeText.SetRenderEnabled(false);
         passiveText.SetRenderEnabled(false);
         if (usesDisabled)
         {
             disabledText.SetRenderEnabled(false);
         }
     }
 }
Example #3
0
        internal MASComponentTextLabel(ConfigNode config, InternalProp prop, MASFlightComputer comp)
            : base(config, prop, comp)
        {
            string transform = string.Empty;

            if (!config.TryGetValue("transform", ref transform))
            {
                throw new ArgumentException("Missing 'transform' in TEXT_LABEL " + name);
            }

            string fontName = string.Empty;

            if (!config.TryGetValue("font", ref fontName))
            {
                throw new ArgumentException("Invalid or missing 'font' in TEXT_LABEL " + name);
            }

            string    styleStr = string.Empty;
            FontStyle style    = FontStyle.Normal;

            if (config.TryGetValue("style", ref styleStr))
            {
                style = MdVTextMesh.FontStyle(styleStr);
            }

            string text = string.Empty;

            if (!config.TryGetValue("text", ref text))
            {
                throw new ArgumentException("Invalid or missing 'text' in TEXT_LABEL " + name);
            }

            if (!config.TryGetValue("fontSize", ref fontSize))
            {
                throw new ArgumentException("Invalid or missing 'fontSize' in TEXT_LABEL " + name);
            }

            Vector2 transformOffset = Vector2.zero;

            if (!config.TryGetValue("transformOffset", ref transformOffset))
            {
                transformOffset = Vector2.zero;
            }

            Transform textObjTransform = prop.FindModelTransform(transform);
            Vector3   localScale       = prop.transform.localScale;

            Transform offsetTransform = new GameObject().transform;

            offsetTransform.gameObject.name  = Utility.ComposeObjectName(this.GetType().Name, name, prop.propID);
            offsetTransform.gameObject.layer = textObjTransform.gameObject.layer;
            offsetTransform.SetParent(textObjTransform, false);
            offsetTransform.Translate(transformOffset.x * localScale.x, transformOffset.y * localScale.y, 0.0f);

            textObj = offsetTransform.gameObject.AddComponent <MdVTextMesh>();

            Font font = MASLoader.GetFont(fontName.Trim());

            if (font == null)
            {
                throw new ArgumentNullException("Unable to load font " + fontName + " in TEXT_LABEL " + name);
            }

            float lineSpacing = 1.0f;

            if (!config.TryGetValue("lineSpacing", ref lineSpacing))
            {
                lineSpacing = 1.0f;
            }

            float sizeScalar = 32.0f / (float)font.fontSize;

            textObj.SetFont(font, font.fontSize, fontSize * 0.00005f * sizeScalar);
            textObj.SetLineSpacing(lineSpacing);
            textObj.fontStyle = style;

            string passiveColorStr = string.Empty;

            if (!config.TryGetValue("passiveColor", ref passiveColorStr))
            {
                throw new ArgumentException("Invalid or missing 'passiveColor' in TEXT_LABEL " + name);
            }
            else
            {
                Color32 namedColor;
                if (comp.TryGetNamedColor(passiveColorStr, out namedColor))
                {
                    passiveColor = namedColor;
                }
                else
                {
                    string[] startColors = Utility.SplitVariableList(passiveColorStr);
                    if (startColors.Length < 3 || startColors.Length > 4)
                    {
                        throw new ArgumentException("passiveColor does not contain 3 or 4 values in TEXT_LABEL " + name);
                    }

                    variableRegistrar.RegisterVariableChangeCallback(startColors[0], (double newValue) =>
                    {
                        passiveColor.r = Mathf.Clamp01((float)newValue * (1.0f / 255.0f));
                        if (blend)
                        {
                            UpdateBlendColor();
                        }
                        else
                        {
                            UpdateBooleanColor();
                        }
                    });

                    variableRegistrar.RegisterVariableChangeCallback(startColors[1], (double newValue) =>
                    {
                        passiveColor.g = Mathf.Clamp01((float)newValue * (1.0f / 255.0f));
                        if (blend)
                        {
                            UpdateBlendColor();
                        }
                        else
                        {
                            UpdateBooleanColor();
                        }
                    });

                    variableRegistrar.RegisterVariableChangeCallback(startColors[2], (double newValue) =>
                    {
                        passiveColor.b = Mathf.Clamp01((float)newValue * (1.0f / 255.0f));
                        if (blend)
                        {
                            UpdateBlendColor();
                        }
                        else
                        {
                            UpdateBooleanColor();
                        }
                    });

                    if (startColors.Length == 4)
                    {
                        variableRegistrar.RegisterVariableChangeCallback(startColors[3], (double newValue) =>
                        {
                            passiveColor.a = Mathf.Clamp01((float)newValue * (1.0f / 255.0f));
                            if (blend)
                            {
                                UpdateBlendColor();
                            }
                            else
                            {
                                UpdateBooleanColor();
                            }
                        });
                    }
                }
            }
            // Final validations
            bool   usesMulticolor = false;
            string activeColorStr = string.Empty;

            if (config.TryGetValue("activeColor", ref activeColorStr))
            {
                usesMulticolor = true;

                Color32 namedColor;
                if (comp.TryGetNamedColor(activeColorStr, out namedColor))
                {
                    activeColor = namedColor;
                }
                else
                {
                    string[] startColors = Utility.SplitVariableList(activeColorStr);
                    if (startColors.Length < 3 || startColors.Length > 4)
                    {
                        throw new ArgumentException("activeColor does not contain 3 or 4 values in TEXT_LABEL " + name);
                    }

                    variableRegistrar.RegisterVariableChangeCallback(startColors[0], (double newValue) =>
                    {
                        activeColor.r = Mathf.Clamp01((float)newValue * (1.0f / 255.0f));
                        if (blend)
                        {
                            UpdateBlendColor();
                        }
                        else
                        {
                            UpdateBooleanColor();
                        }
                    });

                    variableRegistrar.RegisterVariableChangeCallback(startColors[1], (double newValue) =>
                    {
                        activeColor.g = Mathf.Clamp01((float)newValue * (1.0f / 255.0f));
                        if (blend)
                        {
                            UpdateBlendColor();
                        }
                        else
                        {
                            UpdateBooleanColor();
                        }
                    });

                    variableRegistrar.RegisterVariableChangeCallback(startColors[2], (double newValue) =>
                    {
                        activeColor.b = Mathf.Clamp01((float)newValue * (1.0f / 255.0f));
                        if (blend)
                        {
                            UpdateBlendColor();
                        }
                        else
                        {
                            UpdateBooleanColor();
                        }
                    });

                    if (startColors.Length == 4)
                    {
                        variableRegistrar.RegisterVariableChangeCallback(startColors[3], (double newValue) =>
                        {
                            activeColor.a = Mathf.Clamp01((float)newValue * (1.0f / 255.0f));
                            if (blend)
                            {
                                UpdateBlendColor();
                            }
                            else
                            {
                                UpdateBooleanColor();
                            }
                        });
                    }
                }
            }

            string anchor = string.Empty;

            if (!config.TryGetValue("anchor", ref anchor))
            {
                anchor = string.Empty;
            }

            if (!string.IsNullOrEmpty(anchor))
            {
                if (anchor == TextAnchor.LowerCenter.ToString())
                {
                    textObj.anchor = TextAnchor.LowerCenter;
                }
                else if (anchor == TextAnchor.LowerLeft.ToString())
                {
                    textObj.anchor = TextAnchor.LowerLeft;
                }
                else if (anchor == TextAnchor.LowerRight.ToString())
                {
                    textObj.anchor = TextAnchor.LowerRight;
                }
                else if (anchor == TextAnchor.MiddleCenter.ToString())
                {
                    textObj.anchor = TextAnchor.MiddleCenter;
                }
                else if (anchor == TextAnchor.MiddleLeft.ToString())
                {
                    textObj.anchor = TextAnchor.MiddleLeft;
                }
                else if (anchor == TextAnchor.MiddleRight.ToString())
                {
                    textObj.anchor = TextAnchor.MiddleRight;
                }
                else if (anchor == TextAnchor.UpperCenter.ToString())
                {
                    textObj.anchor = TextAnchor.UpperCenter;
                }
                else if (anchor == TextAnchor.UpperLeft.ToString())
                {
                    textObj.anchor = TextAnchor.UpperLeft;
                }
                else if (anchor == TextAnchor.UpperRight.ToString())
                {
                    textObj.anchor = TextAnchor.UpperRight;
                }
                else
                {
                    Utility.LogError(this, "Unrecognized anchor '{0}' in config for {1} ({2})", anchor, prop.propID, prop.propName);
                }
            }

            string alignment = string.Empty;

            if (!config.TryGetValue("alignment", ref alignment))
            {
                alignment = string.Empty;
            }
            if (!string.IsNullOrEmpty(alignment))
            {
                if (alignment == TextAlignment.Center.ToString())
                {
                    textObj.alignment = TextAlignment.Center;
                }
                else if (alignment == TextAlignment.Left.ToString())
                {
                    textObj.alignment = TextAlignment.Left;
                }
                else if (alignment == TextAlignment.Right.ToString())
                {
                    textObj.alignment = TextAlignment.Right;
                }
                else
                {
                    Utility.LogError(this, "Unrecognized alignment '{0}' in config for {1} ({2})", alignment, prop.propID, prop.propName);
                }
            }

            string emissive = string.Empty;

            config.TryGetValue("emissive", ref emissive);

            if (string.IsNullOrEmpty(emissive))
            {
                if (usesMulticolor)
                {
                    emissiveMode = EmissiveMode.active;
                }
                else
                {
                    emissiveMode = EmissiveMode.always;
                }
            }
            else if (emissive.ToLower() == EmissiveMode.always.ToString())
            {
                emissiveMode = EmissiveMode.always;
            }
            else if (emissive.ToLower() == EmissiveMode.never.ToString())
            {
                emissiveMode = EmissiveMode.never;
            }
            else if (emissive.ToLower() == EmissiveMode.active.ToString())
            {
                emissiveMode = EmissiveMode.active;
            }
            else if (emissive.ToLower() == EmissiveMode.passive.ToString())
            {
                emissiveMode = EmissiveMode.passive;
            }
            else if (emissive.ToLower() == EmissiveMode.flash.ToString())
            {
                emissiveMode = EmissiveMode.flash;
            }
            else
            {
                Utility.LogError(this, "Unrecognized emissive mode '{0}' in config for {1} ({2})", emissive, prop.propID, prop.propName);
                emissiveMode = EmissiveMode.always;
            }

            string variableName = string.Empty;

            if (!config.TryGetValue("variable", ref variableName) || string.IsNullOrEmpty(variableName))
            {
                if (usesMulticolor)
                {
                    throw new ArgumentException("Invalid or missing 'variable' in TEXT_LABEL " + name);
                }
            }
            else if (!usesMulticolor)
            {
                throw new ArgumentException("Invalid or missing 'activeColor' in TEXT_LABEL " + name);
            }

            config.TryGetValue("blend", ref blend);

            if (emissiveMode == EmissiveMode.flash)
            {
                if (blend == false && config.TryGetValue("flashRate", ref flashRate) && flashRate > 0.0f)
                {
                    this.comp = comp;
                    comp.RegisterFlashCallback(flashRate, FlashToggle);
                }
                else
                {
                    emissiveMode = EmissiveMode.active;
                }
            }

            bool immutable = false;

            if (!config.TryGetValue("oneshot", ref immutable))
            {
                immutable = false;
            }

            textObj.SetColor(passiveColor);
            textObj.SetText(text, immutable, false, comp, prop);

            UpdateShader();

            if (!string.IsNullOrEmpty(variableName))
            {
                variableRegistrar.RegisterVariableChangeCallback(variableName, VariableCallback);
            }
        }
Example #4
0
        internal MASPageText(ConfigNode config, InternalProp prop, MASFlightComputer comp, MASMonitor monitor, Transform pageRoot, float depth)
            : base(config, prop, comp)
        {
            if (!config.TryGetValue("text", ref text))
            {
                string textfile = string.Empty;
                if (!config.TryGetValue("textfile", ref textfile))
                {
                    string rpmModText = string.Empty;
                    if (!config.TryGetValue("textmethod", ref rpmModText))
                    {
                        throw new ArgumentException("Unable to find 'text', 'textfile', or 'textmethod' in TEXT " + name);
                    }

                    string[] rpmMod = rpmModText.Split(':');
                    if (rpmMod.Length != 2)
                    {
                        throw new ArgumentException("Invalid 'textmethod' in TEXT " + name);
                    }
                    bool moduleFound = false;

                    int numModules = prop.internalModules.Count;
                    int moduleIndex;
                    for (moduleIndex = 0; moduleIndex < numModules; ++moduleIndex)
                    {
                        if (prop.internalModules[moduleIndex].ClassName == rpmMod[0])
                        {
                            moduleFound = true;
                            break;
                        }
                    }

                    if (moduleFound)
                    {
                        rpmModule = prop.internalModules[moduleIndex];
                        Type       moduleType = prop.internalModules[moduleIndex].GetType();
                        MethodInfo method     = moduleType.GetMethod(rpmMod[1]);
                        if (method != null && method.GetParameters().Length == 2 && method.GetParameters()[0].ParameterType == typeof(int) && method.GetParameters()[1].ParameterType == typeof(int))
                        {
                            rpmModuleTextMethod = DynamicMethodFactory.CreateFunc <object, int, int, string>(method);
                        }
                    }

                    if (rpmModuleTextMethod != null)
                    {
                        this.comp = comp;
                        this.prop = prop;
                    }
                    text = " ";
                }
                else
                {
                    // Load text
                    text = string.Join(Environment.NewLine, File.ReadAllLines(KSPUtil.ApplicationRootPath + "GameData/" + textfile.Trim(), Encoding.UTF8));
                }
            }

            string localFonts = string.Empty;

            if (!config.TryGetValue("font", ref localFonts))
            {
                localFonts = string.Empty;
            }

            string    styleStr = string.Empty;
            FontStyle style    = FontStyle.Normal;

            if (config.TryGetValue("style", ref styleStr))
            {
                style = MdVTextMesh.FontStyle(styleStr);
            }
            else
            {
                style = monitor.defaultStyle;
            }

            Vector2 fontSize = Vector2.zero;

            if (!config.TryGetValue("fontSize", ref fontSize) || fontSize.x < 0.0f || fontSize.y < 0.0f)
            {
                fontSize = monitor.fontSize;
            }

            Color32 textColor;
            string  textColorStr = string.Empty;

            if (!config.TryGetValue("textColor", ref textColorStr) || string.IsNullOrEmpty(textColorStr))
            {
                textColor = monitor.textColor_;
            }
            else
            {
                textColor = Utility.ParseColor32(textColorStr, comp);
            }

            // Position is based on default font size
            fontScale = monitor.fontSize;
            // Position is based on local font size.
            //fontScale = fontSize;

            string variableName = string.Empty;

            if (config.TryGetValue("variable", ref variableName))
            {
                variableName = variableName.Trim();
            }

            // Set up our text.
            imageOrigin = pageRoot.position + new Vector3(monitor.screenSize.x * -0.5f, monitor.screenSize.y * 0.5f, depth);

            meshObject                    = new GameObject();
            meshObject.name               = Utility.ComposeObjectName(pageRoot.gameObject.name, this.GetType().Name, name, (int)(-depth / MASMonitor.depthDelta));
            meshObject.layer              = pageRoot.gameObject.layer;
            meshObject.transform.parent   = pageRoot;
            meshObject.transform.position = imageOrigin;

            string positionString = string.Empty;

            if (config.TryGetValue("position", ref positionString))
            {
                string[] positions = Utility.SplitVariableList(positionString);
                if (positions.Length != 2)
                {
                    throw new ArgumentException("position does not contain 2 values in TEXT " + name);
                }

                variableRegistrar.RegisterVariableChangeCallback(positions[0], (double newValue) =>
                {
                    position.x = (float)newValue * fontScale.x;
                    meshObject.transform.position = imageOrigin + new Vector3(position.x, -position.y, 0.0f);
                });

                variableRegistrar.RegisterVariableChangeCallback(positions[1], (double newValue) =>
                {
                    position.y = (float)newValue * fontScale.y;
                    meshObject.transform.position = imageOrigin + new Vector3(position.x, -position.y, 0.0f);
                });
            }

            textObj = meshObject.gameObject.AddComponent <MdVTextMesh>();

            Font font;

            if (string.IsNullOrEmpty(localFonts))
            {
                font = monitor.defaultFont;
            }
            else
            {
                font = MASLoader.GetFont(localFonts.Trim());
            }

            // We want to use a different shader for monitor displays.
            textObj.material = new Material(MASLoader.shaders["MOARdV/TextMonitor"]);
            textObj.SetFont(font, fontSize);
            textObj.SetColor(textColor);
            textObj.material.SetFloat(Shader.PropertyToID("_EmissiveFactor"), 1.0f);
            textObj.fontStyle = style;

            // text, immutable, preserveWhitespace, comp, prop
            textObj.SetText(text, false, true, comp, prop);
            RenderPage(false);

            if (!string.IsNullOrEmpty(variableName))
            {
                // Disable the mesh if we're in variable mode
                meshObject.SetActive(false);
                variableRegistrar.RegisterVariableChangeCallback(variableName, VariableCallback);
            }
            else
            {
                currentState = true;
            }

            if (rpmModuleTextMethod != null)
            {
                comp.StartCoroutine(TextMethodUpdate());
            }
        }
        internal MASPageMenu(ConfigNode config, InternalProp prop, MASFlightComputer comp, MASMonitor monitor, Transform pageRoot, float depth)
            : base(config, prop, comp)
        {
            this.prop = prop;
            this.comp = comp;

            if (!config.TryGetValue("maxLines", ref maxLines))
            {
                maxLines = int.MaxValue;
            }
            if (maxLines < 1)
            {
                throw new ArgumentException("'maxLines' must be greater than zero in MENU " + name);
            }

            int itemPositionShift = 0;

            if (!config.TryGetValue("itemPositionShift", ref itemPositionShift))
            {
                itemPositionShift = 0;
            }

            if (!config.TryGetValue("cursorPersistentName", ref cursorPersistentName))
            {
                throw new ArgumentException("Missing 'cursorPersistentName' in MENU " + name);
            }

            config.TryGetValue("upSoftkey", ref upSoftkey);
            config.TryGetValue("downSoftkey", ref downSoftkey);
            config.TryGetValue("enterSoftkey", ref enterSoftkey);
            config.TryGetValue("homeSoftkey", ref homeSoftkey);
            config.TryGetValue("endSoftkey", ref endSoftkey);

            string localFonts = string.Empty;

            if (!config.TryGetValue("font", ref localFonts))
            {
                localFonts = string.Empty;
            }

            string styleStr = string.Empty;

            style = FontStyle.Normal;
            if (config.TryGetValue("style", ref styleStr))
            {
                style = MdVTextMesh.FontStyle(styleStr);
            }
            else
            {
                style = monitor.defaultStyle;
            }

            fontSize = Vector2.zero;
            if (!config.TryGetValue("fontSize", ref fontSize) || fontSize.x < 0.0f || fontSize.y < 0.0f)
            {
                fontSize = monitor.fontSize;
            }

            charAdvance = fontSize.x * itemPositionShift;
            lineAdvance = fontSize.y;

            defaultColor = monitor.textColor_;

            Color32 cursorColor;
            string  cursorColorStr = string.Empty;

            if (!config.TryGetValue("cursorColor", ref cursorColorStr) || string.IsNullOrEmpty(cursorColorStr))
            {
                cursorColor = monitor.textColor_;
            }
            else
            {
                cursorColor = Utility.ParseColor32(cursorColorStr, comp);
            }

            // Set up our text.
            textOrigin = pageRoot.position + new Vector3(monitor.screenSize.x * -0.5f, monitor.screenSize.y * 0.5f, depth);

            rootObject                    = new GameObject();
            rootObject.name               = Utility.ComposeObjectName(pageRoot.gameObject.name, this.GetType().Name, name, (int)(-depth / MASMonitor.depthDelta));
            rootObject.layer              = pageRoot.gameObject.layer;
            rootObject.transform.parent   = pageRoot;
            rootObject.transform.position = textOrigin;

            string positionString = string.Empty;

            if (config.TryGetValue("position", ref positionString))
            {
                string[] positions = Utility.SplitVariableList(positionString);
                if (positions.Length != 2)
                {
                    throw new ArgumentException("position does not contain 2 values in MENU " + name);
                }

                variableRegistrar.RegisterVariableChangeCallback(positions[0], (double newValue) =>
                {
                    position.x = (float)newValue * monitor.fontSize.x;
                    rootObject.transform.position = textOrigin + new Vector3(position.x, -position.y, 0.0f);
                    updateMenu = true;
                });

                variableRegistrar.RegisterVariableChangeCallback(positions[1], (double newValue) =>
                {
                    position.y = (float)newValue * monitor.fontSize.y;
                    rootObject.transform.position = textOrigin + new Vector3(position.x, -position.y, 0.0f);
                    updateMenu = true;
                });
            }

            if (string.IsNullOrEmpty(localFonts))
            {
                font = monitor.defaultFont;
            }
            else
            {
                font = MASLoader.GetFont(localFonts.Trim());
            }

            cursorObject                    = new GameObject();
            cursorObject.name               = rootObject.name + "_cursor";
            cursorObject.layer              = rootObject.layer;
            cursorObject.transform.parent   = rootObject.transform;
            cursorObject.transform.position = textOrigin;

            cursorText          = cursorObject.AddComponent <MdVTextMesh>();
            cursorText.material = new Material(MASLoader.shaders["MOARdV/TextMonitor"]);
            cursorText.SetFont(font, fontSize);
            cursorText.SetColor(cursorColor);
            cursorText.material.SetFloat(Shader.PropertyToID("_EmissiveFactor"), 1.0f);
            cursorText.fontStyle = style;

            string cursorPrompt = string.Empty;

            config.TryGetValue("cursor", ref cursorPrompt);
            // text, immutable, preserveWhitespace, comp, prop
            cursorText.SetText(cursorPrompt, false, true, comp, prop);

            string itemCountStr = string.Empty;

            config.TryGetValue("itemCount", ref itemCountStr);

            List <MenuItem> itemNodes = new List <MenuItem>();

            ConfigNode[] menuItemConfigNodes = config.GetNodes("ITEM");
            foreach (ConfigNode itemNode in menuItemConfigNodes)
            {
                try
                {
                    MenuItem cpt = new MenuItem(itemNode, rootObject, font, fontSize, style, defaultColor, comp, prop, variableRegistrar, itemNodes.Count);
                    itemNodes.Add(cpt);
                }
                catch (Exception e)
                {
                    Utility.LogError(this, "Exception creating ITEM in MENU " + name);
                    Utility.LogError(this, e.ToString());
                }
            }
            if (itemNodes.Count == 0)
            {
                throw new ArgumentException("No valid ITEM nodes in MENU " + name);
            }
            menuItems = itemNodes.ToArray();
            if (string.IsNullOrEmpty(itemCountStr))
            {
                numMenuItems = menuItems.Length;

                softkeyUpAction   = comp.GetAction(string.Format("fc.AddPersistentWrapped(\"{0}\", -1, 0, {1})", cursorPersistentName, numMenuItems), prop);
                softkeyDownAction = comp.GetAction(string.Format("fc.AddPersistentWrapped(\"{0}\", 1, 0, {1})", cursorPersistentName, numMenuItems), prop);
                softkeyEndAction  = comp.GetAction(string.Format("fc.SetPersistent(\"{0}\", {1})", cursorPersistentName, numMenuItems - 1), prop);
            }
            else if (itemNodes.Count > 1)
            {
                throw new ArgumentException("Only one valid ITEM node may be used in dynamic MENU " + name);
            }
            else
            {
                dynamicMenuTemplate = menuItemConfigNodes[0].CreateCopy();
            }

            variableRegistrar.RegisterVariableChangeCallback(string.Format("fc.GetPersistentAsNumber(\"{0}\")", cursorPersistentName), CursorMovedCallback);
            softkeyHomeAction = comp.GetAction(string.Format("fc.SetPersistent(\"{0}\", 0)", cursorPersistentName), prop);

            if (!string.IsNullOrEmpty(itemCountStr))
            {
                variableRegistrar.RegisterVariableChangeCallback(itemCountStr, MenuCountCallback);
            }

            string masterVariableName = string.Empty;

            if (config.TryGetValue("variable", ref masterVariableName))
            {
                rootObject.SetActive(false);

                variableRegistrar.RegisterVariableChangeCallback(masterVariableName, VariableCallback);
            }
            else
            {
                currentState = true;
                rootObject.SetActive(true);
            }

            RenderPage(false);
        }
            internal MenuItem(ConfigNode itemNode, GameObject rootObject, Font font, Vector2 fontSize, FontStyle style, Color32 defaultColor, MASFlightComputer comp, InternalProp prop, VariableRegistrar variableRegistrar, int itemId)
            {
                string itemIdStr = itemId.ToString();

                if (!itemNode.TryGetValue("name", ref name))
                {
                    name = "anonymous";
                }

                string selectEventStr = string.Empty;

                if (itemNode.TryGetValue("selectEvent", ref selectEventStr))
                {
                    selectEventStr = selectEventStr.Replace("%ITEMID%", itemIdStr);
                    selectEvent    = comp.GetAction(selectEventStr, prop);
                }

                enabled = true;

                string activeColorStr = string.Empty;

                if (!itemNode.TryGetValue("activeColor", ref activeColorStr) || string.IsNullOrEmpty(activeColorStr))
                {
                    activeColor = defaultColor;
                }
                else
                {
                    activeColor = Utility.ParseColor32(activeColorStr, comp);
                }

                string activeTextStr = string.Empty;

                if (!itemNode.TryGetValue("activeText", ref activeTextStr))
                {
                    throw new ArgumentException("Missing 'activeText' in ITEM " + name);
                }
                activeTextStr = activeTextStr.Replace("%ITEMID%", itemIdStr);

                activeObject                    = new GameObject();
                activeObject.name               = rootObject.name + "_activeitem_" + name;
                activeObject.layer              = rootObject.layer;
                activeObject.transform.parent   = rootObject.transform;
                activeObject.transform.position = rootObject.transform.position;

                activeText          = activeObject.AddComponent <MdVTextMesh>();
                activeText.material = new Material(MASLoader.shaders["MOARdV/TextMonitor"]);
                activeText.SetFont(font, fontSize);
                activeText.SetColor(activeColor);
                activeText.material.SetFloat(Shader.PropertyToID("_EmissiveFactor"), 1.0f);
                activeText.fontStyle = style;
                activeText.SetText(activeTextStr, false, true, comp, prop);
                activeText.SetRenderEnabled(false);

                string passiveColorStr = string.Empty;

                if (!itemNode.TryGetValue("passiveColor", ref passiveColorStr) || string.IsNullOrEmpty(passiveColorStr))
                {
                    passiveColor = activeColor;
                }
                else
                {
                    passiveColor = Utility.ParseColor32(passiveColorStr, comp);
                }

                string passiveTextStr = string.Empty;

                if (!itemNode.TryGetValue("passiveText", ref passiveTextStr))
                {
                    passiveObject = activeObject;
                    passiveText   = activeText;
                }
                else
                {
                    passiveTextStr = passiveTextStr.Replace("%ITEMID%", itemIdStr);

                    passiveObject                    = new GameObject();
                    passiveObject.name               = rootObject.name + "_passiveitem_" + name;
                    passiveObject.layer              = rootObject.layer;
                    passiveObject.transform.parent   = rootObject.transform;
                    passiveObject.transform.position = rootObject.transform.position;

                    passiveText          = passiveObject.AddComponent <MdVTextMesh>();
                    passiveText.material = new Material(MASLoader.shaders["MOARdV/TextMonitor"]);
                    passiveText.SetFont(font, fontSize);
                    passiveText.SetColor(passiveColor);
                    passiveText.material.SetFloat(Shader.PropertyToID("_EmissiveFactor"), 1.0f);
                    passiveText.fontStyle = style;
                    passiveText.SetText(passiveTextStr, false, true, comp, prop);
                    passiveText.SetRenderEnabled(false);
                }

                string activeVariableStr = string.Empty;

                if (itemNode.TryGetValue("activeVariable", ref activeVariableStr))
                {
                    active            = false;
                    activeVariableStr = activeVariableStr.Replace("%ITEMID%", itemIdStr);
                    variableRegistrar.RegisterVariableChangeCallback(activeVariableStr, (double newValue) => active = (newValue > 0.0));
                }
                else
                {
                    active = true;
                }

                string enabledVariableStr = string.Empty;

                if (itemNode.TryGetValue("enabledVariable", ref enabledVariableStr))
                {
                    usesDisabled       = true;
                    enabled            = false;
                    enabledVariableStr = enabledVariableStr.Replace("%ITEMID%", itemIdStr);
                    variableRegistrar.RegisterVariableChangeCallback(enabledVariableStr, (double newValue) => enabled = (newValue > 0.0));

                    string disabledTextStr = string.Empty;
                    if (!itemNode.TryGetValue("disabledText", ref disabledTextStr))
                    {
                        throw new ArgumentException("Missing 'disabledText' in ITEM " + name);
                    }
                    disabledTextStr = disabledTextStr.Replace("%ITEMID%", itemIdStr);

                    Color32 disabledColor;
                    string  disabledColorStr = string.Empty;
                    if (!itemNode.TryGetValue("disabledColor", ref disabledColorStr) || string.IsNullOrEmpty(disabledColorStr))
                    {
                        disabledColor = defaultColor;
                    }
                    else
                    {
                        disabledColor = Utility.ParseColor32(disabledColorStr, comp);
                    }

                    disabledObject                    = new GameObject();
                    disabledObject.name               = rootObject.name + "_disableditem_" + name;
                    disabledObject.layer              = rootObject.layer;
                    disabledObject.transform.parent   = rootObject.transform;
                    disabledObject.transform.position = rootObject.transform.position;

                    disabledText          = disabledObject.AddComponent <MdVTextMesh>();
                    disabledText.material = new Material(MASLoader.shaders["MOARdV/TextMonitor"]);
                    disabledText.SetFont(font, fontSize);
                    disabledText.SetColor(disabledColor);
                    disabledText.material.SetFloat(Shader.PropertyToID("_EmissiveFactor"), 1.0f);
                    disabledText.fontStyle = style;
                    disabledText.SetText(disabledTextStr, false, true, comp, prop);
                    disabledText.SetRenderEnabled(false);
                }
                else
                {
                    enabled      = true;
                    usesDisabled = false;
                }
            }