/// <summary> /// Add a rectangle. Note 1 px sized rectangles won't be rendered properly. /// </summary> /// <param name="a">upper-left point</param> /// <param name="b">lower-right point</param> /// <param name="color">color</param> /// <param name="rounding">radius of rounded corners</param> /// <param name="roundingCorners">which corner(s) will be rounded</param> TODO finish this documentation on how to use roundingCorners /// <param name="thickness">thickness</param> public void AddRect(Point a, Point b, Color color, float rounding = 0.0f, int roundingCorners = 0x0F, float thickness = 1.0f) { if (MathEx.AmostZero(color.A)) { return; } PathRect(a + new Vector(0.5f, 0.5f), b - new Vector(0.5f, 0.5f), rounding, roundingCorners); PathStroke(color, true, thickness); }
public void AddRectFilledGradientTopLeftToBottomRight(Point a, Point b, Color topLeftColor, Color bottomRightColor) { if (MathEx.AmostZero(topLeftColor.A) && MathEx.AmostZero(bottomRightColor.A)) { return; } this.ShapeMesh.PrimReserve(6, 4); PrimRectGradientTopLeftToBottomRight(a, b, topLeftColor, bottomRightColor); }
/// <summary> /// Add a line segment. /// </summary> /// <param name="start">start point</param> /// <param name="end">end point</param> /// <param name="color">color</param> /// <param name="thickness">thickness</param> public void AddLine(Point start, Point end, Color color, double thickness = 1.0) { if (MathEx.AmostZero(color.A)) { return; } PathLineTo(start + new Vector(0.5, 0.5)); PathLineTo(end + new Vector(0.5, 0.5)); PathStroke(color, false, thickness); }
/// <summary> /// Add a filled triangle. Make sure the points a->b->c is clockwise. /// </summary> /// <param name="a">point A</param> /// <param name="b">point B</param> /// <param name="c">point C</param> /// <param name="color"></param> public void AddTriangleFilled(Point a, Point b, Point c, Color color) { if (MathEx.AmostZero(color.A)) { return; } PathLineTo(a); PathLineTo(b); PathLineTo(c); PathFill(color); }
public void AddCircleFilled(Point center, double radius, Color col, int num_segments) { if (MathEx.AmostZero(col.A)) { return; } float a_max = (float)Math.PI * 2.0f * (num_segments - 1.0f) / num_segments; PathArcTo(center, (float)radius, 0.0f, a_max, num_segments); PathFill(col); }
public void AddCircle(Point center, float radius, Color col, int num_segments, float thickness) { if (MathEx.AmostZero(col.A)) { return; } float a_max = (float)Math.PI * 2.0f * ((float)num_segments - 1.0f) / (float)num_segments; PathArcTo(center, radius - 0.5f, 0.0f, a_max, num_segments); PathStroke(col, true, thickness); }
/// <summary> /// Add an image. /// </summary> /// <param name="texture">the texture that are used</param> /// <param name="a">top-left point</param> /// <param name="b">bottom-right point</param> /// <param name="uvA">texture coordinate of point a</param> /// <param name="uvB">texture coordinate of point b</param> /// <param name="color">tint color</param> public void AddImage(ITexture texture, Point a, Point b, Point uvA, Point uvB, Color color) { if (GetCurrentClipRect().IsEmpty) { return; } if (MathEx.AmostZero(color.A)) { return; } AddImageDrawCommand(texture); this.ImageMesh.PrimReserve(6, 4); AddImageRect(a, b, uvA, uvB, color); }
/// <summary> /// Add a filled rectangle. Note 1 px sized rectangles won't be rendered properly. /// </summary> /// <param name="a">top-left point</param> /// <param name="b">bottom-right point</param> /// <param name="color">color</param> /// <param name="rounding">radius of rounded corners</param> /// <param name="roundingCorners">which corner(s) will be rounded</param> TODO finish this documentation on how to use roundingCorners public void AddRectFilled(Point a, Point b, Color color, float rounding = 0.0f, int roundingCorners = 0x0F) { if (MathEx.AmostZero(color.A)) { return; } if (rounding > 0.0f) { PathRect(a, b, rounding, roundingCorners); PathFill(color); } else { this.ShapeMesh.PrimReserve(6, 4); PrimRect(a, b, color); } }
/// <summary> /// (Fast) adds an arc from angle1 to angle2 to the current path. /// </summary> /// <param name="center">the center of the arc</param> /// <param name="radius">the radius of the arc</param> /// <param name="amin">angle1 = amin * π * 1/12</param> /// <param name="amax">angle1 = amax * π * 1/12</param> public void PathArcToFast(Point center, double radius, int amin, int amax) { if (amin > amax) { return; } if (MathEx.AmostZero(radius)) { Path.Add(center); } else { Path.Capacity = Path.Count + amax - amin + 1; for (int a = amin; a <= amax; a++) { Point c = CirclePoints[a % CirclePoints.Length]; Path.Add(new Point(center.X + c.X * radius, center.Y + c.Y * radius)); } } }
/// <summary> /// Draw a box model /// </summary> /// <param name="drawList"></param> /// <param name="rect">the rect (of the border-box) to draw this box model </param> /// <param name="text">text of the box model</param> /// <param name="style">style of the box model</param> /// <param name="state"></param> public static void DrawBoxModel(this DrawList drawList, Rect rect, string text, GUIStyle style, GUIState state = GUIState.Normal) { if (rect == Layout.StackLayout.DummyRect) { return; } //Widths of border var bt = style.Get <double>(GUIStyleName.BorderTop, state); var br = style.Get <double>(GUIStyleName.BorderRight, state); var bb = style.Get <double>(GUIStyleName.BorderBottom, state); var bl = style.Get <double>(GUIStyleName.BorderLeft, state); //Widths of padding var pt = style.Get <double>(GUIStyleName.PaddingTop, state); var pr = style.Get <double>(GUIStyleName.PaddingRight, state); var pb = style.Get <double>(GUIStyleName.PaddingBottom, state); var pl = style.Get <double>(GUIStyleName.PaddingLeft, state); //4 corner of the border-box var btl = new Point(rect.Left, rect.Top); var btr = new Point(rect.Right, rect.Top); var bbr = new Point(rect.Right, rect.Bottom); var bbl = new Point(rect.Left, rect.Bottom); var borderBoxRect = new Rect(btl, bbr); //4 corner of the padding-box var ptl = new Point(btl.X + bl, btl.Y + bt); var ptr = new Point(btr.X - br, btr.Y + bt); var pbr = new Point(bbr.X - br, bbr.Y - bb); var pbl = new Point(bbl.X + bl, bbl.Y - bb); //if (ptl.X > ptr.X) return;//TODO what if (ptl.X > ptr.X) happens? var paddingBoxRect = new Rect(ptl, pbr); //4 corner of the content-box var ctl = new Point(ptl.X + pl, ptl.Y + pt); var ctr = new Point(ptr.X - pr, ptr.Y + pr); var cbr = new Point(pbr.X - pr, pbr.Y - pb); var cbl = new Point(pbl.X + pl, pbl.Y - pb); var contentBoxRect = new Rect(ctl, cbr); // draw background in padding-box var gradient = (Gradient)style.Get <int>(GUIStyleName.BackgroundGradient, state); if (gradient == Gradient.None) { var bgColor = style.Get <Color>(GUIStyleName.BackgroundColor, state); var borderRounding = style.BorderRadius.topLeft; //FIXME drawList.AddRectFilled(paddingBoxRect, bgColor, (float)borderRounding); //TODO drawing method needed: rect with custom rounding at each corner } else if (gradient == Gradient.TopBottom) { var topColor = style.Get <Color>(GUIStyleName.GradientTopColor, state); var bottomColor = style.Get <Color>(GUIStyleName.GradientBottomColor, state); drawList.AddRectFilledGradient(paddingBoxRect, topColor, bottomColor); } else { throw new InvalidOperationException(); } //Content //Content-box if (text != null && ctl.X < ctr.X)//content should not be visible when ctl.X > ctr.X { //var textSize = style.CalcSize(text, state); /*HACK Don't check text size because the size calculated by Typography is not accurate. */ /*if (textSize.Height < contentBoxRect.Height && textSize.Width < contentBoxRect.Width)*/ { drawList.DrawText(contentBoxRect, text, style, state); } } //Border // Top if (!MathEx.AmostZero(bt)) { var borderTopColor = style.Get <Color>(GUIStyleName.BorderTopColor, state); if (!MathEx.AmostZero(borderTopColor.A)) { drawList.PathLineTo(ptl); drawList.PathLineTo(btl); drawList.PathLineTo(btr); drawList.PathLineTo(ptr); drawList.PathFill(borderTopColor); } } // Right if (!MathEx.AmostZero(br)) { var borderRightColor = style.Get <Color>(GUIStyleName.BorderRightColor, state); if (!MathEx.AmostZero(borderRightColor.A)) { drawList.PathLineTo(ptr); drawList.PathLineTo(btr); drawList.PathLineTo(bbr); drawList.PathLineTo(pbr); drawList.PathFill(borderRightColor); } } // Bottom if (!MathEx.AmostZero(bb)) { var borderBottomColor = style.Get <Color>(GUIStyleName.BorderBottomColor, state); if (!MathEx.AmostZero(borderBottomColor.A)) { drawList.PathLineTo(pbr); drawList.PathLineTo(bbr); drawList.PathLineTo(bbl); drawList.PathLineTo(pbl); drawList.PathFill(borderBottomColor); } } // Left if (!MathEx.AmostZero(bl)) { var borderLeftColor = style.Get <Color>(GUIStyleName.BorderLeftColor, state); if (!MathEx.AmostZero(borderLeftColor.A)) { drawList.PathLineTo(pbl); drawList.PathLineTo(bbl); drawList.PathLineTo(btl); drawList.PathLineTo(ptl); drawList.PathFill(borderLeftColor); } } //Outline var outlineWidth = style.Get <double>(GUIStyleName.OutlineWidth, state); if (!MathEx.AmostZero(outlineWidth)) { var outlineColor = style.Get <Color>(GUIStyleName.OutlineColor, state); if (!MathEx.AmostZero(outlineColor.A)) { drawList.PathRect(btl, bbr); drawList.PathStroke(outlineColor, true, outlineWidth); } } #if DrawPaddingBox drawList.PathRect(ptl, pbr); drawList.PathStroke(Color.ColorRgb(0, 100, 100), true, 1); #endif #if DrawContentBox drawList.PathRect(ctl, cbr); drawList.PathStroke(Color.ColorRgb(100, 0, 100), true, 1); #endif }
public void NewFrame(GUIContext g) { // Handle user moving window (at the beginning of the frame to avoid input lag or sheering). Only valid for root windows. if (MovingWindow != null) { g.KeepAliveID(g.ActiveId); Debug.Assert(MovingWindow?.RootWindow != null); var movingWindow = MovingWindow.RootWindow; if (Mouse.Instance.LeftButtonState == KeyState.Down) { var delta = Mouse.Instance.MouseDelta; if (!MathEx.AmostZero(delta.X) && !MathEx.AmostZero(delta.Y)) { movingWindow.Position += Mouse.Instance.MouseDelta; movingWindow.Layout(); } this.FocusWindow(MovingWindow); } else { g.SetActiveID(0, null); this.MovingWindow = null; } } else { if (ActiveIdWindow != null && ActiveIdWindow.MoveId == g.ActiveId) { g.KeepAliveID(g.ActiveId); if (Mouse.Instance.LeftButtonState != KeyState.Down) { g.SetActiveID(0, null); } } } // Find the window we are hovering. Child windows can extend beyond the limit of their parent so we need to derive HoveredRootWindow from HoveredWindow this.HoveredWindow = this.MovingWindow ?? this.FindHoveredWindow(Mouse.Instance.Position, false); if (this.HoveredWindow != null && (this.HoveredWindow.Flags.HaveFlag(WindowFlags.ChildWindow))) { this.HoveredRootWindow = this.HoveredWindow.RootWindow; } else { this.HoveredRootWindow = (this.MovingWindow != null) ? this.MovingWindow.RootWindow : this.FindHoveredWindow(Mouse.Instance.Position, true); } // Scale & Scrolling if (this.HoveredWindow != null && Mouse.Instance.MouseWheel != 0.0 && !this.HoveredWindow.Collapsed) { Window window = this.HoveredWindow; if (Keyboard.Instance.KeyDown(Key.LeftControl)) { //Scale //TODO } else { // Scroll if (!(window.Flags.HaveFlag(WindowFlags.NoScrollWithMouse))) { var newScrollY = window.ClientAreaNode.ScrollOffset.Y - Math.Sign(Mouse.Instance.MouseWheel) * 20 /*scroll step*/; float window_rounding = (float)window.WindowContainer.RuleSet.Get <double>(StylePropertyName.WindowRounding); double resize_corner_size = Math.Max(window.WindowContainer.RuleSet.FontSize * 1.35, window_rounding + 1.0 + window.WindowContainer.RuleSet.FontSize * 0.2); var contentSize = window.ContentRect.Size; var vH = window.Rect.Height - window.TitleBarHeight - window.WindowContainer.RuleSet.BorderVertical - window.WindowContainer.RuleSet.PaddingVertical; var cH = contentSize.Height; if (cH > vH) { newScrollY = MathEx.Clamp(newScrollY, 0, cH - vH); window.SetWindowScrollY(newScrollY); } } } } // Mark all windows as not visible for (int i = 0; i != this.Windows.Count; i++) { Window window = this.Windows[i]; window.WasActive = window.Active; window.Active = false; window.Accessed = false; //disable all nodes in the window window.ClientAreaNode.Foreach(n => { n.ActiveSelf = false; return(true); }); window.AbsoluteVisualList.ForEach(n => n.ActiveSelf = false); } // Clear temp data for (int i = 0; i != this.Windows.Count; i++) { Window window = this.Windows[i]; window.TempData.Clear(); } // No window should be open at the beginning of the frame. // But in order to allow the user to call NewFrame() multiple times without calling Render(), we are doing an explicit clear. this.WindowStack.Clear(); }