예제 #1
0
        public override void RenderInteractiveElements(float deltaTime)
        {
            Render2DTexture(
                richtTextTexture.TextureId,
                (int)Bounds.renderX,
                (int)Bounds.renderY,
                (int)richtTextTexture.Width,
                (int)richtTextTexture.Height,
                zPos,
                RenderColor
                );

            bool found = false;
            int  relx  = (int)(api.Input.MouseX - Bounds.absX);
            int  rely  = (int)(api.Input.MouseY - Bounds.absY);

            MouseOverCursor = null;
            for (int i = 0; i < Components.Length; i++)
            {
                RichTextComponentBase comp = Components[i];

                comp.RenderColor = RenderColor;
                comp.RenderInteractiveElements(deltaTime, Bounds.renderX, Bounds.renderY);

                for (int j = 0; !found && j < comp.BoundsPerLine.Length; j++)
                {
                    LineRectangled rec = comp.BoundsPerLine[j];

                    if (rec.PointInside(relx, rely))
                    {
                        MouseOverCursor = comp.MouseOverCursor;

                        found = true;
                    }
                }
            }
        }
예제 #2
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));
            }
        }
예제 #3
0
        public void CalcHeightAndPositions()
        {
            Bounds.CalcWorldBounds();

            if (DebugLogging)
            {
                api.Logger.VerboseDebug("GuiElementRichtext: before bounds: {0}/{1}  w/h = {2},{3}", Bounds.absX, Bounds.absY, Bounds.OuterWidth, Bounds.OuterHeight);
            }

            double posX = 0;
            double posY = 0;

            List <int>          currentLine  = new List <int>();
            List <TextFlowPath> flowPathList = new List <TextFlowPath>();

            flowPathList.Add(new TextFlowPath(Bounds.InnerWidth));

            double lineHeight          = 0;
            double ascentHeight        = 0;
            RichTextComponentBase comp = null;

            for (int i = 0; i < Components.Length; i++)
            {
                comp = Components[i];

                bool didLineBreak = comp.CalcBounds(flowPathList.ToArray(), lineHeight, posX, posY);

                if (DebugLogging)
                {
                    api.Logger.VerboseDebug("GuiElementRichtext, add comp {0}, posY={1}, lineHeight={2}", i, posY, lineHeight);
                    api.Logger.VerboseDebug("GuiElementRichtext, Comp bounds 0 w/h: {0}/{1}", comp.BoundsPerLine[0].Width, comp.BoundsPerLine[0].Height);
                }


                posX += scaled(comp.PaddingLeft);

                if (comp.Float == EnumFloat.None)
                {
                    posX  = 0;
                    posY += Math.Max(lineHeight, comp.BoundsPerLine[0].Height) + (didLineBreak ? GuiElement.scaled(comp.UnscaledMarginTop) : 0);
                    posY  = Math.Ceiling(posY);

                    currentLine.Clear();
                    lineHeight   = 0;
                    ascentHeight = 0;
                    continue;
                }

                if (didLineBreak)
                {
                    lineHeight   = Math.Ceiling(Math.Max(lineHeight, comp.BoundsPerLine[0].Height));
                    ascentHeight = Math.Ceiling(Math.Max(ascentHeight, comp.BoundsPerLine[0].AscentOrHeight));

                    // All previous elements in this line might need to have their Y pos adjusted due to a larger element in the line
                    foreach (int index in currentLine)
                    {
                        RichTextComponentBase lineComp       = Components[index];
                        Rectangled            lastLineBounds = lineComp.BoundsPerLine[lineComp.BoundsPerLine.Length - 1];

                        if (lineComp.VerticalAlign == EnumVerticalAlign.Bottom)
                        {
                            lastLineBounds.Y = Math.Ceiling(lastLineBounds.Y + ascentHeight - lineComp.BoundsPerLine[lineComp.BoundsPerLine.Length - 1].AscentOrHeight);
                        }
                        if (lineComp.VerticalAlign == EnumVerticalAlign.Middle)
                        {
                            lastLineBounds.Y = Math.Ceiling(lastLineBounds.Y + ascentHeight - lineComp.BoundsPerLine[lineComp.BoundsPerLine.Length - 1].AscentOrHeight / 2);
                        }
                    }

                    // The current element that was still on the same line as well
                    // Offset all lines by the gained y-offset on the first line
                    if (comp.VerticalAlign == EnumVerticalAlign.Bottom)
                    {
                        foreach (var val in comp.BoundsPerLine)
                        {
                            val.Y = Math.Ceiling(val.Y + ascentHeight - comp.BoundsPerLine[0].AscentOrHeight);
                        }
                    }
                    if (comp.VerticalAlign == EnumVerticalAlign.Middle)
                    {
                        foreach (var val in comp.BoundsPerLine)
                        {
                            val.Y = Math.Ceiling(val.Y + ascentHeight - comp.BoundsPerLine[0].AscentOrHeight / 2);
                        }
                    }

                    currentLine.Clear();
                    currentLine.Add(i);


                    posY += lineHeight;
                    for (int k = 1; k < comp.BoundsPerLine.Length - 1; k++)
                    {
                        posY += comp.BoundsPerLine[k].Height;
                    }
                    posY += scaled(comp.UnscaledMarginTop);
                    posY  = Math.Ceiling(posY);


                    posX = comp.BoundsPerLine[comp.BoundsPerLine.Length - 1].Width; // + GuiElement.scaled(comp.PaddingLeft); - this adds too much padding when there is a line break inside a rich text compoment and afterwards there comes a link
                    if (comp.BoundsPerLine[comp.BoundsPerLine.Length - 1].Width > 0)
                    {
                        lineHeight   = comp.BoundsPerLine[comp.BoundsPerLine.Length - 1].Height;
                        ascentHeight = comp.BoundsPerLine[comp.BoundsPerLine.Length - 1].AscentOrHeight;
                    }
                    else
                    {
                        lineHeight   = 0;
                        ascentHeight = 0;
                    }
                }
                else
                {
                    if (comp.Float == EnumFloat.Inline && comp.BoundsPerLine.Length > 0)
                    {
                        posX        += comp.BoundsPerLine[0].Width;
                        lineHeight   = Math.Max(comp.BoundsPerLine[0].Height, lineHeight);
                        ascentHeight = Math.Max(comp.BoundsPerLine[0].AscentOrHeight, ascentHeight);
                        currentLine.Add(i);
                    }
                }

                if (comp.Float != EnumFloat.Inline)
                {
                    ConstrainTextFlowPath(flowPathList, posY, comp);
                }
            }


            if (DebugLogging)
            {
                api.Logger.VerboseDebug("GuiElementRichtext: after loop. posY = {0}", posY);
            }


            if (comp != null && posX > 0 && comp.BoundsPerLine.Length > 0)
            {
                posY += lineHeight;
            }

            Bounds.fixedHeight = (posY + 1) / RuntimeEnv.GUIScale;


            double maxHeight = 0;

            foreach (int index in currentLine)
            {
                RichTextComponentBase lineComp       = Components[index];
                Rectangled            lastLineBounds = lineComp.BoundsPerLine[lineComp.BoundsPerLine.Length - 1];
                maxHeight = Math.Max(maxHeight, lastLineBounds.Height);
            }

            foreach (int index in currentLine)
            {
                RichTextComponentBase lineComp       = Components[index];
                Rectangled            lastLineBounds = lineComp.BoundsPerLine[lineComp.BoundsPerLine.Length - 1];

                if (lineComp.VerticalAlign == EnumVerticalAlign.Bottom)
                {
                    lastLineBounds.Y = Math.Ceiling(lastLineBounds.Y + ascentHeight - lineComp.BoundsPerLine[lineComp.BoundsPerLine.Length - 1].AscentOrHeight);
                }
                if (lineComp.VerticalAlign == EnumVerticalAlign.Middle)
                {
                    lastLineBounds.Y = (maxHeight - lastLineBounds.Height) / 2f;
                }
            }

            this.flowPath = flowPathList.ToArray();

            if (DebugLogging)
            {
                api.Logger.VerboseDebug("GuiElementRichtext: after bounds: {0}/{1}  w/h = {2},{3}", Bounds.absX, Bounds.absY, Bounds.OuterWidth, Bounds.OuterHeight);
                api.Logger.VerboseDebug("GuiElementRichtext: posY = {0}", posY);

                api.Logger.VerboseDebug("GuiElementRichtext: framewidth/height: {0}/{1}", api.Render.FrameWidth, api.Render.FrameHeight);
            }
        }