Example #1
0
        static void Richtextify(ICoreClientAPI capi, VtmlToken token, ref List <RichTextComponentBase> elems, Stack <CairoFont> fontStack, Action <LinkTextComponent> didClickLink)
        {
            if (token is VtmlTagToken)
            {
                VtmlTagToken tagToken = token as VtmlTagToken;

                switch (tagToken.Name)
                {
                case "br":
                    elems.Add(new RichTextComponent(capi, "\r\n", fontStack.Peek()));
                    break;

                case "i":
                    CairoFont font = fontStack.Peek().Clone();
                    font.Slant = FontSlant.Italic;
                    fontStack.Push(font);
                    foreach (var val in tagToken.ChildElements)
                    {
                        Richtextify(capi, val, ref elems, fontStack, didClickLink);
                    }
                    fontStack.Pop();
                    break;

                case "a":
                    LinkTextComponent cmp = new LinkTextComponent(capi, tagToken.ContentText, fontStack.Peek(), didClickLink);
                    tagToken.Attributes.TryGetValue("href", out cmp.Href);

                    elems.Add(cmp);
                    break;

                case "icon":
                    string iconName;
                    tagToken.Attributes.TryGetValue("name", out iconName);
                    IconComponent iconcmp = new IconComponent(capi, iconName, fontStack.Peek());
                    elems.Add(iconcmp);
                    break;

                case "itemstack":
                    string    code;
                    string    type;
                    float     size      = (float)fontStack.Peek().GetFontExtents().Height;
                    EnumFloat floatType = EnumFloat.Inline;
                    string    floattypestr;
                    if (tagToken.Attributes.TryGetValue("floattype", out floattypestr))
                    {
                        if (!Enum.TryParse(floattypestr, out floatType))
                        {
                            floatType = EnumFloat.Inline;
                        }
                    }

                    tagToken.Attributes.TryGetValue("code", out code);
                    if (!tagToken.Attributes.TryGetValue("type", out type))
                    {
                        type = "block";
                    }

                    ItemStack stack;
                    if (type == "item")
                    {
                        stack = new ItemStack(capi.World.GetItem(new AssetLocation(code)));
                    }
                    else
                    {
                        stack = new ItemStack(capi.World.GetBlock(new AssetLocation(code)));
                    }

                    float sizemul = 1f;
                    if (tagToken.Attributes.TryGetValue("rsize", out var sizemulstr))
                    {
                        sizemul = sizemulstr.ToFloat();
                    }

                    SlideshowItemstackTextComponent stckcmp = new SlideshowItemstackTextComponent(capi, new ItemStack[] { stack }, size / RuntimeEnv.GUIScale, floatType);
                    stckcmp.renderSize   *= sizemul;
                    stckcmp.VerticalAlign = EnumVerticalAlign.Middle;

                    if (tagToken.Attributes.TryGetValue("offx", out var offxstr))
                    {
                        stckcmp.offX = GuiElement.scaled(offxstr.ToFloat(0));
                    }
                    if (tagToken.Attributes.TryGetValue("offy", out var offystr))
                    {
                        stckcmp.offY = GuiElement.scaled(offystr.ToFloat(0));
                    }

                    elems.Add(stckcmp);
                    break;

                case "font":
                    fontStack.Push(getFont(tagToken, fontStack));
                    foreach (var val in tagToken.ChildElements)
                    {
                        Richtextify(capi, val, ref elems, fontStack, didClickLink);
                    }
                    fontStack.Pop();
                    break;

                case "clear":
                    elems.Add(new ClearFloatTextComponent(capi));
                    break;

                case "strong":
                    fontStack.Push(fontStack.Peek().Clone().WithWeight(Cairo.FontWeight.Bold));
                    foreach (var val in tagToken.ChildElements)
                    {
                        Richtextify(capi, val, ref elems, fontStack, didClickLink);
                    }
                    fontStack.Pop();
                    break;
                }


                if (tagToken.Name != null && TagConverters.ContainsKey(tagToken.Name))
                {
                    RichTextComponentBase elem = TagConverters[tagToken.Name](capi, tagToken, fontStack, didClickLink);
                    if (elem != null)
                    {
                        elems.Add(elem);
                    }
                }
            }
            else
            {
                VtmlTextToken textToken = token as VtmlTextToken;
                elems.Add(new RichTextComponent(capi, textToken.Text, fontStack.Peek()));
            }
        }
Example #2
0
 public ItemstackTextComponent(ICoreClientAPI capi, ItemStack itemstack, double size, double sidePadding = 0, EnumFloat floatType = EnumFloat.Left, Common.Action <ItemStack> onStackClicked = null) : base(capi)
 {
     slot = new DummySlot(itemstack);
     this.onStackClicked = onStackClicked;
     this.Float          = floatType;
     this.size           = size;
     this.BoundsPerLine  = new LineRectangled[] { new LineRectangled(0, 0, size + sidePadding, size) };
     //PaddingRight = 0;
 }
