/// <summary> /// Copies the <see cref="T:System.Manageent.Automation.Host.BufferCell" /> array into the screen buffer at the /// given origin, clipping such that cells in the array that would fall outside the screen buffer are ignored. /// </summary> /// <param name="origin"> /// The top left corner of the rectangular screen area to which <paramref name="contents" /> is copied. /// </param> /// <param name="contents"> /// A rectangle of <see cref="T:System.Management.Automation.Host.BufferCell" /> objects to be copied to the /// screen buffer. /// </param> /// <seealso cref="M:System.Management.Automation.Host.PSHostRawUserInterface.NewBufferCellArray(System.Int32,System.Int32,System.Management.Automation.Host.BufferCell)" /> /// <seealso cref="M:System.Management.Automation.Host.PSHostRawUserInterface.NewBufferCellArray(System.Management.Automation.Host.Size,System.Management.Automation.Host.BufferCell)" /> /// <seealso cref="M:System.Management.Automation.Host.PSHostRawUserInterface.NewBufferCellArray(System.String[],System.ConsoleColor,System.ConsoleColor)" /> /// <seealso cref="M:System.Management.Automation.Host.PSHostRawUserInterface.LengthInBufferCells(System.Char)" /> /// <seealso cref="M:System.Management.Automation.Host.PSHostRawUserInterface.LengthInBufferCells(System.String)" /> /// <seealso cref="M:System.Management.Automation.Host.PSHostRawUserInterface.SetBufferContents(System.Management.Automation.Host.Rectangle,System.Management.Automation.Host.BufferCell)" /> /// <seealso cref="M:System.Management.Automation.Host.PSHostRawUserInterface.GetBufferContents(System.Management.Automation.Host.Rectangle)" /> /// <seealso cref="M:System.Management.Automation.Host.PSHostRawUserInterface.ScrollBufferContents(System.Management.Automation.Host.Rectangle,System.Management.Automation.Host.Coordinates,System.Management.Automation.Host.Rectangle,System.Management.Automation.Host.BufferCell)" /> public override void SetBufferContents(Coordinates origin, BufferCell[,] contents) { Trace.WriteLine($"set buffer {contents.Length}"); Logger.Debug($"SetBufferContents {origin} ({contents.Length})"); var length = contents.GetLength(1); var g = new ushort[length]; var advanceWidths = new double[length]; Debug.WriteLine(nameof(SetBufferContents)); var k = 0; var l = contents.GetLength(0); try { for (var i = origin.Y; k < l; i++, k++) { var z = 0; var bound = contents.GetLength(1); for (var j = origin.X; z < bound; j++, z++) { try { var bufferCell = contents[k, z]; //buf.Buf[i, j] = bufferCell; var bufferCellCharacter = bufferCell.Character; var bufferCellBackgroundColor = bufferCell.BackgroundColor; var bufferCellForegroundColor = bufferCell.ForegroundColor; TermInterface.Dispatcher.Invoke(() => { try { var xx = bound; TermInterface.SetCellCharacter(i, j, bufferCellCharacter, bufferCellForegroundColor, bufferCellBackgroundColor, false, true); } catch (Exception ex) { throw; } }); } catch (Exception ex) { } } } } catch (Exception ex) { Debug.WriteLine(ex); } }
/// <summary> /// Write text /// </summary> /// <param name="text">Text</param> /// <param name="textAlignment">Text alignment</param> /// <param name="foregroundColor">Foreground color</param> /// <param name="backgroundColor">Background color</param> /// <param name="allowTransparency">Allow transparency</param> /// <param name="buffer">Buffer</param> /// <param name="rectangle">Rectangle</param> internal static void WriteText(string text, ETextAlignment textAlignment, ConsoleColor foregroundColor, ConsoleColor backgroundColor, bool allowTransparency, BufferCell[,] buffer, RectInt rectangle) { BufferCell empty_cell = new BufferCell(BufferCell.empty.Character, foregroundColor, backgroundColor); For(new Vector2Int(buffer.GetLength(0), buffer.GetLength(1)), rectangle, (x, y) => { bool show = true; int index = x; switch (textAlignment) { case ETextAlignment.TopCenter: index = x - ((rectangle.Width - text.Length) / 2); show = (y == 0); break; case ETextAlignment.TopRight: index = x - (rectangle.Width - text.Length); show = (y == 0); break; case ETextAlignment.CenterLeft: show = (y == (rectangle.Height / 2)); break; case ETextAlignment.Center: index = x - ((rectangle.Width - text.Length) / 2); show = (y == (rectangle.Height / 2)); break; case ETextAlignment.CenterRight: index = x - (rectangle.Width - text.Length); show = (y == (rectangle.Height / 2)); break; case ETextAlignment.BottomLeft: show = (y == (rectangle.Height - 1)); break; case ETextAlignment.BottomCenter: index = x - ((rectangle.Width - text.Length) / 2); show = (y == (rectangle.Height - 1)); break; case ETextAlignment.BottomRight: index = x - (rectangle.Width - text.Length); show = (y == (rectangle.Height - 1)); break; } BufferCell cell = (show ? (((index < 0) || (index >= text.Length)) ? empty_cell : new BufferCell(text[index], foregroundColor, backgroundColor)) : empty_cell); if ((cell.Character != BufferCell.empty.Character) || (!allowTransparency)) { buffer[rectangle.X + x, rectangle.Y + y] = cell; } }); }
/// <summary> /// Write border /// </summary> /// <param name="foregroundColor">Foreground color</param> /// <param name="backgroundColor">Background color</param> /// <param name="borderStyle">Border style</param> /// <param name="isTopOpen">Is top open</param> /// <param name="isBottomOpen">Is bottom open</param> /// <param name="isLeftOpen">Is left open</param> /// <param name="isRightOpen">Is right open</param> /// <param name="buffer">Buffer</param> /// <param name="rectangle">Rectangle</param> internal static void WriteBorder(ConsoleColor foregroundColor, ConsoleColor backgroundColor, BorderStyle borderStyle, bool isTopOpen, bool isBottomOpen, bool isLeftOpen, bool isRightOpen, bool allowTransparency, BufferCell[,] buffer, RectInt rectangle) { For(new Vector2Int(buffer.GetLength(0), buffer.GetLength(1)), rectangle, (x, y) => { BufferCell cell = new BufferCell((x <= 0) ? ((y <= 0) ? (isTopOpen ? (isLeftOpen ? borderStyle.Cross : borderStyle.LeftMiddleCorner) : (isLeftOpen ? borderStyle.TopMiddleCorner : borderStyle.TopLeftCorner)) : (((y + 1) >= rectangle.Height) ? (isBottomOpen ? (isLeftOpen ? borderStyle.Cross : borderStyle.LeftMiddleCorner) : (isLeftOpen ? borderStyle.BottomMiddleCorner : borderStyle.BottomLeftCorner)) : borderStyle.LeftSide)) : (((x + 1) >= rectangle.Width) ? ((y <= 0) ? (isTopOpen ? (isRightOpen ? borderStyle.Cross : borderStyle.RightMiddleCorner) : (isRightOpen ? borderStyle.TopMiddleCorner : borderStyle.TopRightCorner)) : (((y + 1) >= rectangle.Height) ? (isBottomOpen ? (isRightOpen ? borderStyle.Cross : borderStyle.RightMiddleCorner) : (isRightOpen ? borderStyle.BottomMiddleCorner : borderStyle.BottomRightCorner)) : borderStyle.RightSide)) : ((y <= 0) ? borderStyle.TopSide : (((y + 1) >= rectangle.Height) ? borderStyle.BottomSide : ' '))), foregroundColor, backgroundColor); if ((cell.Character != BufferCell.empty.Character) || (!allowTransparency)) { buffer[rectangle.X + x, rectangle.Y + y] = cell; } }); }
/// <summary> /// Write cells lines /// </summary> /// <param name="cellsLines">Cells lines</param> /// <param name="textAlignment">Text alignment</param> /// <param name="foregroundColor">Foreground color</param> /// <param name="backgroundColor">Background color</param> /// <param name="allowTransparency">Allow transparency</param> /// <param name="buffer">Buffer</param> /// <param name="rectangle">Rectangle</param> internal static void WriteCellsLines(IReadOnlyList <IReadOnlyList <BufferCell> > cellsLines, ETextAlignment textAlignment, ConsoleColor foregroundColor, ConsoleColor backgroundColor, bool allowTransparency, BufferCell[,] buffer, RectInt rectangle) { BufferCell empty_cell = new BufferCell(BufferCell.empty.Character, foregroundColor, backgroundColor); For(new Vector2Int(buffer.GetLength(0), buffer.GetLength(1)), rectangle, (x, y) => { int row = y; int index = x; IReadOnlyList <BufferCell> cells = Array.Empty <BufferCell>(); switch (textAlignment) { case ETextAlignment.TopLeft: case ETextAlignment.TopCenter: case ETextAlignment.TopRight: cells = (((row < 0) || (row >= cellsLines.Count)) ? Array.Empty <BufferCell>() : ((cellsLines[row] == null) ? Array.Empty <BufferCell>() : cellsLines[row])); break; case ETextAlignment.CenterLeft: case ETextAlignment.Center: case ETextAlignment.CenterRight: row = y - ((rectangle.Height - cellsLines.Count) / 2); cells = (((row < 0) || (row >= cellsLines.Count)) ? Array.Empty <BufferCell>() : ((cellsLines[row] == null) ? Array.Empty <BufferCell>() : cellsLines[row])); break; case ETextAlignment.BottomLeft: case ETextAlignment.BottomCenter: case ETextAlignment.BottomRight: row = y - (rectangle.Height - cellsLines.Count); cells = (((row < 0) || (row >= cellsLines.Count)) ? Array.Empty <BufferCell>() : ((cellsLines[row] == null) ? Array.Empty <BufferCell>() : cellsLines[row])); break; } switch (textAlignment) { case ETextAlignment.TopCenter: case ETextAlignment.Center: case ETextAlignment.BottomCenter: index = x - ((rectangle.Width - cells.Count) / 2); break; case ETextAlignment.TopRight: case ETextAlignment.CenterRight: case ETextAlignment.BottomRight: index = x - (rectangle.Width - cells.Count); break; } BufferCell cell = (((index < 0) || (index >= cells.Count)) ? empty_cell : cells[index]); if ((cell.Character != BufferCell.empty.Character) || (!allowTransparency)) { buffer[rectangle.X + x, rectangle.Y + y] = cell; } }); }
Show() { if (!IsShowing) { // Get temporary reference to the progress region since it can be // changed at any time by a call to WriteProgress. BufferCell[,] tempProgressRegion = _progressRegion; if (tempProgressRegion == null) { return; } // The location where we show ourselves is always relative to the screen buffer's current window position. int rows = tempProgressRegion.GetLength(0); int cols = tempProgressRegion.GetLength(1); _location = _rawui.WindowPosition; // We have to show the progress pane in the first column, as the screen buffer at any point might contain // a CJK double-cell characters, which makes it impractical to try to find a position where the pane would // not slice a character. Column 0 is the only place where we know for sure we can place the pane. _location.X = 0; _location.Y = Math.Min(_location.Y + 2, _bufSize.Height); #if UNIX // replace the saved region in the screen buffer with our progress display _location = _rawui.CursorPosition; //set the cursor position back to the beginning of the region to overwrite write-progress //if the cursor is at the bottom, back it up to overwrite the previous write progress if (_location.Y >= _rawui.BufferSize.Height - rows) { Console.Out.Write('\n'); if (_location.Y >= rows) { _location.Y -= rows; } } _rawui.CursorPosition = _location; #else // Save off the current contents of the screen buffer in the region that we will occupy _savedRegion = _rawui.GetBufferContents( new Rectangle(_location.X, _location.Y, _location.X + cols - 1, _location.Y + rows - 1)); #endif // replace the saved region in the screen buffer with our progress display _rawui.SetBufferContents(_location, tempProgressRegion); } }
public override void WriteToBuffer(BufferCell[,] buffer, RectInt rectangle) { Vector2Int buffer_size = new Vector2Int(buffer.GetLength(0), buffer.GetLength(1)); Vector2Int start_index = Vector2Int.Max(-rectangle.Position, Vector2Int.zero); Vector2Int clamped_size = rectangle.Size - Vector2Int.Max(rectangle.Position + rectangle.Size - buffer_size, Vector2Int.zero); Parallel.For(start_index.Y, clamped_size.Y, (y) => { for (int x = start_index.X; x < clamped_size.X; x++) { buffer[rectangle.Position.X + x, rectangle.Position.Y + y] = this.buffer[x, y]; } }); }
/// <summary> /// Compare buffers /// </summary> /// <param name="left">Left</param> /// <param name="right">RIght</param> /// <returns>Delta</returns> internal static IReadOnlyCollection <Vector2Int> CompareBuffers(BufferCell[,] left, BufferCell[,] right) { ConcurrentBag <Vector2Int> delta = new ConcurrentBag <Vector2Int>(); Parallel.For(0, left.GetLength(1), (y) => { for (int x = 0, x_size = left.GetLength(0); x < x_size; x++) { if (left[x, y] != right[x, y]) { delta.Add(new Vector2Int(x, y)); } } }); return(delta); }
public BufferCell[,] NewBufferCellArray(int width, int height, BufferCell contents) { using (PSHostRawUserInterface._tracer.TraceMethod()) { if (width <= 0) { throw PSHostRawUserInterface._tracer.NewArgumentOutOfRangeException(nameof(width), (object)width, "MshHostRawUserInterfaceStrings", "NonPositiveNumberErrorTemplate", (object)nameof(width)); } BufferCell[,] bufferCellArray = height > 0 ? new BufferCell[height, width] : throw PSHostRawUserInterface._tracer.NewArgumentOutOfRangeException(nameof(height), (object)height, "MshHostRawUserInterfaceStrings", "NonPositiveNumberErrorTemplate", (object)nameof(height)); switch (this.LengthInBufferCells(contents.Character)) { case 1: for (int index1 = 0; index1 < bufferCellArray.GetLength(0); ++index1) { for (int index2 = 0; index2 < bufferCellArray.GetLength(1); ++index2) { bufferCellArray[index1, index2] = contents; bufferCellArray[index1, index2].BufferCellType = BufferCellType.Complete; } } break; case 2: int index3 = width % 2 == 0 ? width : width - 1; for (int index1 = 0; index1 < height; ++index1) { int index2; for (int index4 = 0; index4 < index3; index4 = index2 + 1) { bufferCellArray[index1, index4] = contents; bufferCellArray[index1, index4].BufferCellType = BufferCellType.Leading; index2 = index4 + 1; bufferCellArray[index1, index2] = new BufferCell(char.MinValue, contents.ForegroundColor, contents.BackgroundColor, BufferCellType.Trailing); } if (index3 < width) { bufferCellArray[index1, index3] = contents; bufferCellArray[index1, index3].BufferCellType = BufferCellType.Leading; } } break; } return(bufferCellArray); } }
internal void Show() { BufferCell[,] bufferCellArray = this.progressRegion; if (bufferCellArray != null) { int length = bufferCellArray.GetLength(0); int num = bufferCellArray.GetLength(1); this.location = this.rawui.WindowPosition; this.location.X = 0; this.location.Y = Math.Min(this.location.Y + 2, this.bufSize.Height); this.savedRegion = this.rawui.GetBufferContents(new Rectangle(this.location.X, this.location.Y, this.location.X + num - 1, this.location.Y + length - 1)); this.rawui.SetBufferContents(this.location, bufferCellArray); return; } else { return; } }
internal void Show(PendingProgress pendingProgress) { bool flag; this.bufSize = this.rawui.BufferSize; int width = this.bufSize.Width; Size windowSize = this.rawui.WindowSize; int num = Math.Max(5, windowSize.Height / 3); string[] strArrays = pendingProgress.Render(width, num, this.rawui); if (strArrays != null) { BufferCell[,] bufferCellArray = this.rawui.NewBufferCellArray(strArrays, this.ui.ProgressForegroundColor, this.ui.ProgressBackgroundColor); if (this.progressRegion != null) { if (bufferCellArray.GetLength(0) != this.progressRegion.GetLength(0) || bufferCellArray.GetLength(1) != this.progressRegion.GetLength(1)) { flag = true; } else { flag = false; } bool flag1 = flag; this.progressRegion = bufferCellArray; if (!flag1) { this.rawui.SetBufferContents(this.location, this.progressRegion); return; } else { if (this.IsShowing) { this.Hide(); } this.Show(); return; } } else { this.progressRegion = bufferCellArray; this.Show(); return; } } else { this.Hide(); this.progressRegion = null; return; } }
public override void SetBufferContents(Coordinates origin, BufferCell[,] contents) { IntPtr stdHandle = PS2EXEHostRawUI.GetStdHandle(-11); PS2EXEHostRawUI.CHAR_INFO[,] cHARINFOArray = new PS2EXEHostRawUI.CHAR_INFO[contents.GetLength(0), contents.GetLength(1)]; PS2EXEHostRawUI.COORD cOORD = new PS2EXEHostRawUI.COORD() { X = (short)contents.GetLength(1), Y = (short)contents.GetLength(0) }; PS2EXEHostRawUI.COORD cOORD1 = cOORD; PS2EXEHostRawUI.COORD cOORD2 = new PS2EXEHostRawUI.COORD() { X = 0, Y = 0 }; PS2EXEHostRawUI.COORD cOORD3 = cOORD2; PS2EXEHostRawUI.SMALL_RECT sMALLRECT = new PS2EXEHostRawUI.SMALL_RECT() { Left = (short)origin.X, Top = (short)origin.Y, Right = (short)(origin.X + contents.GetLength(1) - 1), Bottom = (short)(origin.Y + contents.GetLength(0) - 1) }; PS2EXEHostRawUI.SMALL_RECT sMALLRECT1 = sMALLRECT; for (int i = 0; i < contents.GetLength(0); i++) { for (int j = 0; j < contents.GetLength(1); j++) { PS2EXEHostRawUI.CHAR_INFO cHARINFO = new PS2EXEHostRawUI.CHAR_INFO() { AsciiChar = contents[i, j].Character, Attributes = (ushort)((int)contents[i, j].ForegroundColor + (int)contents[i, j].BackgroundColor * 16) }; cHARINFOArray[i, j] = cHARINFO; } } PS2EXEHostRawUI.WriteConsoleOutput(stdHandle, cHARINFOArray, cOORD1, cOORD3, ref sMALLRECT1); }
Show() { if (!IsShowing) { // Get temporary reference to the progress region since it can be // changed at any time by a call to WriteProgress. BufferCell[,] tempProgressRegion = _progressRegion; if (tempProgressRegion == null) { return; } // The location where we show ourselves is always relative to the screen buffer's current window position. int rows = tempProgressRegion.GetLength(0); int cols = tempProgressRegion.GetLength(1); _savedCursor = _rawui.CursorPosition; _location.X = 0; #if UNIX _location.Y = _rawui.CursorPosition.Y; // if cursor is not on left edge already move down one line if (_rawui.CursorPosition.X != 0) { _location.Y++; _rawui.CursorPosition = _location; } // if the cursor is at the bottom, create screen buffer space by scrolling int scrollRows = rows - ((_rawui.BufferSize.Height - 1) - _location.Y); if (scrollRows > 0) { // Scroll the console screen up by 'scrollRows' var bottomLocation = _location; bottomLocation.Y = _rawui.BufferSize.Height; _rawui.CursorPosition = bottomLocation; for (int i = 0; i < scrollRows; i++) { Console.Out.Write('\n'); } _location.Y -= scrollRows; _savedCursor.Y -= scrollRows; } // create cleared region to clear progress bar later _savedRegion = tempProgressRegion; for (int row = 0; row < rows; row++) { for (int col = 0; col < cols; col++) { _savedRegion[row, col].Character = ' '; } } // put cursor back to where output should be _rawui.CursorPosition = _location; #else _location = _rawui.WindowPosition; // We have to show the progress pane in the first column, as the screen buffer at any point might contain // a CJK double-cell characters, which makes it impractical to try to find a position where the pane would // not slice a character. Column 0 is the only place where we know for sure we can place the pane. _location.Y = Math.Min(_location.Y + 2, _bufSize.Height); // Save off the current contents of the screen buffer in the region that we will occupy _savedRegion = _rawui.GetBufferContents( new Rectangle(_location.X, _location.Y, _location.X + cols - 1, _location.Y + rows - 1)); #endif // replace the saved region in the screen buffer with our progress display _rawui.SetBufferContents(_location, tempProgressRegion); } }
Show(PendingProgress pendingProgress) { Dbg.Assert(pendingProgress != null, "pendingProgress may not be null"); _bufSize = _rawui.BufferSize; // In order to keep from slicing any CJK double-cell characters that might be present in the screen buffer, // we use the full width of the buffer. int maxWidth = _bufSize.Width; int maxHeight = Math.Max(5, _rawui.WindowSize.Height / 3); string[] contents = pendingProgress.Render(maxWidth, maxHeight, _rawui); if (contents == null) { // There's nothing to show. Hide(); _progressRegion = null; return; } // NTRAID#Windows OS Bugs-1061752-2004/12/15-sburns should read a skin setting here... BufferCell[,] newRegion = _rawui.NewBufferCellArray(contents, _ui.ProgressForegroundColor, _ui.ProgressBackgroundColor); Dbg.Assert(newRegion != null, "NewBufferCellArray has failed!"); if (_progressRegion == null) { // we've never shown this pane before. _progressRegion = newRegion; Show(); } else { // We have shown the pane before. We have to be smart about when we restore the saved region to minimize // flicker. We need to decide if the new contents will change the dimensions of the progress pane // currently being shown. If it will, then restore the saved region, and show the new one. Otherwise, // just blast the new one on top of the last one shown. // We're only checking size, not content, as we assume that the content will always change upon receipt // of a new ProgressRecord. That's not guaranteed, of course, but it's a good bet. So checking content // would usually result in detection of a change, so why bother? bool sizeChanged = (newRegion.GetLength(0) != _progressRegion.GetLength(0)) || (newRegion.GetLength(1) != _progressRegion.GetLength(1)) ? true : false; _progressRegion = newRegion; if (sizeChanged) { if (IsShowing) { Hide(); } Show(); } else { _rawui.SetBufferContents(_location, _progressRegion); } } }