InteractiveComputer/Apps/NotepadApp.cs
using System;
using System.Linq;
using Sandbox.UI;
using PaneOS.InteractiveComputer;
namespace PaneOS.InteractiveComputer.Apps;
[ComputerApp( "system.notepad", "Notepad", Icon = "NP", SortOrder = 10 )]
public sealed class NotepadApp : IComputerApp
{
public ComputerAppSession Run( ComputerAppContext context )
{
return new ComputerAppSession
{
Title = "Untitled - Notepad",
Icon = "NP",
Content = new NotepadPanel( context )
};
}
}
[StyleSheet( "InteractiveComputerApps.scss" )]
public sealed class NotepadPanel : ComputerWarmupPanel
{
private readonly ComputerAppContext context;
private ComputerInputAwareTextEntry textEntry = null!;
private string currentFilePath;
public NotepadPanel( ComputerAppContext context )
{
this.context = context;
AddClass( "notepad-app" );
BuildUi();
}
protected override void WarmupRefresh()
{
BuildUi();
}
private void BuildUi()
{
var currentText = textEntry?.Text;
var caretPosition = textEntry?.CaretPosition ?? 0;
DeleteChildren( true );
var toolbar = new Panel { Parent = this };
toolbar.AddClass( "notepad-toolbar" );
var openButton = new Button( "Open" ) { Parent = toolbar };
openButton.AddClass( "notepad-toolbar-button" );
openButton.AddEventListener( "onclick", OpenFile );
var saveButton = new Button( "Save" ) { Parent = toolbar };
saveButton.AddClass( "notepad-toolbar-button" );
saveButton.AddEventListener( "onclick", SaveFile );
var saveAsButton = new Button( "Save As" ) { Parent = toolbar };
saveAsButton.AddClass( "notepad-toolbar-button" );
saveAsButton.AddEventListener( "onclick", SaveFileAs );
textEntry = new ComputerInputAwareTextEntry( ShouldSuppressInput )
{
Parent = this,
Text = currentText ?? "",
Multiline = true,
Placeholder = ""
};
textEntry.AddClass( "notepad-text" );
if ( currentText is null )
{
LoadInitialDocument();
}
else
{
textEntry.CaretPosition = Math.Clamp( caretPosition, 0, textEntry.TextLength );
}
}
public override void Tick()
{
base.Tick();
if ( context.LoadValue( "text" ) == textEntry.Text )
return;
context.SaveValue( "text", textEntry.Text );
}
private void LoadInitialDocument()
{
currentFilePath = context.LoadValue( "file_path" ) ?? "";
textEntry.Text = string.IsNullOrWhiteSpace( currentFilePath )
? context.LoadValue( "text" ) ?? ""
: context.ReadTextFile( currentFilePath );
textEntry.CaretPosition = textEntry.TextLength;
textEntry.Focus();
}
private bool ShouldSuppressInput()
{
return context.Runtime.ShouldBlockInput( context.State.InstanceId ) ||
context.State.IsMinimized ||
context.Runtime.FocusedApp?.State.InstanceId != context.State.InstanceId;
}
private void OpenFile()
{
context.ShowOpenFileDialog(
new ComputerFileDialogOptions
{
Title = "Open Text File",
InitialPath = context.GetDefaultDocumentsPath(),
AllowedExtensions = new[] { "txt" },
ConfirmButtonText = "Open"
},
result =>
{
if ( !result.Confirmed )
return;
currentFilePath = result.VirtualPath;
context.SaveValue( "file_path", currentFilePath );
textEntry.Text = context.ReadTextFile( currentFilePath );
textEntry.CaretPosition = textEntry.TextLength;
textEntry.Focus();
} );
}
private void SaveFile()
{
if ( string.IsNullOrWhiteSpace( currentFilePath ) )
{
SaveFileAs();
return;
}
context.WriteTextFile( currentFilePath, textEntry.Text );
context.SaveValue( "file_path", currentFilePath );
}
private void SaveFileAs()
{
context.ShowSaveFileDialog(
new ComputerFileDialogOptions
{
Title = "Save Text File",
InitialPath = context.GetDefaultDocumentsPath(),
DefaultFileName = string.IsNullOrWhiteSpace( currentFilePath ) ? "Untitled.txt" : currentFilePath.Split( '/' ).Last(),
AllowedExtensions = new[] { "txt" },
ConfirmButtonText = "Save"
},
result =>
{
if ( !result.Confirmed )
return;
currentFilePath = EnsureTxtExtension( result.VirtualPath );
context.WriteTextFile( currentFilePath, textEntry.Text );
context.SaveValue( "file_path", currentFilePath );
textEntry.Focus();
} );
}
private static string EnsureTxtExtension( string virtualPath )
{
return virtualPath.EndsWith( ".txt", StringComparison.OrdinalIgnoreCase )
? virtualPath
: $"{virtualPath}.txt";
}
}