Files
egtstone3d/ScriptWindow/ScriptWindowVM.vb
T
Demetrio Cassarino c7debc8c31 -pulizia codice script
2025-03-12 09:47:40 +01:00

649 lines
22 KiB
VB.net

Imports EgtUILib
Imports EgtWPFLib5
Imports System.IO
Imports System.Text
Imports System.Text.RegularExpressions
Imports System.Windows.Threading
Public Class ScriptWindowVM
Inherits VMBase
#Region "FIELD & PROPERTIES"
Public textChangedTimer As DispatcherTimer
#Region "Script Color"
' Dizionario con Regex Precompilate e Colori Associati
Private patterns As New Dictionary(Of Regex, System.Windows.Media.Color) From {
{RegexM.KeywordRegex, ColorScriptM.KeywordColor},
{RegexM.ValueRegex, ColorScriptM.ValueColor},
{RegexM.FunctionRegex, ColorScriptM.FunctionColor},
{RegexM.InfoRegex, ColorScriptM.InfoColor},
{RegexM.EgtRegex, ColorScriptM.EgtColor},
{RegexM.BracketRegex, ColorScriptM.BracketColor},
{RegexM.TextRegex, ColorScriptM.TextColor},
{RegexM.NumberRegex, ColorScriptM.NumberColor}
}
#End Region ' Script Color
Private m_sNameFile As String = String.Empty
Public Property sNameFile As String
Get
Return m_sNameFile
End Get
Set(value As String)
m_sNameFile = value
NotifyPropertyChanged(NameOf(sNameFile))
End Set
End Property
Private m_sRichTextParagraph As String = String.Empty
Public Property sRichTextParagraph As String
Get
Return m_sRichTextParagraph
End Get
Set(value As String)
m_sRichTextParagraph = value
NotifyPropertyChanged(NameOf(sRichTextParagraph))
End Set
End Property
Private m_nFontSizeList As New List(Of Integer)
Public Property FontSizeList As List(Of Integer)
Get
Return m_nFontSizeList
End Get
Set(value As List(Of Integer))
m_nFontSizeList = value
NotifyPropertyChanged(NameOf(FontSizeList))
End Set
End Property
Private m_nSelFontSize As Integer
Public Property SelFontSize As Integer
Get
Return m_nSelFontSize
End Get
Set(value As Integer)
m_nSelFontSize = value
If Not IsNothing(m_nSelFontSize) Then ChangeFontSize(m_nSelFontSize)
NotifyPropertyChanged(NameOf(SelFontSize))
End Set
End Property
Friend Sub SetSelFontSize(value As Integer)
m_nSelFontSize = value
NotifyPropertyChanged(NameOf(SelFontSize))
End Sub
Private m_sFontFamilyList As New List(Of FontFamily)
Public Property FontFamilyList As List(Of FontFamily)
Get
Return m_sFontFamilyList
End Get
Set(value As List(Of FontFamily))
m_sFontFamilyList = value
NotifyPropertyChanged(NameOf(FontFamilyList))
End Set
End Property
Private m_sSelFontFamily As FontFamily
Public Property SelFontFamily As FontFamily
Get
Return m_sSelFontFamily
End Get
Set(value As FontFamily)
m_sSelFontFamily = value
If Not IsNothing(m_sSelFontFamily) Then ChangeFontFamily(m_sSelFontFamily)
NotifyPropertyChanged(NameOf(SelFontFamily))
End Set
End Property
Friend Sub SetSelFontFamily(value As FontFamily)
m_sSelFontFamily = value
NotifyPropertyChanged(NameOf(SelFontFamily))
End Sub
Private m_bBoldIsChecked As Boolean = False
Public Property BoldIsChecked As Boolean
Get
Return m_bBoldIsChecked
End Get
Set(value As Boolean)
m_bBoldIsChecked = value
NotifyPropertyChanged(NameOf(BoldIsChecked))
End Set
End Property
Private m_bItalicIsChecked As Boolean = False
Public Property ItalicIsChecked As Boolean
Get
Return m_bItalicIsChecked
End Get
Set(value As Boolean)
m_bItalicIsChecked = value
NotifyPropertyChanged(NameOf(ItalicIsChecked))
End Set
End Property
Private m_bUnderlineChecked As Boolean = False
Public Property UnderlineChecked As Boolean
Get
Return m_bUnderlineChecked
End Get
Set(value As Boolean)
m_bUnderlineChecked = value
NotifyPropertyChanged(NameOf(UnderlineChecked))
End Set
End Property
Private m_bLeftIsChecked As Boolean = False
Public Property LeftIsChecked As Boolean
Get
Return m_bLeftIsChecked
End Get
Set(value As Boolean)
m_bLeftIsChecked = value
SetCenterIsChecked(False)
SetJustifyIsChecked(False)
NotifyPropertyChanged(NameOf(LeftIsChecked))
End Set
End Property
Friend Sub SetLeftIsChecked(value As Boolean)
m_bLeftIsChecked = value
NotifyPropertyChanged(NameOf(LeftIsChecked))
End Sub
Private m_bCenterIsChecked As Boolean = False
Public Property CenterIsChecked As Boolean
Get
Return m_bCenterIsChecked
End Get
Set(value As Boolean)
m_bCenterIsChecked = value
SetLeftIsChecked(False)
SetJustifyIsChecked(False)
NotifyPropertyChanged(NameOf(CenterIsChecked))
End Set
End Property
Friend Sub SetCenterIsChecked(value As Boolean)
m_bCenterIsChecked = value
NotifyPropertyChanged(NameOf(CenterIsChecked))
End Sub
Private m_bJustifyIsChecked As Boolean = False
Public Property JustifyIsChecked As Boolean
Get
Return m_bJustifyIsChecked
End Get
Set(value As Boolean)
m_bJustifyIsChecked = value
SetLeftIsChecked(False)
SetCenterIsChecked(False)
NotifyPropertyChanged(NameOf(JustifyIsChecked))
End Set
End Property
Friend Sub SetJustifyIsChecked(value As Boolean)
m_bJustifyIsChecked = value
NotifyPropertyChanged(NameOf(JustifyIsChecked))
End Sub
Private m_FileAlignLeftSVG As String = String.Empty
Public Property FileAlignLeftSVG As String
Get
Return m_FileAlignLeftSVG
End Get
Set(value As String)
m_FileAlignLeftSVG = value
NotifyPropertyChanged(NameOf(FileAlignLeftSVG))
End Set
End Property
Friend Sub SetFileAlignLeftSVG(sFileAlignLeftSVG As String)
m_FileAlignLeftSVG = sFileAlignLeftSVG
NotifyPropertyChanged(NameOf(FileAlignLeftSVG))
End Sub
Private m_FileAlignCenterSVG As String = String.Empty
Public Property FileAlignCenterSVG As String
Get
Return m_FileAlignCenterSVG
End Get
Set(value As String)
m_FileAlignCenterSVG = value
NotifyPropertyChanged(NameOf(FileAlignCenterSVG))
End Set
End Property
Friend Sub SetFileAlignCenterSVG(sFileAlignCenterSVG As String)
m_FileAlignCenterSVG = sFileAlignCenterSVG
NotifyPropertyChanged(NameOf(FileAlignCenterSVG))
End Sub
Private m_FileAlignJustifySVG As String = String.Empty
Public Property FileAlignJustifySVG As String
Get
Return m_FileAlignJustifySVG
End Get
Set(value As String)
m_FileAlignJustifySVG = value
NotifyPropertyChanged(NameOf(FileAlignJustifySVG))
End Set
End Property
Friend Sub SetFileAlignJustifySVG(sFileAlignJustifySVG As String)
m_FileAlignJustifySVG = sFileAlignJustifySVG
NotifyPropertyChanged(NameOf(FileAlignJustifySVG))
End Sub
#Region "Messages"
Public ReadOnly Property Title As String
Get
Return "Script File" ' Opzioni
End Get
End Property
Public ReadOnly Property Conferma_Msg As String
Get
Return EgtMsg(110003) ' Conferma
End Get
End Property
Public ReadOnly Property Salva_Msg As String
Get
Return EgtMsg(110013) ' Salva
End Get
End Property
Public ReadOnly Property Annulla_Msg As String
Get
Return EgtMsg(110004) ' Annulla
End Get
End Property
#End Region ' Messages
' Definizione Comandi
Private m_ConfermaCmd As ICommand
Private m_cmdSaveAs As ICommand
Private m_cmdAnnulla As ICommand
Private m_cmdTextColor As ICommand
#End Region ' Fields & Properties
#Region "CONSTRUCTOR"
Sub New()
Map.SetRefScriptWindowVM(Me)
If m_nFontSizeList.Count <= 0 Then CreateFontSizeList()
If m_sFontFamilyList.Count <= 0 Then CreateFontFamilyList()
SetToolbar()
SetFileAlignLeftSVG(Map.refMainWindowVM.MainWindowM.sResourcesDir & "\alignleft.svg")
SetFileAlignCenterSVG(Map.refMainWindowVM.MainWindowM.sResourcesDir & "\aligncenter.svg")
SetFileAlignJustifySVG(Map.refMainWindowVM.MainWindowM.sResourcesDir & "\alignjustify.svg")
End Sub
#End Region ' Constructor
#Region "METHODS"
Public Function SaveProject() As Boolean
' Determina il nome del file di default
Dim sFile As String = If(String.IsNullOrWhiteSpace(m_sNameFile), "New.lua", $"{m_sNameFile}.lua")
sFile = IO.Path.ChangeExtension(sFile, "lua")
' Assegnazione nome file con dialogo
Dim SaveFileDialog As New EgtManageFileDialogV(Application.Current.MainWindow, New EgtManageFileDialogVM()) With {
.Title = EgtMsg(110013), ' Salva
.Filter = "lua files (*.lua)|*.lua",
.FileName = sFile,
.FilterIndex = 1,
.InitialDirectory = Map.refMainWindowVM.MainWindowM.sTempDir,
.ValidateNames = False,
.OverwritePrompt = True,
.Mode = 1
}
' Mostra la finestra di dialogo e ottieni il percorso del file selezionato
Dim sFileName As String = String.Empty
If SaveFileDialog.ShowDialog() = Windows.Forms.DialogResult.OK Then
Dim fileExtension = IO.Path.GetExtension(SaveFileDialog.SafeFileName)
sFileName = IO.Path.Combine(SaveFileDialog.InitialDirectory,
SaveFileDialog.SafeFileName & If(String.IsNullOrEmpty(fileExtension),
SaveFileDialog.SelFilter.sExstension.Trim("*"c), String.Empty))
End If
' Verifica se il nome del file è stato selezionato
If String.IsNullOrWhiteSpace(sFileName) Then Return False
' Salva il progetto e scrive lo script Lua
Dim bOk = Map.refSceneHostVM.SaveProj(sFileName)
WriteTextScriptLua(sFileName)
' Imposta lo stato della scena
Map.refSceneHostVM.MainScene.SetStatusNull()
Return bOk
End Function
Private Sub WriteTextScriptLua(sFileName As String)
If String.IsNullOrWhiteSpace(sFileName) Then Return ' Validazione input
Dim sFileScript As String = RichTextBox(sFileName) ' Ottieni contenuto da RichTextBox
File.WriteAllText(sFileName, sFileScript, Encoding.UTF8) ' Salva il file con codifica UTF-8
End Sub
Private Sub SaveScript(sPathFileScript As String, sRichTextParagraph As String)
If String.IsNullOrWhiteSpace(sPathFileScript) OrElse String.IsNullOrWhiteSpace(sRichTextParagraph) Then Return ' Validazione input
Map.refSceneHostVM.SaveProj(sPathFileScript) ' Salva il progetto nel percorso specificato
File.WriteAllText(sPathFileScript, sRichTextParagraph, Encoding.UTF8) ' Salva il contenuto con codifica UTF-8
End Sub
Public Function RichTextBox(sPathFileScript As String) As String
' Recupero il RichTextBox e il FlowDocument
Dim myRichTextBox As RichTextBox = Map.refScriptWindowV.sNameFile_RichTxBx
Dim myFlowDoc As FlowDocument = Map.refScriptWindowV.FDocumentFile
' Cancella il contenuto del documento e assegna un nuovo FlowDocument
myRichTextBox.Document.Blocks.Clear()
myRichTextBox.Document = myFlowDoc
' Ottiene il testo completo del documento
Dim textRange As New TextRange(myRichTextBox.Document.ContentStart, myRichTextBox.Document.ContentEnd)
Return textRange.Text
End Function
Private Sub CreateFontSizeList()
' Aggiunge solo font-size pari alla lista, con un semplice iteratore
m_nFontSizeList.AddRange(Enumerable.Range(8, 13).Where(Function(size) size Mod 2 = 0))
End Sub
Private Sub ChangeFontSize(nSelFontSize As Integer)
If nSelFontSize = GDB_ID.NULL Then Return
Dim pixelSize As Double = nSelFontSize * (96.0 / 72.0)
Dim textRange = New TextRange(Map.refScriptWindowV.sNameFile_RichTxBx.Selection.Start, Map.refScriptWindowV.sNameFile_RichTxBx.Selection.End)
textRange.ApplyPropertyValue(TextElement.FontSizeProperty, pixelSize)
End Sub
Private Sub CreateFontFamilyList()
' Aggiunge direttamente tutte le famiglie di font alla lista
m_sFontFamilyList.AddRange(Fonts.SystemFontFamilies)
End Sub
Private Sub ChangeFontFamily(sSelFontFamily As FontFamily)
If sSelFontFamily Is Nothing Then Return
Dim textRange = New TextRange(Map.refScriptWindowV.sNameFile_RichTxBx.Selection.Start, Map.refScriptWindowV.sNameFile_RichTxBx.Selection.End)
textRange.ApplyPropertyValue(TextElement.FontFamilyProperty, sSelFontFamily)
End Sub
Friend Sub SetToolbar()
Dim textRange As New TextRange(Map.refScriptWindowV.sNameFile_RichTxBx.Selection.Start, Map.refScriptWindowV.sNameFile_RichTxBx.Selection.[End])
' Recupera font e dimensione
SetSelFontFamily(textRange.GetPropertyValue(TextElement.FontFamilyProperty))
SetSelFontSize(textRange.GetPropertyValue(TextElement.FontSizeProperty))
If Not String.IsNullOrWhiteSpace(textRange.Text) Then
' Recupera proprietà di formattazione (Bold, Italic, Underline)
m_bBoldIsChecked = Equals(textRange.GetPropertyValue(TextElement.FontWeightProperty), FontWeights.Bold)
m_bItalicIsChecked = Equals(textRange.GetPropertyValue(TextElement.FontStyleProperty), FontStyles.Italic)
m_bUnderlineChecked = Equals(textRange.GetPropertyValue(Inline.TextDecorationsProperty), TextDecorations.Underline)
End If
' Recupera proprietà di allineamento
Dim alignment = textRange.GetPropertyValue(FlowDocument.TextAlignmentProperty)
m_bLeftIsChecked = Equals(alignment, TextAlignment.Left)
m_bCenterIsChecked = Equals(alignment, TextAlignment.Center)
m_bJustifyIsChecked = Equals(alignment, TextAlignment.Justify)
End Sub
Public Sub InsertText(ByVal sRichTextBox As RichTextBox, ByVal content As String)
' Verifica nullità e contenuto non vuoto
If String.IsNullOrWhiteSpace(content) OrElse sRichTextBox Is Nothing Then Return
' Sospende gli aggiornamenti visivi per migliorare le prestazioni
sRichTextBox.BeginChange()
Try
' Rimuove il testo selezionato (se esiste)
If Not String.IsNullOrEmpty(sRichTextBox.Selection.Text) Then sRichTextBox.Selection.Text = String.Empty
' Inserisce il contenuto e riposiziona il cursore
Dim textPointer As TextPointer = sRichTextBox.CaretPosition
textPointer.InsertTextInRun(content)
sRichTextBox.CaretPosition = textPointer.GetPositionAtOffset(content.Length, LogicalDirection.Forward)
Finally
' Ripristina gli aggiornamenti visivi
sRichTextBox.EndChange()
' Imposta il focus sulla RichTextBox
Keyboard.Focus(sRichTextBox)
End Try
End Sub
Public Sub SyntaxHighlighting(rtb As RichTextBox)
' Sospendere gli aggiornamenti visivi per migliorare le prestazioni
rtb.BeginChange()
Try
' Recupera il testo dalla RichTextBox
Dim textRange As New TextRange(rtb.Document.ContentStart, rtb.Document.ContentEnd)
Dim text As String = textRange.Text
' Applicare evidenziazione per ogni regex nel dizionario
For Each kvp In patterns
Dim regex As Regex = kvp.Key
Dim color As Color = kvp.Value
' Evidenzia le corrispondenze
Dim matches As MatchCollection = regex.Matches(text)
For Each match As Match In matches
HighlightText(rtb, match.Index, match.Length, color)
Next
Next
' Evidenzia commenti (esempio di commento Lua: "--")
Dim commentMatches = patterns.FirstOrDefault(Function(p) p.Key.ToString().Contains("--"))
If commentMatches.Key IsNot Nothing Then
HighlightComments(rtb, text, "--", ColorScriptM.CommentColor)
End If
Finally
' Riprendere gli aggiornamenti visivi
rtb.EndChange()
End Try
End Sub
Private Sub HighlightText(rtb As RichTextBox, startIndex As Integer, length As Integer, color As Color)
Dim startPointer As TextPointer = GetTextPosition(rtb.Document.ContentStart, startIndex)
Dim endPointer As TextPointer = GetTextPosition(startPointer, length)
Dim range As New TextRange(startPointer, endPointer)
range.ApplyPropertyValue(TextElement.ForegroundProperty, New SolidColorBrush(color))
End Sub
Private Sub HighlightComments(rtb As RichTextBox, text As String, commentSymbol As String, color As Color)
Dim startIndex As Integer = 0
While startIndex < text.Length
startIndex = text.IndexOf(commentSymbol, startIndex)
If startIndex = -1 Then Exit While
Dim endIndex As Integer = text.IndexOf(Environment.NewLine, startIndex)
If endIndex = -1 Then endIndex = text.Length
HighlightText(rtb, startIndex, endIndex - startIndex, color)
startIndex = endIndex
End While
End Sub
Private Function GetTextPosition(start As TextPointer, position As Integer) As TextPointer
Dim navigator As TextPointer = start
While navigator IsNot Nothing AndAlso position > 0
Dim context = navigator.GetPointerContext(LogicalDirection.Forward)
If context = TextPointerContext.Text Then
Dim run As String = navigator.GetTextInRun(LogicalDirection.Forward)
Dim count As Integer = Math.Min(run.Length, position)
navigator = navigator.GetPositionAtOffset(count)
position -= count
Else
navigator = navigator.GetPositionAtOffset(1)
End If
End While
Return navigator
End Function
Public Sub ProcessTextChanges()
SyntaxHighlighting(Map.refScriptWindowV.sNameFile_RichTxBx)
End Sub
Public Sub ChangeTimer()
If Not IsNothing(Map.refScriptWindowVM) AndAlso textChangedTimer Is Nothing Then
textChangedTimer = New DispatcherTimer()
textChangedTimer.Interval = TimeSpan.FromMilliseconds(500)
AddHandler textChangedTimer.Tick, AddressOf OnTextChangedTimerTick
End If
textChangedTimer?.Stop()
textChangedTimer?.Start()
End Sub
Public Sub Tabulation(ByVal sRichTextBox As RichTextBox)
If sRichTextBox Is Nothing Then Return ' Verifica nullità dell'oggetto
' Inserisci un carattere di tabulazione (3 spazi)
Dim tabString As String = " "
' Gestisci il punto di inserimento del cursore
Dim caretPosition As TextPointer = sRichTextBox.CaretPosition
If caretPosition IsNot Nothing Then
caretPosition.InsertTextInRun(tabString)
' Aggiorna la posizione del cursore dopo il testo inserito
sRichTextBox.CaretPosition = caretPosition.GetPositionAtOffset(tabString.Length, LogicalDirection.Forward)
End If
End Sub
#End Region ' Methods
#Region "EVENTS"
Private Sub OnTextChangedTimerTick(sender As Object, e As EventArgs)
textChangedTimer.Stop()
ProcessTextChanges()
End Sub
#End Region ' Events
#Region "COMMANDS"
#Region "ConfermCmd"
Public ReadOnly Property ConfermaCmd As ICommand
Get
If m_ConfermaCmd Is Nothing Then
m_ConfermaCmd = New Command(AddressOf Conferma)
End If
Return m_ConfermaCmd
End Get
End Property
Public Sub Conferma()
' Genera il percorso del file script
Dim scriptFilePath As String = IO.Path.Combine(Map.refMainWindowVM.MainWindowM.sTempDir, $"{m_sNameFile}.lua")
' Recupera il contenuto del file script
Dim sFileScript As String = RichTextBox(scriptFilePath)
' Salva il file script
SaveScript(scriptFilePath, sFileScript)
' Esegue il file script
EgtLuaExecFile(scriptFilePath)
' Imposta lo stato della gestione mouse diretto della scena a "nessuno"
Map.refSceneHostVM.MainScene.SetStatusNull()
End Sub
#End Region ' ConfermaCmd
#Region "SaveAsCommand"
Public ReadOnly Property SalvaCmd As ICommand
Get
If m_cmdSaveAs Is Nothing Then
m_cmdSaveAs = New Command(AddressOf SaveAs)
End If
Return m_cmdSaveAs
End Get
End Property
Public Sub SaveAs()
SaveProject()
End Sub
#End Region ' SaveAsCommand
#Region "AnnullaCmd"
Public ReadOnly Property AnnullaCmd As ICommand
Get
If m_cmdAnnulla Is Nothing Then
m_cmdAnnulla = New Command(AddressOf Annulla)
End If
Return m_cmdAnnulla
End Get
End Property
Public Sub Annulla()
Map.refScriptWindowV.Close()
End Sub
#End Region ' AnnullaCmd
#Region "TextColorCmd"
Public ReadOnly Property TextColorCmd As ICommand
Get
If m_cmdTextColor Is Nothing Then
m_cmdTextColor = New Command(AddressOf TextColor)
End If
Return m_cmdTextColor
End Get
End Property
Public Sub TextColor()
' Recupero colori custom
Dim defaultColor As New Color3d(10, 122, 150)
Dim sCustomColors As String = String.Empty
GetMainPrivateProfileString(S_COLORS, K_CUSTOMCOLORS, "", sCustomColors)
' Parsing dei colori custom in una lista di interi
Dim nCustomColors = sCustomColors.Split(","c).
Select(Function(color)
Dim nColor As Integer
Return If(Integer.TryParse(color, nColor), nColor, Nothing)
End Function).
Where(Function(nColor) nColor > 0).Cast(Of Integer)().ToList()
' Configurazione dialogo colori
Dim colorDialog As New EgtColorPickerV(Application.Current.MainWindow, New EgtColorPickerVM()) With {
.CustomColors = nCustomColors.ToArray(),
.Color = defaultColor.ToColor()
}
' Visualizzo il dialogo e gestisco l'output
If colorDialog.ShowDialog() <> Windows.Forms.DialogResult.OK Then Return
' Conversione colore selezionato
Dim selectedColor As System.Windows.Media.Color = System.Windows.Media.Color.FromArgb(
CByte(colorDialog.Color.A),
CByte(colorDialog.Color.R),
CByte(colorDialog.Color.G),
CByte(colorDialog.Color.B)
)
Dim selColorBrush As New SolidColorBrush(selectedColor)
' Applicazione del colore al testo selezionato
Dim textRange As New TextRange(Map.refScriptWindowV.sNameFile_RichTxBx.Selection.Start, Map.refScriptWindowV.sNameFile_RichTxBx.Selection.End)
textRange.ApplyPropertyValue(TextElement.ForegroundProperty, selColorBrush)
End Sub
#End Region ' TextColorCmd
#End Region ' Commands
End Class