123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435 |
- /*
- ConFrames - Gui Stuff for Console Windows
- Copyright (C) 2017-2018 Topten Software.
- ConFrames is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
- ConFrames is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with ConFrames. If not, see <http://www.gnu.org/licenses/>.
- */
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Runtime.InteropServices;
- namespace ConFrames
- {
- public class Desktop
- {
- public Desktop(int width, int height)
- {
- // Save stdout
- _stdout = Interop.GetStdHandle(Interop.STD_OUTPUT_HANDLE);
-
- // Create buffer
- _buffer = Interop.CreateConsoleScreenBuffer(Interop.GENERIC_READWRITE, (uint)0, IntPtr.Zero, Interop.CONSOLE_TEXTMODE_BUFFER, IntPtr.Zero);
- // Default colors
- ActiveBorderBackgroundColor = ConsoleColor.Blue;
- ActiveBorderLineColor = ConsoleColor.White;
- InactiveBorderLineColor = ConsoleColor.Gray;
- InactiveBorderBackgroundColor = ConsoleColor.DarkBlue;
- // Default desktop size
- DesktopSize = new Size(width, height);
- DesktopColor = ConsoleColor.DarkBlue;
- }
- // Handle to the screen and stdout buffers
- IntPtr _stdout;
- IntPtr _buffer;
- // Desktop size
- Size _desktopSize;
- public Size DesktopSize
- {
- get { return _desktopSize; }
- set
- {
- try
- {
- // Try to set it
- Interop.SetBufferAndScreenSize(_buffer, (short)value.Width, (short)value.Height);
- // Save it
- _desktopSize = value;
- }
- catch
- {
- try
- {
- // try to set it back
- Interop.SetBufferAndScreenSize(_buffer, (short)_desktopSize.Width, (short)_desktopSize.Height);
- }
- catch { }
- throw;
- }
- }
- }
- // List of all windows
- List<Window> _windows = new List<Window>();
- // Register a new window
- internal void AddWindow(Window window)
- {
- if (_windows.IndexOf(window)<0)
- {
- _windows.Add(window);
- InvalidateDesktop();
- }
- }
- // Remove a window
- internal void RemoveWindow(Window window)
- {
- _windows.Remove(window);
- InvalidateDesktop();
- }
- // Colors
- public ConsoleColor ActiveBorderBackgroundColor
- {
- get;
- set;
- }
- public ConsoleColor ActiveBorderLineColor
- {
- get;
- set;
- }
- public ConsoleColor InactiveBorderBackgroundColor
- {
- get;
- set;
- }
- public ConsoleColor InactiveBorderLineColor
- {
- get;
- set;
- }
- // Color of area behind all windows
- ConsoleColor _desktopColor;
- public ConsoleColor DesktopColor
- {
- get
- {
- return _desktopColor;
- }
- set
- {
- _desktopColor = value;
- InvalidateDesktop();
- }
- }
- // Called just before repainting the screen
- protected virtual void OnWillUpdate()
- {
- }
- // Called just after repainting the screen
- protected virtual void OnDidUpdate()
- {
- }
- // Called just before waiting for input
- protected virtual void OnEnterProcessing()
- {
- }
- // Called just after waiting for input
- protected virtual void OnLeaveProcessing()
- {
- }
- // Preview received keys - return true if handled
- protected virtual bool OnPreviewKey(ConsoleKeyInfo key)
- {
- if (PreviewKey != null)
- return PreviewKey(key);
- return false;
- }
- // Handler
- public Func<ConsoleKeyInfo, bool> PreviewKey;
- // Get/Set the currently active window
- public Window ActiveWindow
- {
- get { return _windows.Count == 0 ? null : _windows[_windows.Count - 1]; }
- set
- {
- var oldActive = ActiveWindow;
- int pos = _windows.IndexOf(value);
- if (pos < _windows.Count-1)
- {
- _windows.RemoveAt(pos);
- _windows.Add(value);
- }
- if (oldActive!=ActiveWindow)
- {
- Invalidate(oldActive);
- Invalidate(ActiveWindow);
- }
- }
- }
- // Invalidate flags
- bool _needRedraw = false;
- bool _needClear = false;
- public void Invalidate(Window w)
- {
- _needRedraw = true;
- }
- public void InvalidateDesktop()
- {
- _needClear = true;
- _needRedraw = true;
- }
- // Update
- public void Update()
- {
- // Quit if we don't need a redraw
- if (_needRedraw)
- {
- // Notify
- OnWillUpdate();
- // Clear flag
- _needRedraw = false;
- // Do we need to clear?
- if (_needClear)
- {
- _needClear = false;
- // Get screens size
- Interop.CONSOLE_SCREEN_BUFFER_INFO info;
- Interop.GetConsoleScreenBufferInfo(_buffer, out info);
- // Create buffer
- CharInfo[] buf = new CharInfo[info.dwSize.X * info.dwSize.Y];
- // Clear buffer
- var defAttributes = (ushort)((ushort)0 | ((ushort)_desktopColor << 4));
- for (int i = 0; i < buf.Length; ++i)
- {
- buf[i].Attributes = defAttributes;
- buf[i].Char = (char)' ';
- }
- // Copy it
- var r = new Interop.SmallRect()
- {
- Top = (short)0,
- Left = (short)0,
- Right = (short)info.dwSize.X,
- Bottom = (short)info.dwSize.Y,
- };
- Interop.WriteConsoleOutput(_buffer,
- buf,
- new Interop.Coord() { X = (short)info.dwSize.X, Y = info.dwSize.Y },
- new Interop.Coord() { X = 0, Y = 0 },
- ref r);
- }
- // Draw all windows
- foreach (var w in _windows)
- {
- var buf = w.Draw();
- var r = new Interop.SmallRect()
- {
- Top = (short)w.FrameRectangle.Top,
- Left = (short)w.FrameRectangle.Left,
- Right = (short)w.FrameRectangle.Right,
- Bottom = (short)w.FrameRectangle.Bottom,
- };
- Interop.WriteConsoleOutput(_buffer,
- buf,
- new Interop.Coord() { X = (short)w.FrameRectangle.Width, Y = (short)w.FrameRectangle.Height },
- new Interop.Coord() { X = 0, Y = 0 },
- ref r);
- }
- // Finished
- OnDidUpdate();
- }
- // Reposition cursor according to how the active window wants it
- var active = ActiveWindow;
- if (active != null)
- {
- if (active.CursorPosition.X >= 0 && active.CursorPosition.Y >= 0 &&
- active.CursorPosition.X < active.FrameRectangle.Width - 2 &&
- active.CursorPosition.Y < active.FrameRectangle.Height - 2)
- {
- Interop.SetConsoleCursorPosition(_buffer, new Interop.Coord(
- (short)(active.FrameRectangle.Left + active.CursorPosition.X + 1),
- (short)(active.FrameRectangle.Top + active.CursorPosition.Y + 1)
- ));
- Interop.SetConsoleCursorVisible(_buffer, active.CursorVisible);
- }
- else
- {
- Interop.SetConsoleCursorVisible(_buffer, false);
- }
- }
- else
- {
- Interop.SetConsoleCursorVisible(_buffer, false);
- }
- }
- // Cancel from the process loop
- bool _continueProcessing = false;
- public void EndProcessing()
- {
- _continueProcessing = false;
- }
- // Process
- public void Process()
- {
- // Notfiy
- OnEnterProcessing();
- // Make active
- ViewMode = ViewMode.Desktop;
- // Process loop
- _continueProcessing = true;
- while (_continueProcessing)
- {
- // Do any update
- Update();
- // Bring console to front
- BringToFront();
- // Read the next key
- var key = Console.ReadKey(true);
- // Switch windows?
- if (key.Key == ConsoleKey.Tab)
- {
- if (key.Modifiers == ConsoleModifiers.Control)
- {
- if (_windows.Any())
- {
- var top = _windows[_windows.Count - 1];
- _windows.RemoveAt(_windows.Count-1);
- _windows.Insert(0, top);
- _needRedraw = true;
- }
- continue;
- }
- if (key.Modifiers == (ConsoleModifiers.Control | ConsoleModifiers.Shift))
- {
- if (_windows.Any())
- {
- var top = _windows[0];
- _windows.RemoveAt(0);
- _windows.Add(top);
- _needRedraw = true;
- }
- continue;
- }
- }
- // Toggle to stdout?
- if (key.Key == ConsoleKey.F4 && key.Modifiers == 0)
- {
- ViewMode = ViewMode.StdOut;
- Console.ReadKey(true);
- ViewMode = ViewMode.Desktop;
- continue;
- }
- // Preview key event
- if (OnPreviewKey(key))
- continue;
- // Send key to the active window
- var aw = ActiveWindow;
- if (aw!= null)
- {
- aw.OnKey(key);
- }
- }
- // Notify
- OnLeaveProcessing();
- // Finished
- return;
- }
- // Bring the console window to foreground
- IntPtr _oldForegroundWindow;
- public void BringToFront()
- {
- _oldForegroundWindow = Interop.GetActiveWindow();
- Interop.SetForegroundWindow(Interop.GetConsoleWindow());
- }
- // Restore the old active foreground window
- public void RestoreForegroundWindow()
- {
- if (_oldForegroundWindow==IntPtr.Zero)
- {
- _oldForegroundWindow = System.Diagnostics.Process.GetCurrentProcess().MainWindowHandle;
- }
- if (_oldForegroundWindow !=IntPtr.Zero)
- {
- Interop.SetForegroundWindow(_oldForegroundWindow);
- _oldForegroundWindow = IntPtr.Zero;
- }
- }
- // Set the view mode (desktop or stdout)
- ViewMode _viewMode = ViewMode.StdOut;
- public ViewMode ViewMode
- {
- get
- {
- return _viewMode;
- }
- set
- {
- if (_viewMode !=value)
- {
- _viewMode = value;
- if (_viewMode==ViewMode.Desktop)
- {
- Interop.SetConsoleActiveScreenBuffer(_buffer);
- }
- else
- {
- Interop.SetConsoleActiveScreenBuffer(_stdout);
- }
- }
- }
- }
- }
- }
|