parent
a6377d1a57
commit
d0853e23bc
@ -0,0 +1,39 @@
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace SCI.AsciiArt;
|
||||
|
||||
public class Generator {
|
||||
public static async Task<string> FromImage (string imagePath, int width) {
|
||||
// Ensure image exists
|
||||
if (!File.Exists (imagePath)) {
|
||||
throw new FileNotFoundException ($"The specified file '{imagePath}' does not exist");
|
||||
}
|
||||
|
||||
var process = new Process ();
|
||||
process.StartInfo = new ProcessStartInfo () {
|
||||
FileName = "jp2a",
|
||||
Arguments = $"--width={width} \"{imagePath}\"",
|
||||
RedirectStandardInput = true,
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true,
|
||||
CreateNoWindow = true,
|
||||
UseShellExecute = false
|
||||
};
|
||||
|
||||
process.Start ();
|
||||
|
||||
// Wait up to one second for the task to finish
|
||||
try {
|
||||
var cancellationTokenSource = new CancellationTokenSource (1000);
|
||||
await process.WaitForExitAsync (cancellationTokenSource.Token);
|
||||
} catch (TaskCanceledException) {
|
||||
throw new TimeoutException ("jp2a did not finish after 1000ms, process was killed");
|
||||
}
|
||||
|
||||
if (process.ExitCode != 0) {
|
||||
throw new Exception ($"jp2a returned with exit code {process.ExitCode}.\n{process.StandardError.ReadToEnd ()}");
|
||||
}
|
||||
|
||||
return await process.StandardOutput.ReadToEndAsync ();
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
using Mindmagma.Curses;
|
||||
|
||||
namespace SCI.CursesWrapper;
|
||||
|
||||
public class ContentWindow : Window {
|
||||
public ContentWindow (nint rootScreen, InputHandler inputHandler) :
|
||||
base (
|
||||
0, 1,
|
||||
CursesWrapper.GetWidth (rootScreen),
|
||||
CursesWrapper.GetHeight (rootScreen) - 2,
|
||||
inputHandler
|
||||
)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new nested child window without inner padding
|
||||
/// </summary>
|
||||
public Window CreateInnerWindow () {
|
||||
return new Window (-1, -1, -2, -2, this) {
|
||||
BorderEnabled = false
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes all children elements and redraws the window
|
||||
/// </summary>
|
||||
public void Clean () {
|
||||
foreach (var window in ChildWindows.ToList ()) {
|
||||
window.Destroy (true);
|
||||
}
|
||||
|
||||
// Clear window and redraw
|
||||
NCurses.ClearWindow (WindowId);
|
||||
SetBorder (true);
|
||||
Draw ();
|
||||
}
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
namespace SCI.CursesWrapper;
|
||||
|
||||
public class InnerWindow : Window {
|
||||
public InnerWindow (nint rootScreen, InputHandler inputHandler) :
|
||||
base (
|
||||
0, 1,
|
||||
CursesWrapper.GetWidth (rootScreen),
|
||||
CursesWrapper.GetHeight (rootScreen) - 2,
|
||||
inputHandler
|
||||
)
|
||||
{ }
|
||||
}
|
@ -0,0 +1,109 @@
|
||||
|
||||
using System.Drawing;
|
||||
using Mindmagma.Curses;
|
||||
|
||||
namespace SCI.CursesWrapper;
|
||||
|
||||
public class ScrollWindow : Window {
|
||||
private nint _innerPadId;
|
||||
public nint InnerPadId { get { return _innerPadId; }}
|
||||
|
||||
private Point _scrollPosition;
|
||||
public Point ScrollPosition { get { return _scrollPosition; }}
|
||||
|
||||
private Size _padSize;
|
||||
public Size PadSize { get { return _padSize; }}
|
||||
|
||||
public ScrollWindow (Window parentWindow, InputHandler inputHandler, int innerHeight = -1) :
|
||||
base (0, 0, 0, 0, inputHandler, parentWindow)
|
||||
{
|
||||
var padWidth = GetUsableWidth ();
|
||||
var padHeight = innerHeight;
|
||||
|
||||
if (padHeight == -1) {
|
||||
padHeight = parentWindow.GetUsableHeight ();
|
||||
}
|
||||
|
||||
_innerPadId = NCurses.NewPad (padHeight, padWidth);
|
||||
|
||||
_padSize = new Size (padWidth, padHeight);
|
||||
|
||||
NCurses.WindowBackground (InnerPadId, ColorSchemes.TextInputField ());
|
||||
ShowPad ();
|
||||
|
||||
OnKeyPress += ScrollKeyHandler;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scrolls the window up or down on up key or down key
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private void ScrollKeyHandler (object sender, NCursesKeyPressEventArgs e) {
|
||||
if (e.SourceWindow is null || e.SourceWindow != this) return;
|
||||
|
||||
if (e.KeyCode == CursesKey.UP) {
|
||||
ScrollTo (ScrollPosition.X, ScrollPosition.Y - 1);
|
||||
} else if (e.KeyCode == CursesKey.DOWN) {
|
||||
ScrollTo (ScrollPosition.X, ScrollPosition.Y + 1);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scrolls the pad to the specified coordinates
|
||||
/// </summary>
|
||||
/// <param name="scrollX"></param>
|
||||
/// <param name="scrollY"></param>
|
||||
public void ScrollTo (int scrollX, int scrollY) {
|
||||
if (ParentWindow is null) return;
|
||||
|
||||
_scrollPosition = new Point (scrollX, scrollY);
|
||||
ShowPad ();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shows the pad the current scroll location
|
||||
/// </summary>
|
||||
public void ShowPad () {
|
||||
if (ParentWindow is null) return;
|
||||
|
||||
var scrollToX = ScrollPosition.X;
|
||||
var scrollToY = ScrollPosition.Y;
|
||||
|
||||
var viewableWidth = GetUsableWidth ();
|
||||
var viewableHeight = GetUsableHeight ();
|
||||
|
||||
// Check for unnecessary scrolling due to small Pad size
|
||||
if (PadSize.Width <= viewableWidth) {
|
||||
scrollToX = 0;
|
||||
}
|
||||
if (PadSize.Height <= viewableHeight) {
|
||||
scrollToY = 0;
|
||||
}
|
||||
|
||||
// Check values for upper bounds
|
||||
if (scrollToX > PadSize.Width - viewableWidth) scrollToX = PadSize.Width - viewableWidth;
|
||||
if (scrollToY > PadSize.Height - viewableHeight) scrollToY = PadSize.Height - viewableHeight;
|
||||
|
||||
// Check values for lower bounds
|
||||
if (scrollToX < 0) scrollToX = 0;
|
||||
if (scrollToY < 0) scrollToY = 0;
|
||||
|
||||
// Store potentially updated scroll coordinates
|
||||
_scrollPosition = new Point (scrollToX, scrollToY);
|
||||
|
||||
var fromY = Position.Y;
|
||||
var fromX = Position.X;
|
||||
var toY = viewableHeight;
|
||||
var toX = viewableWidth - 2; // TODO: Why the two? How is the geometry this wong?!
|
||||
|
||||
NCurses.PadRefresh (
|
||||
_innerPadId,
|
||||
scrollToY, scrollToX,
|
||||
fromY,
|
||||
fromX,
|
||||
toY,
|
||||
toX
|
||||
);
|
||||
}
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
namespace ANSI_Fahrplan.Screens;
|
||||
|
||||
public abstract class ScrollableScreen : Screen {
|
||||
|
||||
public ScrollableScreen (nint rootWindow) : base (rootWindow) {}
|
||||
|
||||
|
||||
}
|
After Width: | Height: | Size: 16 KiB |
Loading…
Reference in new issue