Example #3
0
        /// <summary>
        /// Looks at the collectibles handbook groupBy attribute and makes a list of itemstacks from that
        /// </summary>
        /// <param name="itemstackgroup"></param>
        /// <param name="unscaleSize"></param>
        /// <param name="floatType"></param>
        public SlideshowItemstackTextComponent(ICoreClientAPI capi, ItemStack itemstackgroup, List <ItemStack> allstacks, double unscaleSize, EnumFloat floatType, Action <ItemStack> onStackClicked = null) : base(capi)
        {
            initSlot();
            this.onStackClicked = onStackClicked;

            string[] groups = itemstackgroup.Collectible.Attributes?["handbook"]?["groupBy"]?.AsArray <string>(null);

            List <ItemStack> nowGroupedStacks = new List <ItemStack>();
            List <ItemStack> stacks           = new List <ItemStack>();

            nowGroupedStacks.Add(itemstackgroup);
            stacks.Add(itemstackgroup);

            if (allstacks != null)
            {
                if (groups != null)
                {
                    AssetLocation[] groupWildCards = new AssetLocation[groups.Length];
                    for (int i = 0; i < groups.Length; i++)
                    {
                        if (!groups[i].Contains(":"))
                        {
                            groupWildCards[i] = new AssetLocation(itemstackgroup.Collectible.Code.Domain, groups[i]);
                        }
                        else
                        {
                            groupWildCards[i] = new AssetLocation(groups[i]);
                        }
                    }

                    foreach (var val in allstacks)
                    {
                        if (val.Collectible.Attributes?["handbook"]?["isDuplicate"].AsBool(false) == true)
                        {
                            nowGroupedStacks.Add(val);
                            continue;
                        }
                        for (int i = 0; i < groupWildCards.Length; i++)
                        {
                            if (val.Collectible.WildCardMatch(groupWildCards[i]))
                            {
                                stacks.Add(val);
                                nowGroupedStacks.Add(val);
                                break;
                            }
                        }
                    }
                }

                foreach (var val in nowGroupedStacks)
                {
                    allstacks.Remove(val);
                }
            }

            this.Itemstacks    = stacks.ToArray();
            this.Float         = floatType;
            this.BoundsPerLine = new LineRectangled[] { new LineRectangled(0, 0, GuiElement.scaled(unscaleSize), GuiElement.scaled(unscaleSize)) };
        }
Example #4
0
        /// <summary>
        /// Flips through given array of item stacks every second
        /// </summary>
        /// <param name="itemstacks"></param>
        /// <param name="unscaleSize"></param>
        /// <param name="floatType"></param>
        public SlideshowItemstackTextComponent(ICoreClientAPI capi, ItemStack[] itemstacks, double unscaleSize, EnumFloat floatType, Action <ItemStack> onStackClicked = null) : base(capi)
        {
            initSlot();

            this.Itemstacks     = itemstacks;
            this.Float          = floatType;
            this.BoundsPerLine  = new LineRectangled[] { new LineRectangled(0, 0, GuiElement.scaled(unscaleSize), GuiElement.scaled(unscaleSize)) };
            this.onStackClicked = onStackClicked;
        }
        public ItemstackTextComponent(ICoreClientAPI capi, ItemStack itemstack, double size, double rightSidePadding = 0, EnumFloat floatType = EnumFloat.Left, Action <ItemStack> onStackClicked = null) : base(capi)
        {
            size = GuiElement.scaled(size);

            slot = new DummySlot(itemstack);
            this.onStackClicked = onStackClicked;
            this.Float          = floatType;
            this.size           = size;
            this.BoundsPerLine  = new LineRectangled[] { new LineRectangled(0, 0, size, size) };
            PaddingRight        = GuiElement.scaled(rightSidePadding);
        }
Example #6
0
        private void ConstrainTextFlowPath(List <TextFlowPath> flowPath, double posY, RichTextComponentBase comp)
        {
            Rectangled rect         = comp.BoundsPerLine[0];
            EnumFloat  elementFloat = comp.Float;

            double x1 = elementFloat == EnumFloat.Left ? rect.Width + comp.PaddingRight : 0;
            double x2 = elementFloat == EnumFloat.Right ? Bounds.InnerWidth - rect.Width - comp.PaddingLeft : Bounds.InnerWidth;

            double remainingHeight = rect.Height;

            for (int i = 0; i < flowPath.Count; i++)
            {
                TextFlowPath tfp = flowPath[i];

                if (tfp.Y2 <= posY)
                {
                    continue;                 // we already passed this one
                }
                double hereX1 = Math.Max(x1, tfp.X1);
                double hereX2 = Math.Min(x2, tfp.X2);


                // Current bounds are taller, let's make a split and insert ours
                if (tfp.Y2 > posY + rect.Height)
                {
                    // Already more contrained, don't touch
                    if (x1 <= tfp.X1 && x2 >= tfp.X2)
                    {
                        continue;
                    }

                    if (i == 0)
                    {
                        // We're at the begining, so don't need a "before" element
                        flowPath[i] = new TextFlowPath(hereX1, posY, hereX2, posY + rect.Height);
                        flowPath.Insert(i + 1, new TextFlowPath(tfp.X1, posY + rect.Height, tfp.X2, tfp.Y2));
                    }
                    else
                    {
                        flowPath[i] = new TextFlowPath(tfp.X1, tfp.Y1, tfp.X2, posY);
                        flowPath.Insert(i + 1, new TextFlowPath(tfp.X1, posY + rect.Height, tfp.X2, tfp.Y2));
                        flowPath.Insert(i, new TextFlowPath(hereX1, posY, hereX2, posY + rect.Height));
                    }

                    remainingHeight = 0;
                    break;
                }
                else

                // Current bounds are shorter, let's update it
                {
                    flowPath[i].X1   = hereX1;
                    flowPath[i].X2   = hereX2;
                    remainingHeight -= tfp.Y2 - posY;
                }
            }

            if (remainingHeight > 0)
            {
                flowPath.Add(new TextFlowPath(x1, posY, x2, posY + remainingHeight));
            }
        }
