public override void ComposeElements(Context ctxStatic, ImageSurface surfaceStatic) { handleWidth = scaled(unscaledHandleWidth) * Scale; handleHeight = scaled(unscaledHandleHeight) * Scale; hoverTextWidth = scaled(unscaledHoverTextHeight); hoverTextHeight = scaled(unscaledHoverTextHeight); padding = scaled(unscaledPadding) * Scale; Bounds.CalcWorldBounds(); ctxStatic.SetSourceRGBA(0, 0, 0, 0.2); RoundRectangle(ctxStatic, Bounds.drawX, Bounds.drawY, Bounds.InnerWidth, Bounds.InnerHeight, 1); ctxStatic.Fill(); EmbossRoundRectangleElement(ctxStatic, Bounds, true, 1, 1); double insetWidth = Bounds.InnerWidth - 2 * padding; double insetHeight = Bounds.InnerHeight - 2 * padding; if (alarmValue > 0 && alarmValue < maxValue) { float alarmValueRel = (float)alarmValue / maxValue; alarmTextureRect = new Rectangled() { X = padding + (Bounds.InnerWidth - 2 * padding) * alarmValueRel, Y = padding, Width = (Bounds.InnerWidth - 2 * padding) * (1 - alarmValueRel), Height = Bounds.InnerHeight - 2 * padding }; ctxStatic.SetSourceRGBA(0.62, 0, 0, 0.4); RoundRectangle(ctxStatic, Bounds.drawX + padding + insetWidth * alarmValueRel, Bounds.drawY + padding, insetWidth * (1 - alarmValueRel), insetHeight, 1); ctxStatic.Fill(); } /*** 2. Handle ***/ ImageSurface surface = new ImageSurface(Format.Argb32, (int)handleWidth + 4, (int)handleHeight + 4); Context ctx = genContext(surface); ctx.SetSourceRGBA(1, 1, 1, 0); ctx.Paint(); RoundRectangle(ctx, 2, 2, handleWidth, handleHeight, 1); fillWithPattern(api, ctx, woodTextureName, false, true); ctx.SetSourceRGB(43 / 255.0, 33 / 255.0, 24 / 255.0); ctx.LineWidth = 2; ctx.Stroke(); generateTexture(surface, ref handleTexture); ctx.Dispose(); surface.Dispose(); ComposeWaterTexture(); ComposeHoverTextElement(); }
void MakeAlarmValueTexture() { float alarmValueRel = (float)(alarmValue - minValue) / (maxValue - minValue); alarmTextureRect = new Rectangled() { X = padding + (Bounds.InnerWidth - 2 * padding) * alarmValueRel, Y = padding, Width = (Bounds.InnerWidth - 2 * padding) * (1 - alarmValueRel), Height = Bounds.InnerHeight - 2 * padding }; ImageSurface surface = new ImageSurface(Format.Argb32, (int)alarmTextureRect.Width, (int)alarmTextureRect.Height); Context ctx = genContext(surface); ctx.SetSourceRGBA(1, 0, 1, 0.4); RoundRectangle(ctx, 0, 0, alarmTextureRect.Width, alarmTextureRect.Height, GuiStyle.ElementBGRadius); ctx.Fill(); generateTexture(surface, ref alarmValueTexture.TextureId); ctx.Dispose(); surface.Dispose(); }
public override void ComposeTextElements(Context ctx, ImageSurface surface) { if (!didInit) { SetUpMovableState(null); didInit = true; } RoundRectangle(ctx, Bounds.bgDrawX, Bounds.bgDrawY, Bounds.OuterWidth, Bounds.OuterHeight, GuiStyle.DialogBGRadius); //ctx.SetSourceRGBA(GuiStyle.DialogDefaultBgColor[0], GuiStyle.DialogDefaultBgColor[1], GuiStyle.DialogDefaultBgColor[2], 1); //ctx.FillPreserve(); LinearGradient gradient = new LinearGradient(0, 0, Bounds.InnerWidth, 0); gradient.AddColorStop(0, new Color(GuiStyle.DialogDefaultBgColor[0] * 1.4, GuiStyle.DialogDefaultBgColor[1] * 1.4, GuiStyle.DialogDefaultBgColor[2] * 1.4, 1)); gradient.AddColorStop(0.5, new Color(GuiStyle.DialogDefaultBgColor[0] * 1.1, GuiStyle.DialogDefaultBgColor[1] * 1.1, GuiStyle.DialogDefaultBgColor[2] * 1.1, 1)); gradient.AddColorStop(1, new Color(GuiStyle.DialogDefaultBgColor[0] * 1.4, GuiStyle.DialogDefaultBgColor[1] * 1.4, GuiStyle.DialogDefaultBgColor[2] * 1.4, 1)); ctx.SetSource(gradient); ctx.FillPreserve(); gradient.Dispose(); Bounds.CalcWorldBounds(); double radius = GuiStyle.DialogBGRadius; ctx.NewPath(); ctx.MoveTo(Bounds.drawX, Bounds.drawY + Bounds.InnerHeight); ctx.LineTo(Bounds.drawX, Bounds.drawY + radius); ctx.Arc(Bounds.drawX + radius, Bounds.drawY + radius, radius, 180 * GameMath.DEG2RAD, 270 * GameMath.DEG2RAD); ctx.Arc(Bounds.drawX + Bounds.OuterWidth - radius, Bounds.drawY + radius, radius, -90 * GameMath.DEG2RAD, 0 * GameMath.DEG2RAD); ctx.LineTo(Bounds.drawX + Bounds.OuterWidth, Bounds.drawY + Bounds.InnerHeight); ctx.SetSourceRGBA(GuiStyle.TitleBarColor); ctx.FillPreserve(); ctx.SetSourceRGBA(new double[] { 45 / 255.0, 35 / 255.0, 33 / 255.0, 1 }); ctx.LineWidth = 6; ctx.Stroke(); Font.SetupContext(ctx); DrawTextLineAt(ctx, text, scaled(GuiStyle.ElementToDialogPadding), (Bounds.InnerHeight - Font.GetFontExtents().Height) / 2 + scaled(2)); double crossSize = scaled(unscaledCloseIconSize); double menuSize = scaled(unscaledCloseIconSize + 2); double crossX = Bounds.drawX + Bounds.OuterWidth - crossSize - scaled(12); double iconY = Bounds.drawY + scaled(7); double crossWidth = scaled(2); double menuX = Bounds.drawX + Bounds.OuterWidth - crossSize - menuSize - scaled(20); menuIconRect = new Rectangled(Bounds.OuterWidth - crossSize - menuSize - scaled(20), scaled(6), crossSize, crossSize); closeIconRect = new Rectangled(Bounds.OuterWidth - crossSize - scaled(12), scaled(5), menuSize, menuSize); ctx.Operator = Operator.Over; ctx.SetSourceRGBA(0, 0, 0, 0.3); api.Gui.Icons.DrawCross(ctx, crossX + 2, iconY + 2, crossWidth, crossSize); ctx.Operator = Operator.Source; ctx.SetSourceRGBA(GuiStyle.DialogDefaultTextColor); api.Gui.Icons.DrawCross(ctx, crossX, iconY, crossWidth, crossSize); ctx.Operator = Operator.Over; api.Gui.Icons.Drawmenuicon_svg(ctx, (int)menuX + 2, (int)iconY + 2, (int)menuSize, (int)menuSize, new double[] { 0, 0, 0, 0.3 }); ctx.Operator = Operator.Source; api.Gui.Icons.Drawmenuicon_svg(ctx, (int)menuX, (int)iconY + 1, (int)menuSize, (int)menuSize, GuiStyle.DialogDefaultTextColor); ctx.Operator = Operator.Over; ComposeHoverIcons(); listMenu.Bounds.fixedX = (Bounds.absX + menuIconRect.X - Bounds.absX) / RuntimeEnv.GUIScale; listMenu.ComposeDynamicElements(); }
public override void ComposeElements(Context ctxStatic, ImageSurface surfaceStatic) { handleWidth = scaled(unscaledHandleWidth); handleHeight = scaled(unscaledHandleHeight); hoverTextWidth = scaled(unscaledHoverTextHeight); hoverTextHeight = scaled(unscaledHoverTextHeight); padding = scaled(unscaledPadding); Bounds.CalcWorldBounds(); // Wood bg RoundRectangle(ctxStatic, Bounds.drawX, Bounds.drawY, Bounds.InnerWidth, Bounds.InnerHeight, GuiStyle.ElementBGRadius); fillWithPattern(api, ctxStatic, woodTextureName); EmbossRoundRectangleElement(ctxStatic, Bounds.drawX, Bounds.drawY, Bounds.InnerWidth, Bounds.InnerHeight); double insetWidth = Bounds.InnerWidth - 2 * padding; double insetHeight = Bounds.InnerHeight - 2 * padding; // Wood Inset ctxStatic.SetSourceRGBA(0, 0, 0, 0.6); RoundRectangle(ctxStatic, Bounds.drawX + padding, Bounds.drawY + padding, insetWidth, insetHeight, GuiStyle.ElementBGRadius); ctxStatic.Fill(); EmbossRoundRectangleElement(ctxStatic, Bounds.drawX + padding, Bounds.drawY + padding, insetWidth, insetHeight, true); if (alarmValue > 0 && alarmValue < maxValue) { float alarmValueRel = (float)alarmValue / maxValue; alarmTextureRect = new Rectangled() { X = padding + (Bounds.InnerWidth - 2 * padding) * alarmValueRel, Y = padding, Width = (Bounds.InnerWidth - 2 * padding) * (1 - alarmValueRel), Height = Bounds.InnerHeight - 2 * padding }; ctxStatic.SetSourceRGBA(0.62, 0, 0, 0.4); RoundRectangle(ctxStatic, Bounds.drawX + padding + insetWidth * alarmValueRel, Bounds.drawY + padding, insetWidth * (1 - alarmValueRel), insetHeight, GuiStyle.ElementBGRadius); ctxStatic.Fill(); } /*** 2. Handle ***/ ImageSurface surface = new ImageSurface(Format.Argb32, (int)handleWidth + 5, (int)handleHeight + 5); Context ctx = genContext(surface); ctx.SetSourceRGBA(1, 1, 1, 0); ctx.Paint(); ctx.SetSourceRGBA(0, 0, 0, 0.5); RoundRectangle(ctx, 0, 0, handleWidth, handleHeight, GuiStyle.ElementBGRadius); ctx.Fill(); surface.Blur(3); RoundRectangle(ctx, 0, 0, handleWidth, handleHeight, GuiStyle.ElementBGRadius); fillWithPattern(api, ctx, woodTextureName); EmbossRoundRectangleElement(ctx, 0, 0, handleWidth, handleHeight, false); generateTexture(surface, ref handleTextureId); ctx.Dispose(); surface.Dispose(); ComposeHoverTextElement(); }
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)); } }
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); } }