/// <summary> /// Draw a single-stroke border based on given rectangle. /// </summary> /// <param name="surface">Target surface</param> /// <param name="bounds">Border bounds</param> /// <param name="front">Foreground color to use</param> /// <param name="back">Background color to use</param> public static void DrawBorder( this Surface surface, Rectangle bounds, Color front, Color back ) { var topLeft = bounds.TopLeft; var topRight = bounds.TopRight; var bottomLeft = bounds.BottomLeft; var bottomRight = bounds.BottomRight; var horizontalTile = new Tile((int)BoxCharacters.Horizontal, front, back); for (var ix = topLeft.X; ix <= topRight.X; ++ix) { surface.SetTile(new Position(ix, topLeft.Y), horizontalTile); surface.SetTile(new Position(ix, bottomRight.Y), horizontalTile); } var verticalTile = new Tile((int)BoxCharacters.Vertical, front, back); for (var iy = topLeft.Y; iy <= bottomLeft.Y; ++iy) { surface.SetTile(new Position(topLeft.X, iy), verticalTile); surface.SetTile(new Position(topRight.X, iy), verticalTile); } surface.SetTile(topLeft, new Tile((int)BoxCharacters.CornerTopLeft, front, back)); surface.SetTile(topRight, new Tile((int)BoxCharacters.CornerTopRight, front, back)); surface.SetTile(bottomLeft, new Tile((int)BoxCharacters.CornerBottomLeft, front, back)); surface.SetTile(bottomRight, new Tile((int)BoxCharacters.CornerBottomRight, front, back)); }
/// <summary> /// Draw a rectangle of given glyph with given colors /// </summary> public static void DrawRectangle( this Surface surface, Rectangle bounds, int glyph, Color front, Color back ) { var tile = new Tile(glyph, front, back); var topLeft = bounds.TopLeft; var topRight = bounds.TopRight; var bottomLeft = bounds.BottomLeft; var bottomRight = bounds.BottomRight; for (var ix = topLeft.X; ix <= topRight.X; ++ix) { surface.SetTile(new Position(ix, topLeft.Y), tile); surface.SetTile(new Position(ix, bottomRight.Y), tile); } for (var iy = topLeft.Y; iy <= bottomLeft.Y; ++iy) { surface.SetTile(new Position(topLeft.X, iy), tile); surface.SetTile(new Position(topRight.X, iy), tile); } }
/// <summary> /// Draw a window consisting of a border and a title. /// </summary> /// <param name="surface">Target surface</param> /// <param name="bounds">Position and dimensions of the window</param> /// <param name="title">Window title</param> /// <param name="borderFront">Border foreground color</param> /// <param name="borderBack">Border background color</param> /// <param name="titleFront">Tittle foreground color</param> /// <param name="fillBack">The color used to fill the inner parts of the window</param> public static void DrawWindow( this Surface surface, Rectangle bounds, string title, Color borderFront, Color borderBack, Color titleFront, Color fillBack ) { if (string.IsNullOrEmpty(title)) { throw new ArgumentException("DrawWindow: Title can't be empty"); } var maxLength = bounds.Size.Width - 4; var truncatedTitle = (title.Length <= maxLength) ? title : title.Substring(0, maxLength); surface.FillArea(bounds, new Tile(0, DefaultColors.Black, fillBack)); surface.DrawBorder(bounds, borderFront, borderBack); var centerX = bounds.TopLeft.X + (bounds.Size.Width / 2); surface.DrawStringCentered(new Position(centerX, bounds.TopLeft.Y), truncatedTitle, titleFront, borderBack); var beforeTitleX = centerX - ((truncatedTitle.Length / 2) + 1); var afterTitleX = centerX + (truncatedTitle.Length / 2); surface.SetTile(new Position(beforeTitleX, bounds.TopLeft.Y), new Tile((int)BoxCharacters.VerticalLeft, borderFront, borderBack)); surface.SetTile(new Position(afterTitleX, bounds.TopLeft.Y), new Tile((int)BoxCharacters.VerticalRight, borderFront, borderBack)); for (var ix = 0; ix < bounds.Size.Width; ++ix) { var position = new Position(bounds.TopLeft.X + 1 + ix, bounds.BottomRight.Y + 1); surface.SetUiShadow(position, true); } for (var iy = 0; iy < bounds.Size.Height; ++iy) { var position = new Position(bounds.TopRight.X + 1, bounds.TopLeft.Y + 1 + iy); surface.SetUiShadow(position, true); } // Make sure no left over UI shadow is placed on this window from previous drawing operations // this window is overlaying for (var ix = bounds.BottomLeft.X; ix <= bounds.BottomRight.X; ++ix) { for (var iy = bounds.TopLeft.Y; iy <= bounds.BottomRight.Y; ++iy) { surface.SetUiShadow(new Position(ix, iy), false); } } }
/// <summary> /// Fill given area on surface with a tile /// </summary> public static void FillArea( this Surface surface, Rectangle area, Tile tile ) { for (var ix = area.TopLeft.X; ix <= area.BottomRight.X; ++ix) { for (var iy = area.TopLeft.Y; iy <= area.BottomRight.Y; ++iy) { surface.SetTile(new Position(ix, iy), tile); } } }
/// <summary> /// Draw a progress bar in given bounds. /// </summary> /// <param name="surface">Target surface</param> /// <param name="bounds">Bounds to fill with progress bar</param> /// <param name="value">Current progress bar value, in [0, 1]</param> /// <param name="front">Foreground color to use</param> /// <param name="back">Background color to use</param> public static void DrawProgressBar( this Surface surface, Rectangle bounds, double value, Color front, Color back ) { // Clamp progress value to [0.0, 1.0] to avoid issues value = Math.Clamp(value, 0.0, 1.0); var filledSegment = new Tile(219, front, back); var halfFilledSegment = new Tile(221, front, back); var emptySegment = new Tile(219, back, back); var progress = value * bounds.Size.Width; // Draw filled segments var filledSegments = (int)progress; for (var ix = 0; ix < filledSegments; ++ix) { for (var iy = 0; iy < bounds.Size.Height; ++iy) { surface.SetTile(new Position(bounds.TopLeft.X + ix, bounds.TopLeft.Y + iy), filledSegment); } } // Draw potentially half-filled segment var fraction = progress - Math.Truncate(progress); var drawHalfSegment = (fraction >= 0.5); if (drawHalfSegment) { for (var iy = 0; iy < bounds.Size.Height; ++iy) { surface.SetTile(new Position(bounds.TopLeft.X + filledSegments, bounds.TopLeft.Y + iy), halfFilledSegment); } } // Draw empty segments for (var ix = (drawHalfSegment ? 1 : 0) + filledSegments; ix < bounds.Size.Width; ++ix) { for (var iy = 0; iy < bounds.Size.Height; ++iy) { surface.SetTile(new Position(bounds.TopLeft.X + ix, bounds.TopLeft.Y + iy), emptySegment); } } }