Example #7
0
        /// <summary>
        /// Flips through given array of grid recipes every second
        /// </summary>
        /// <param name="capi"></param>
        /// <param name="gridrecipes"></param>
        /// <param name="size"></param>
        /// <param name="floatType"></param>
        /// <param name="onStackClicked"></param>
        /// <param name="allStacks">If set, will resolve wildcards based on this list, otherwise will search all available blocks/items</param>
        public SlideshowGridRecipeTextComponent(ICoreClientAPI capi, GridRecipe[] gridrecipes, double size, EnumFloat floatType, Action <ItemStack> onStackClicked = null, ItemStack[] allStacks = null) : base(capi)
        {
            size = GuiElement.scaled(size);

            this.onStackClicked = onStackClicked;
            this.Float          = floatType;
            this.BoundsPerLine  = new LineRectangled[] { new LineRectangled(0, 0, 3 * (size + 3), 3 * (size + 3)) };
            this.size           = size;

            Random fixedRand = new Random(123);

            // Expand wild cards
            List <GridRecipeAndUnnamedIngredients> resolvedGridRecipes = new List <GridRecipeAndUnnamedIngredients>();
            Queue <GridRecipe> halfResolvedRecipes = new Queue <GridRecipe>(gridrecipes);

            bool allResolved = false;

            while (!allResolved)
            {
                allResolved = true;

                int cnt = halfResolvedRecipes.Count;

                while (cnt-- > 0)
                {
                    GridRecipe toTestRecipe = halfResolvedRecipes.Dequeue();
                    Dictionary <int, ItemStack[]> unnamedIngredients = null;

                    bool thisResolved = true;

                    for (int j = 0; j < toTestRecipe.resolvedIngredients.Length; j++)
                    {
                        CraftingRecipeIngredient ingred = toTestRecipe.resolvedIngredients[j];

                        if (ingred != null && ingred.IsWildCard)
                        {
                            allResolved  = false;
                            thisResolved = false;
                            ItemStack[] stacks = ResolveWildCard(capi.World, ingred, allStacks);

                            if (ingred.Name == null)
                            {
                                if (unnamedIngredients == null)
                                {
                                    unnamedIngredients = new Dictionary <int, ItemStack[]>();
                                }
                                unnamedIngredients[j] = ((ItemStack[])stacks.Clone()).Shuffle(fixedRand);
                                thisResolved          = true;
                                continue;
                            }

                            if (stacks.Length == 0)
                            {
                                throw new ArgumentException("Attempted to resolve the recipe ingredient wildcard " + ingred.Type + " " + ingred.Code + " but there are no such items/blocks!");
                            }

                            for (int k = 0; k < stacks.Length; k++)
                            {
                                GridRecipe cloned = toTestRecipe.Clone();

                                for (int m = 0; m < cloned.resolvedIngredients.Length; m++)
                                {
                                    CraftingRecipeIngredient clonedingred = cloned.resolvedIngredients[m];
                                    if (clonedingred != null && clonedingred.Code.Equals(ingred.Code))
                                    {
                                        clonedingred.Code              = stacks[k].Collectible.Code;
                                        clonedingred.IsWildCard        = false;
                                        clonedingred.ResolvedItemstack = stacks[k];
                                    }
                                }

                                halfResolvedRecipes.Enqueue(cloned);
                            }

                            break;
                        }
                    }

                    if (thisResolved)
                    {
                        resolvedGridRecipes.Add(new GridRecipeAndUnnamedIngredients()
                        {
                            Recipe = toTestRecipe, unnamedIngredients = unnamedIngredients
                        });
                    }
                }
            }

            resolveCache.Clear();
            this.GridRecipesAndUnIn = resolvedGridRecipes.ToArray();


            this.GridRecipesAndUnIn.Shuffle(fixedRand);

            for (int i = 0; i < GridRecipesAndUnIn.Length; i++)
            {
                string trait = GridRecipesAndUnIn[i].Recipe.RequiresTrait;
                if (trait != null)
                {
                    extraTexts[i] = capi.Gui.TextTexture.GenTextTexture(Lang.Get("* Requires {0} trait", trait), CairoFont.WhiteDetailText());
                }
            }

            if (GridRecipesAndUnIn.Length == 0)
            {
                throw new ArgumentException("Could not resolve any of the supplied grid recipes?");
            }
        }