//---------------------------------------------------------------------------- // EgalTech 2014-2014 //---------------------------------------------------------------------------- // File : LUA_General.cpp Data : 27.09.14 Versione : 1.5i5 // Contenuto : Funzioni generali per LUA. // // // // Modifiche : 27.09.14 DS Creazione modulo. // // //---------------------------------------------------------------------------- //--------------------------- Include ---------------------------------------- #include "stdafx.h" #include "DllMain.h" #include "EXE.h" #include "LUA.h" #include "GenTools.h" #include "resource.h" #include "AuxDialogBox.h" #include "/EgtDev/Include/ExeExecutor.h" #include "/EgtDev/Include/EGkLuaAux.h" #include "/EgtDev/Include/EGkStringUtils3d.h" #include "/EgtDev/Include/EGnStringUtils.h" #include "/EgtDev/Include/EGnFileUtils.h" #include "/EgtDev/Include/EGnFileCompare.h" #include "/EgtDev/Include/EGnStringKeyVal.h" #include "/EgtDev/Include/EGnEgtUUID.h" #include "/EgtDev/Include/EgtPerfCounter.h" #include "/EgtDev/Include/EgtIniFile.h" #include "/EgtDev/Include/EgtNumUtils.h" #include "/EgtDev/Include/EgtStringConverter.h" #include #include #include using namespace std ; //---------------------------------------------------------------------------- static PerformanceCounter s_Counter ; //------------------------------------------------------------------------------- static int MyPrint( lua_State* L) { string sOut ; int n = lua_gettop( L) ; /* number of arguments */ lua_getglobal( L, "tostring") ; for ( int i = 1 ; i <= n ; ++ i) { const char* s ; lua_pushvalue( L, -1) ; /* function to be called */ lua_pushvalue( L, i) ; /* value to print */ lua_call( L, 1, 1) ; s = lua_tostring( L, -1) ; /* get result */ if ( s == nullptr) return luaL_error( L, "'tostring' must return a string to 'print'") ; if ( i > 1) sOut += "\t" ; sOut += s ; lua_pop( L, 1) ; /* pop result */ } if ( ! sOut.empty()) LOG_INFO( GetLogger(), sOut.c_str()) return 0 ; } //------------------------------------------------------------------------------- static int LuaEvalNumExpr( lua_State* L) { // un solo parametro stringa : sExpr string sExpr ; LuaCheckParam( L, 1, sExpr) LuaClearStack( L) ; // valuto l'espressione double dVal ; bool bOk = ExeLuaEvalNumExpr( sExpr, &dVal) ; // restituisco il risultato if ( bOk) LuaSetParam( L, dVal) ; else LuaSetParam( L) ; return 1 ; } //------------------------------------------------------------------------------- static int LuaPause( lua_State* L) { // 1 o 2 parametri : numero di millisecondi [, bForced] int nTime ; LuaCheckParam( L, 1, nTime) bool bForced = false ; LuaGetParam( L, 2, bForced) ; LuaClearStack( L) ; // se forzata o abilitata UI, controllo la durata della pausa e la eseguo if ( bForced || ExeGetEnableUI()) { const int MIN_TIME = 0 ; const int MAX_TIME = 10000 ; if ( nTime < MIN_TIME) nTime = MIN_TIME ; else if ( nTime > MAX_TIME) nTime = MAX_TIME ; Sleep( nTime) ; } // restituisco il risultato LuaSetParam( L, true) ; return 1 ; } //------------------------------------------------------------------------------- static int LuaGetKeyPressed( lua_State* L) { // 1 parametro : nKeyCode int nKeyCode ; LuaCheckParam( L, 1, nKeyCode) LuaClearStack( L) ; // se abilitata UI, controllo se il tasto indicato è premuto bool bPressed = false ; if ( ExeGetEnableUI()) { bPressed = (( GetAsyncKeyState( nKeyCode) & 0x8000) != 0) ; } // restituisco il risultato LuaSetParam( L, bPressed) ; return 1 ; } //------------------------------------------------------------------------------- static int LuaStartCounter( lua_State* L) { // nessun parametro LuaClearStack( L) ; // avvio il contatore s_Counter.Start() ; return 0 ; } //------------------------------------------------------------------------------- static int LuaStopCounter( lua_State* L) { // nessun parametro LuaClearStack( L) ; // fermo il contatore double dTime = s_Counter.Stop() ; // restituisco il risultato LuaSetParam( L, dTime) ; return 1 ; } //------------------------------------------------------------------------------- static int LuaNumToString( lua_State* L) { // 1 o 2 parametri : dVal [, nDec] double dVal ; LuaCheckParam( L, 1, dVal) int nDec = 3 ; LuaGetParam( L, 2, nDec) ; LuaClearStack( L) ; // costruisco la stringa string sVal = ToString( dVal, nDec) ; // ritorno il risultato LuaSetParam( L, sVal) ; return 1 ; } //------------------------------------------------------------------------------- static int LuaSplitString( lua_State* L) { // 1 o 2 parametri : sVal [, sSep] string sVal ; string sSep = "," ; bool bFound = LuaGetParam( L, 1, sVal) ; LuaGetParam( L, 2, sSep) ; LuaClearStack( L) ; // se ricevuta stringa, la divido in parti separate da sSep if ( bFound) { // eseguo separazione (se tra i separatori c'è spazio ora tokenize collassa eventuali spazi consecutivi in uno solo) STRVECTOR vsVal ; Tokenize( sVal, sSep, vsVal) ; // ritorno il risultato LuaSetParam( L, vsVal) ; } // altrimenti restituisco nil else LuaSetParam( L) ; return 1 ; } //------------------------------------------------------------------------------- static int LuaSplitStringPlus( lua_State* L) { // 2 parametri : sVal, sHea string sVal ; string sHea ; bool bOk = LuaGetParam( L, 1, sVal) && LuaGetParam( L, 2, sHea) ; LuaClearStack( L) ; // se ricevute stringhe, divido la prima in parti con intestazioni della seconda (che conservo) if ( bOk) { STRVECTOR vsVal ; TokenizePlus( sVal, sHea, vsVal) ; // ritorno il risultato LuaSetParam( L, vsVal) ; } // altrimenti restituisco nil else LuaSetParam( L) ; return 1 ; } //------------------------------------------------------------------------------- static int LuaReplaceString( lua_State* L) { // 3 parametri : sVal, sOld, sNew string sVal ; LuaCheckParam( L, 1, sVal) string sOld ; LuaCheckParam( L, 2, sOld) string sNew ; LuaCheckParam( L, 3, sNew) LuaClearStack( L) ; // eseguo sostituzione nella stringa della sequenza indicata dal secondo parametro con quella del terzo int nRes = ReplaceString( sVal, sOld, sNew) ; // restituisco il risultato LuaSetParam( L, sVal) ; LuaSetParam( L, nRes) ; return 2 ; } //------------------------------------------------------------------------------- static int LuaSetVal( lua_State* L) { // 2 parametri : Key, bVal|nVal|dVal|sVal|vtVal|ptVal|b3Val|frVal string sKey ; LuaCheckParam( L, 1, sKey) bool bOk = false ; string sNotes = "" ; switch ( lua_type( L, 2)) { case LUA_TBOOLEAN : { bool bVal ; LuaGetParam( L, 2, bVal) ; LuaClearStack( L) ; bOk = SetVal( sKey, bVal, sNotes) ; } break ; case LUA_TNUMBER : { double dVal ; LuaGetParam( L, 2, dVal) ; LuaClearStack( L) ; bOk = SetVal( sKey, dVal, sNotes) ; } break ; case LUA_TSTRING : { string sVal ; LuaGetParam( L, 2, sVal) ; LuaClearStack( L) ; bOk = SetVal( sKey, (const string&) sVal, sNotes) ; } break ; case LUA_TTABLE : { Frame3d frVal ; BBox3d b3Val ; Vector3d vtVal ; // va bene anche per Point3d INTVECTOR vnVal ; DBLVECTOR vdVal ; STRVECTOR vsVal ; if ( LuaGetParam( L, 2, frVal)) { LuaClearStack( L) ; bOk = SetVal( sKey, frVal, sNotes) ; } else if ( LuaGetParam( L, 2, b3Val)) { LuaClearStack( L) ; bOk = SetVal( sKey, b3Val, sNotes) ; } else if ( LuaGetParam( L, 2, vtVal)) { LuaClearStack( L) ; bOk = SetVal( sKey, vtVal, sNotes) ; } else if ( LuaGetParam( L, 2, vnVal)) { LuaClearStack( L) ; bOk = SetVal( sKey, vnVal, sNotes) ; } else if ( LuaGetParam( L, 2, vdVal)) { LuaClearStack( L) ; bOk = SetVal( sKey, vdVal, sNotes) ; } else if ( LuaGetParam( L, 2, vsVal)) { LuaClearStack( L) ; bOk = SetVal( sKey, vsVal, sNotes) ; } } break ; } // restituisco il risultato if ( bOk) LuaSetParam( L, sNotes) ; else LuaSetParam(L, "") ; return 1 ; } //------------------------------------------------------------------------------- static int LuaGetVal( lua_State* L) { // 2 o 3 parametri : String, Key, sType string sVal ; LuaCheckParam( L, 1, sVal) string sKey ; LuaCheckParam( L, 2, sKey) string sType = "s" ; LuaGetParam( L, 3, sType) ; LuaClearStack( L) ; // recupero l'info if ( sType == "b" || sType == "B") { bool bVal ; if ( GetVal( sVal, sKey, bVal)) LuaSetParam( L, bVal) ; else LuaSetParam( L) ; } else if ( sType == "i" || sType == "I") { int nVal ; if ( GetVal( sVal, sKey, nVal)) LuaSetParam( L, nVal) ; else LuaSetParam( L) ; } else if ( sType == "d" || sType == "D") { double dVal ; if ( GetVal( sVal, sKey, dVal)) LuaSetParam( L, dVal) ; else LuaSetParam( L) ; } else if ( sType == "v" || sType == "V") { Vector3d vtVal ; if ( GetVal( sVal, sKey, vtVal)) LuaSetParam( L, vtVal) ; else LuaSetParam( L) ; } else if ( sType == "p" || sType == "P") { Point3d ptVal ; if ( GetVal( sVal, sKey, ptVal)) LuaSetParam( L, ptVal) ; else LuaSetParam( L) ; } else if ( sType == "x" || sType == "X") { BBox3d b3Val ; if ( GetVal( sVal, sKey, b3Val)) LuaSetParam( L, b3Val) ; else LuaSetParam( L) ; } else if ( sType == "f" || sType == "F") { Frame3d frVal ; if ( GetVal( sVal, sKey, frVal)) LuaSetParam( L, frVal) ; else LuaSetParam( L) ; } else if ( sType == "vi" || sType == "vI") { INTVECTOR vnVal ; if ( GetVal( sVal, sKey, vnVal)) LuaSetParam( L, vnVal) ; else LuaSetParam( L) ; } else if ( sType == "vd" || sType == "vD") { DBLVECTOR vdVal ; if ( GetVal( sVal, sKey, vdVal)) LuaSetParam( L, vdVal) ; else LuaSetParam( L) ; } else if ( sType == "vs" || sType == "vS") { STRVECTOR vsVal ; if ( GetVal( sVal, sKey, vsVal)) LuaSetParam( L, vsVal) ; else LuaSetParam( L) ; } else { // "s" "S" string sInfo ; if ( GetVal( sVal, sKey, sInfo)) LuaSetParam( L, sInfo) ; else LuaSetParam( L) ; } return 1 ; } //------------------------------------------------------------------------------- static int LuaGetUUID( lua_State* L) { // nessun parametro LuaClearStack( L) ; // recupero UUID e lo trasformo in stringa EgtUUID uuId ; bool bOk = CreateEgtUUID( uuId) ; // restituisco il risultato if ( bOk) LuaSetParam( L, ToString( uuId)) ; else LuaSetParam( L) ; return 1 ; } //------------------------------------------------------------------------------- static int LuaExecTsc( lua_State* L) { // 1 parametro : file string sFile ; LuaCheckParam( L, 1, sFile) LuaClearStack( L) ; // eseguo lo script TSC bool bOk = ExeTscExecFile( sFile) ; // restituisco il risultato LuaSetParam( L, bOk) ; return 1 ; } //------------------------------------------------------------------------------- static int LuaExecTscLine( lua_State* L) { // 1 parametro : linea string sLine ; LuaCheckParam( L, 1, sLine) LuaClearStack( L) ; // eseguo la linea TSC bool bOk = ExeTscExecLine( sLine) ; // restituisco il risultato LuaSetParam( L, bOk) ; return 1 ; } //------------------------------------------------------------------------------- static int LuaSetTscVar( lua_State* L) { // 2 parametri : nome, valore string sName ; LuaCheckParam( L, 1, sName) int nVal ; LuaCheckParam( L, 2, nVal) LuaClearStack( L) ; // assegno il valore alla variabile Tsc bool bOk = ExeTscSetVariable( sName, nVal) ; // restituisco il risultato LuaSetParam( L, bOk) ; return 1 ; } //------------------------------------------------------------------------------- static int LuaGetTscVar( lua_State* L) { // 1 parametro : nome string sName ; LuaCheckParam( L, 1, sName) LuaClearStack( L) ; // recupero il valore della variabile Tsc int nVal ; bool bOk = ExeTscGetVariable( sName, nVal) ; // restituisco il risultato if ( bOk) LuaSetParam( L, nVal) ; else LuaSetParam( L) ; return 1 ; } //------------------------------------------------------------------------------- static int LuaGetDebugLevel( lua_State* L) { // nessun parametro LuaClearStack( L) ; // restituisco il livello di debug int nDebugLev = ExeGetDebugLevel() ; LuaSetParam( L, nDebugLev) ; return 1 ; } //------------------------------------------------------------------------------- static int LuaGetUserLevel( lua_State* L) { // nessun parametro LuaClearStack( L) ; // restituisco il livello utente int nUserLev = ExeGetUserLevel() ; LuaSetParam( L, nUserLev) ; return 1 ; } //------------------------------------------------------------------------------- static int LuaOutLog( lua_State* L) { // 1 o 2 parametri : stringa da emettere [, DebugLevel = 0] string sOut ; LuaCheckParam( L, 1, sOut) int nDbgLev = 0 ; LuaGetParam( L, 2, nDbgLev) ; LuaClearStack( L) ; // accodo il messaggio nel file di log ExeOutLog( sOut, nDbgLev) ; // non c'è risultato return 0 ; } //------------------------------------------------------------------------------- static int LuaGetEnableUI( lua_State* L) { // nessun parametro LuaClearStack( L) ; // accodo il messaggio nel file di log bool bOk = ExeGetEnableUI() ; // restituisco lo stato di abilitazione dell'interfaccia utente LuaSetParam( L, bOk) ; return 1 ; } //------------------------------------------------------------------------------- static int LuaOutBox( lua_State* L) { // 2, 3 o 4 parametri : sOut, sTitle [, sIcon] [, sButtons] string sOut ; LuaCheckParam( L, 1, sOut) string sTitle ; LuaCheckParam( L, 2, sTitle) string sIcon ; LuaGetParam( L, 3, sIcon) ; int nIcon = 0 ; ToUpper( sIcon) ; if ( sIcon == "ERROR") nIcon = MB_ICONERROR ; else if ( sIcon == "WARNING") nIcon = MB_ICONWARNING ; else if ( sIcon == "INFO") nIcon = MB_ICONINFORMATION ; else if ( sIcon == "QUESTION") nIcon = MB_ICONQUESTION ; string sButtons ; LuaGetParam( L, 4, sButtons) ; int nButtons = MB_OKCANCEL ; ToUpper( sButtons) ; if ( sButtons == "OK") nButtons = MB_OK ; else if ( sButtons == "OKCANCEL") nButtons = MB_OKCANCEL ; else if ( sButtons == "ABORTRETRYIGNORE") nButtons = MB_ABORTRETRYIGNORE ; else if ( sButtons == "YESNOCANCEL") nButtons = MB_YESNOCANCEL ; else if ( sButtons == "YESNO") nButtons = MB_YESNO ; else if ( sButtons == "RETRYCANCEL") nButtons = MB_RETRYCANCEL ; else if ( sButtons == "CANCELTRYCONTINUE") nButtons = MB_CANCELTRYCONTINUE ; LuaClearStack( L) ; // emetto finestra di dialogo (solo se ablitata UI) int nRes = ExeMessageBox( sOut, sTitle, nButtons | nIcon) ; // risultato if ( nRes == IDOK || nRes == IDRETRY || nRes == IDYES || nRes == IDTRYAGAIN) LuaSetParam( L, true) ; else if ( nRes == IDNO || nRes == IDCONTINUE || nRes == IDIGNORE) LuaSetParam( L, false) ; else LuaSetParam( L) ; return 1 ; } //------------------------------------------------------------------------------- static int LuaProcessEvents( lua_State* L) { // 2 parametri : nProg, nPause int nProg ; LuaCheckParam( L, 1, nProg) int nPause ; LuaCheckParam( L, 2, nPause) LuaClearStack( L) ; // lancio aggiornamento interfaccia (viene fatto solo se abilitata UI) int nRes = ExeProcessEvents( nProg, nPause) ; // restituisco il risultato LuaSetParam( L, nRes) ; return 1 ; } //------------------------------------------------------------------------------- static int LuaOutText( lua_State* L) { // 1 parametro : sText string sText ; LuaCheckParam( L, 1, sText) LuaClearStack( L) ; // lancio emissione testo (viene fatto solo se abilitata UI) bool bOk = ExeOutText( sText) ; // restituisco il risultato LuaSetParam( L, bOk) ; return 1 ; } //------------------------------------------------------------------------------- static int LuaFileDialog( lua_State* L) { // 3 parametri : bOpenVsSave, sFile, sFilter bool bOpenVsSave ; LuaCheckParam( L, 1, bOpenVsSave) string sFile ; LuaCheckParam( L, 2, sFile) string sFilter ; LuaCheckParam( L, 3, sFilter) LuaClearStack( L) ; // se abilitata UI, emetto la finestra di dialogo if ( ExeGetEnableUI()) { // Converto i parametri nel formato wide AtoWEX wsFileName( sFile.c_str()) ; AtoW wsFilter( sFilter.c_str()) ; // Converto L'/' in L'\\' nel nome file proposto for ( wchar_t* pC = wsFileName.m_psz ; *pC != L'\0' ; ++ pC) { if ( *pC == L'/') *pC = L'\\' ; } // Cambio L'|' in L'\0' nel filtro for ( wchar_t* pC = wsFilter.m_psz ; *pC != L'\0' ; ++ pC) { if ( *pC == L'|') *pC = L'\0' ; } // Riempio la struttura dati per il dialogo OPENFILENAME ofn ; ZeroMemory( &ofn, sizeof( ofn)) ; ofn.lStructSize = sizeof( ofn) ; ofn.hwndOwner = ExeGetMainWindowHandle() ; ofn.lpstrFilter = LPWSTR( wsFilter) ; ofn.lpstrFile = LPWSTR( wsFileName) ; ofn.nMaxFile = MAX_PATH ; ofn.Flags = OFN_DONTADDTORECENT | OFN_PATHMUSTEXIST ; // Visualizzo il dialogo if ( bOpenVsSave) { ofn.Flags |= OFN_FILEMUSTEXIST | OFN_HIDEREADONLY ; if ( GetOpenFileName( &ofn) != FALSE) LuaSetParam( L, wstrztoA( wsFileName)) ; else LuaSetParam( L) ; } else { ofn.Flags |= OFN_OVERWRITEPROMPT ; if ( GetSaveFileName( &ofn) != FALSE) LuaSetParam( L, wstrztoA( wsFileName)) ; else LuaSetParam( L) ; } } else LuaSetParam( L) ; return 1 ; } //------------------------------------------------------------------------------- static int LuaExistsFile( lua_State* L) { // 1 parametro : sFile string sFile ; LuaCheckParam( L, 1, sFile) LuaClearStack( L) ; // verifico esistenza file bool bOk = ExistsFile( sFile) ; // restituisco il risultato LuaSetParam( L, bOk) ; return 1 ; } //------------------------------------------------------------------------------- static int LuaCopyFile( lua_State* L) { // 2 parametri : sFile, sNewFile string sFile ; LuaCheckParam( L, 1, sFile) string sNewFile ; LuaCheckParam( L, 2, sNewFile) LuaClearStack( L) ; // copio il file bool bOk = CopyFileEgt( sFile, sNewFile) ; // restituisco il risultato LuaSetParam( L, bOk) ; return 1 ; } //------------------------------------------------------------------------------- static int LuaRenameFile( lua_State* L) { // 2 parametri : sFile, sNewFile string sFile ; LuaCheckParam( L, 1, sFile) string sNewFile ; LuaCheckParam( L, 2, sNewFile) LuaClearStack( L) ; // rinomino il file bool bOk = RenameFile( sFile, sNewFile) ; // restituisco il risultato LuaSetParam( L, bOk) ; return 1 ; } //------------------------------------------------------------------------------- static int LuaEraseFile( lua_State* L) { // 1 parametro : file string sFile ; LuaCheckParam( L, 1, sFile) LuaClearStack( L) ; // cancello il file bool bOk = EraseFile( sFile) ; // restituisco il risultato LuaSetParam( L, bOk) ; return 1 ; } //------------------------------------------------------------------------------- static int LuaFindAllFiles( lua_State* L) { // 1 parametro : specifiche del file string sFileSpec ; LuaCheckParam( L, 1, sFileSpec) LuaClearStack( L) ; // recupero tutti i file che rispondono alle specifiche STRVECTOR vsFiles ; bool bOk = FindAllFiles( sFileSpec, vsFiles) ; // restituisco il risultato if ( bOk) LuaSetParam( L, vsFiles) ; else LuaSetParam( L) ; return 1 ; } //------------------------------------------------------------------------------- static int LuaCompareFilesLastWriteTime( lua_State* L) { // 2 parametri : file1, file2 string sFile1 ; LuaCheckParam( L, 1, sFile1) string sFile2 ; LuaCheckParam( L, 2, sFile2) LuaClearStack( L) ; // confronto la data di ultima scrittura dei due file int nRes ; bool bOk = CompareFilesLastWriteTime( sFile1, sFile2, nRes) ; // restituisco il risultato if ( bOk) LuaSetParam( L, nRes) ; else LuaSetParam( L) ; return 1 ; } //------------------------------------------------------------------------------- int CALLBACK DirectoryBoxProc( HWND hwndDlg, UINT uMsg, LPARAM lParam, LPARAM lpData) { if ( uMsg == BFFM_INITIALIZED) SendMessage( hwndDlg, BFFM_SETSELECTION, TRUE, lpData) ; return 0 ; } //------------------------------------------------------------------------------- static int LuaDirectoryDialog( lua_State* L) { // 2 parametri : sText, sDir string sText ; LuaCheckParam( L, 1, sText) string sDir ; LuaCheckParam( L, 2, sDir) LuaClearStack( L) ; // se abilitata UI, emetto la finestra di dialogo if ( ExeGetEnableUI()) { // Converto i parametri nel formato wide AtoWEX wsText( sText.c_str()) ; AtoWEX wsDirName( sDir.c_str()) ; // Converto L'/' in L'\\' nel nome directory proposto for ( wchar_t* pC = wsDirName.m_psz ; *pC != L'\0' ; ++ pC) { if ( *pC == L'/') *pC = L'\\' ; } // Riempio la struttura dati per il dialogo BROWSEINFO bi = { 0} ; bi.hwndOwner = ExeGetMainWindowHandle() ; bi.lpszTitle = LPWSTR( wsText) ; bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_USENEWUI ; bi.lpfn = DirectoryBoxProc ; bi.lParam = (LPARAM) LPWSTR( wsDirName) ; // Visualizzo il dialogo LPITEMIDLIST pIdl = SHBrowseForFolder( &bi) ; if ( pIdl != NULL) { // recupero la path della directory WCHAR wPath[MAX_PATH] ; if ( SHGetPathFromIDList( pIdl, wPath) != FALSE) LuaSetParam( L, wstrztoA( wPath)) ; else LuaSetParam( L) ; // free memory used IMalloc* pImalloc = NULL ; if ( SUCCEEDED( SHGetMalloc( &pImalloc))) { pImalloc->Free( pIdl) ; pImalloc->Release() ; } } else LuaSetParam( L) ; } else LuaSetParam( L) ; return 1 ; } //------------------------------------------------------------------------------- static int LuaExistsDirectory( lua_State* L) { // 1 parametro : sDir string sDir ; LuaCheckParam( L, 1, sDir) LuaClearStack( L) ; // verifico esistenza direttorio bool bOk = ExistsDirectory( sDir) ; // restituisco il risultato LuaSetParam( L, bOk) ; return 1 ; } //------------------------------------------------------------------------------- static int LuaCreateDirectory( lua_State* L) { // 1 parametro : sDir string sDir ; LuaCheckParam( L, 1, sDir) LuaClearStack( L) ; // creo direttorio bool bOk = CreateDirectoryEgt( sDir) ; // restituisco il risultato LuaSetParam( L, bOk) ; return 1 ; } //------------------------------------------------------------------------------- static int LuaEmptyDirectory( lua_State* L) { // 1 parametro : sDir string sDir ; LuaCheckParam( L, 1, sDir) LuaClearStack( L) ; // svuoto il direttorio bool bOk = EmptyDirectory( sDir) ; // restituisco il risultato LuaSetParam( L, bOk) ; return 1 ; } //------------------------------------------------------------------------------- static int LuaEraseDirectory( lua_State* L) { // 1 parametro : sDir string sDir ; LuaCheckParam( L, 1, sDir) LuaClearStack( L) ; // cancello direttorio (deve essere vuoto) bool bOk = EraseDirectory( sDir) ; // restituisco il risultato LuaSetParam( L, bOk) ; return 1 ; } //------------------------------------------------------------------------------- static int LuaEraseNonEmptyDirectory( lua_State* L) { // 1 parametro : sDir string sDir ; LuaCheckParam( L, 1, sDir) LuaClearStack( L) ; // cancello direttorio (deve essere vuoto) bool bOk = EraseNonEmptyDirectory( sDir) ; // restituisco il risultato LuaSetParam( L, bOk) ; return 1 ; } //------------------------------------------------------------------------------- static int LuaTextFileCompare( lua_State* L) { // 4 parametri : file1, file2, inizio commento, file diff string sFile1 ; LuaCheckParam( L, 1, sFile1) string sFile2 ; LuaCheckParam( L, 2, sFile2) string sRemStart ; LuaCheckParam( L, 3, sRemStart) string sFileDiff ; LuaCheckParam( L, 4, sFileDiff) LuaClearStack( L) ; // eseguo il confronto int nDiff ; bool bOk = TextFileCompare( sFile1, sFile2, sRemStart, sFileDiff, nDiff) ; LuaSetParam( L, bOk) ; LuaSetParam( L, nDiff) ; return 2 ; } //------------------------------------------------------------------------------- static int LuaBinaryFileCompare( lua_State* L) { // 3 parametri : file1, file2, file diff string sFile1 ; LuaCheckParam( L, 1, sFile1) string sFile2 ; LuaCheckParam( L, 2, sFile2) string sFileDiff ; LuaCheckParam( L, 3, sFileDiff) LuaClearStack( L) ; // eseguo il confronto int nDiff ; bool bOk = BinaryFileCompare( sFile1, sFile2, sFileDiff, nDiff) ; LuaSetParam( L, bOk) ; LuaSetParam( L, nDiff) ; return 2 ; } //------------------------------------------------------------------------------- static int LuaGetStringFromIni( lua_State* L) { // 4 parametri : sSec, sKey, sDef, sIniFile string sSec ; LuaCheckParam( L, 1, sSec) string sKey ; LuaCheckParam( L, 2, sKey) string sDef ; LuaCheckParam( L, 3, sDef) string sIniFile ; LuaCheckParam( L, 4, sIniFile) LuaClearStack( L) ; // leggo da file INI string sVal = GetPrivateProfileStringUtf8( sSec.c_str(), sKey.c_str(), sDef.c_str(), sIniFile.c_str()) ; LuaSetParam( L, sVal) ; return 1 ; } //------------------------------------------------------------------------------- static int LuaWriteStringToIni( lua_State* L) { // 4 parametri : sSec, sKey, sVal, sIniFile string sSec ; LuaCheckParam( L, 1, sSec) string sKey ; LuaCheckParam( L, 2, sKey) string sVal ; LuaCheckParam( L, 3, sVal) string sIniFile ; LuaCheckParam( L, 4, sIniFile) LuaClearStack( L) ; // scrivo su file INI bool bOk = WritePrivateProfileStringUtf8( sSec.c_str(), sKey.c_str(), sVal.c_str(), sIniFile.c_str()) ; LuaSetParam( L, bOk) ; return 1 ; } //------------------------------------------------------------------------------- static int LuaGetIniFile( lua_State* L) { // nessun parametro LuaClearStack( L) ; // recupero la path del file Ini dell'eseguibile string sIniFile = ExeGetIniFile() ; // restituisco il risultato if ( ! sIniFile.empty()) LuaSetParam( L, sIniFile) ; else LuaSetParam( L) ; return 1 ; } //------------------------------------------------------------------------------- static int LuaGetTempDir( lua_State* L) { // nessun parametro LuaClearStack( L) ; // recupero la path del direttorio temporaneo dell'eseguibile string sTempDir ; ExeGetTempDir( sTempDir) ; // restituisco il risultato if ( ! sTempDir.empty()) LuaSetParam( L, sTempDir) ; else LuaSetParam( L) ; return 1 ; } //------------------------------------------------------------------------------- static int LuaGetExeVersion( lua_State* L) { // nessun parametro LuaClearStack( L) ; // costruisco la stringa con le versioni string sVer ; if ( ! ExeGetExecutableVersion( sVer)) sVer = "ExeVersion error" ; // restituisco il risultato LuaSetParam( L, sVer) ; return 1 ; } //------------------------------------------------------------------------------- static int LuaGetVersion( lua_State* L) { // nessun parametro LuaClearStack( L) ; // costruisco la stringa con le versioni string sVer ; if ( ! ExeGetVersionInfo( sVer, "\n")) sVer = "VersionInfo error" ; // restituisco il risultato LuaSetParam( L, sVer) ; return 1 ; } //------------------------------------------------------------------------------- static int LuaIs64bit( lua_State* L) { // nessun parametro LuaClearStack( L) ; // restituisco il risultato #if defined( _WIN64) bool bRes = true ; #elif defined( _WIN32) bool bRes = false ; #endif LuaSetParam( L, bRes) ; return 1 ; } //------------------------------------------------------------------------------- static int LuaGetLanguage( lua_State* L) { // nessun parametro LuaClearStack( L) ; // recupero il nome della lingua corrente string sLang = ExeGetLanguage() ; LuaSetParam( L, sLang) ; return 1 ; } //------------------------------------------------------------------------------- static int LuaGetMsg( lua_State* L) { // 1 parametro : nMsg int nMsg ; LuaCheckParam( L, 1, nMsg) LuaClearStack( L) ; // recupero il nome della lingua corrente string sMsg = ExeGetMsg( nMsg) ; LuaSetParam( L, sMsg) ; return 1 ; } //------------------------------------------------------------------------------- static int LuaVerifyKeyOption( lua_State* L) { // 1 parametro : nOptInd int nOptInd ; LuaCheckParam( L, 1, nOptInd) LuaClearStack( L) ; // verifico l'abilitazione dell'opzione (da chiave + licenza) bool bOk = ExeVerifyKeyOption( nOptInd) ; LuaSetParam( L, bOk) ; return 1 ; } //------------------------------------------------------------------------------- static int LuaSetDefaultFont( lua_State* L) { // 1 parametro : sDefaultFont string sDefaultFont ; LuaCheckParam( L, 1, sDefaultFont) LuaClearStack( L) ; // imposta il font di default bool bOk = ExeSetFont( "", sDefaultFont) ; LuaSetParam( L, bOk) ; return 1 ; } //------------------------------------------------------------------------------- static int LuaGetDefaultFont( lua_State* L) { // nessun parametro LuaClearStack( L) ; // recupera il font di cefault string sDefaultFont ; bool bOk = ExeGetDefaultFont( sDefaultFont) ; if ( bOk) LuaSetParam( L, sDefaultFont) ; else LuaSetParam( L) ; return 1 ; } //------------------------------------------------------------------------------- static int LuaWinExec( lua_State* L) { // un solo parametro : CmdLine string sCmdLine ; LuaCheckParam( L, 1, sCmdLine) LuaClearStack( L) ; // mando in esecuzione la linea di comando STARTUPINFO si ; PROCESS_INFORMATION pi ; ZeroMemory( &si, sizeof( si)) ; si.cb = sizeof( si) ; ZeroMemory( &pi, sizeof( pi)) ; bool bOk = ( CreateProcess( NULL, stringtoW( sCmdLine), NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi) != FALSE) ; CloseHandle( pi.hProcess) ; CloseHandle( pi.hThread) ; // restituisco il risultato LuaSetParam( L, bOk) ; return 1 ; } //------------------------------------------------------------------------------- static int LuaCloseExe( lua_State* L) { // 1 parametro opzionale : [nExitCode] int nExitCode = 0 ; LuaGetParam( L, 1, nExitCode) ; LuaClearStack( L) ; // eseguo chiusura forzata if ( ExeOnTerminateProcess( nExitCode)) TerminateProcess( GetCurrentProcess(), abs( nExitCode)) ; // restituisco il risultato (se arrivo qui vuol dire che non è consnetito terminare l'esecuzione) LuaSetParam( L, false) ; return 1 ; } //------------------------------------------------------------------------------- static int LuaCreateMutex( lua_State* L) { // un solo parametro : sMutexName string sMutexName ; LuaCheckParam( L, 1, sMutexName) LuaClearStack( L) ; // verifico esistenza Mutex con Nome (altrimenti lo creo per bloccare gli altri) bool bOk = ExeCreateMutex( sMutexName) ; // restituisco il risultato LuaSetParam( L, bOk) ; return 1 ; } //------------------------------------------------------------------------------- static int LuaReleaseMutex( lua_State* L) { // nessun parametro LuaClearStack( L) ; // rilascio l'eventuale Mutex con Nome attivo bool bOk = ExeReleaseMutex() ; // restituisco il risultato LuaSetParam( L, bOk) ; return 1 ; } //------------------------------------------------------------------------------- // =================================== DIALOG =================================== // Variabili Globali const int OFFS_CTRLS = 40 ; enum TYPE_CTRLS { CTRL_NONE = 0, CTRL_CHECK = 1, CTRL_COMBO = 2, CTRL_EDIT = 3, CTRL_COLOR = 4, CTRL_BUTTON = 5} ; static COLORREF s_CustomColors[16] = {12632256} ; // 16 colori GRAY static bool s_bCustomColorsInit = false ; // flag di inizializzazione colori const char* SEC_SCENE = "Scene" ; const char* KEY_CUSTOMCOLORS = "CustomColors" ; // Dialogo Modeless const int MAX_CTRLS = IDC_TEXT8 - IDC_TEXT1 + 1 ; static int s_nCtrls = 0 ; static string s_sCaption ; static string s_sText[MAX_CTRLS] ; static string s_sEdit[MAX_CTRLS] ; static int s_nType[MAX_CTRLS] ; struct DialogContext { bool bDone = false ; // flag per chiusura dialogo (X/Ok/Cancel) bool bCancelled = false ; // true se X/Cancel bool bSelecting = false ; // true quando un BS + in modalità selezione int nLastBS = -1 ; // indice dell'ultimo BS premuto STRVECTOR vsResult ; // valori finali da ritornare a Lua } ; static string s_sIdSel_ML ; static bool s_bSelectionMode = false ; // se true allora diventa dialogo "Modeless" static int s_nActiveRow = - 1 ; // indice della riga di "BS:" attiva //------------------------------------------------------------------------------- // OnClosingDialog // // Scopo: // Gestisce la chiusura del dialogo modeless in modo centralizzato e sicuro. // Questa funzione viene chiamata quando l’utente chiude il dialogo tramite: // - OK // - Cancel // - pulsante X // - WM_CLOSE // // Comportamento: // - Riabilita la finestra principale (Main Window), che era stata disabilitata durante il funzionamento // modale del dialogo. // // - Distrugge la finestra del dialogo. // // - Riporta il focus alla finestra principale, garantendo continuità nell’interazione dell’utente. // // - Deseleziona tutti gli oggetti nella scena e aggiorna la vista, in modo che nessuna selezione residua // rimanga attiva dopo la chiusura. //------------------------------------------------------------------------------- static void OnClosingDialog( HWND hwndDlg) { // reset stato globale s_bSelectionMode = false ; s_nActiveRow = -1 ; nDlgModelessItem = -1 ; // il controllo passa al Main HWND hMain = GetParent( hwndDlg) ; EnableWindow( hMain, TRUE) ; DestroyWindow( hwndDlg) ; phDlgModeless = nullptr ; SetFocus( hMain) ; // deseleziono tutto ExeDeselectAll() ; ExeDraw() ; } //------------------------------------------------------------------------------- // StartSelectionMode // // Scopo: // Attiva la modalità di selezione (modeless) del dialogo. Questa modalità permette all’utente di interagire // con la scena mentre il dialogo rimane aperto e attivo. // // Parametri: // hDlg → handle del dialogo // nEditId → ID dell’edit associato al pulsante BS premuto // nActiveRow → indice della riga BS attiva (0..MAX_CTRLS-1) //------------------------------------------------------------------------------- static void StartSelectionMode( HWND hDlg, int nEditId, int nActiveRow) { // il dialogo torna modeless rispetto alla scena HWND hMain = GetParent( hDlg) ; EnableWindow( hMain, TRUE) ; // resta comunque in primo piano SetWindowPos( hDlg, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE) ; // disabilito tutti gli edit associati ai BS tranne che quello attivo for ( int i = 0; i < s_nCtrls ; ++ i) { if (s_sEdit[i].find( "BS:") == 0) { int idEdit = IDC_EDIT1 + i ; EnableWindow( GetDlgItem( hDlg, idEdit), ( i == nActiveRow ? TRUE : FALSE)) ; } } // seleziono solo gli elementi presenti nell'edit corrispondente nDlgModelessItem = - 1 ; // !<-- Temporaneo [***] ExeDeselectAll() ; // !<-- NB. avendo messo nDlgModelessItem = -1 il testo non viene rimosso s_bSelectionMode = true ; s_nActiveRow = nActiveRow ; nDlgModelessItem = nEditId ; // !<-- Aggiorno [***] AtoWEX<128> wsEdit( "") ; GetDlgItemText( hDlg, nEditId, LPWSTR( wsEdit), 128) ; string sIds = wstrztoA( wsEdit) ; STRVECTOR vsIds ; Tokenize( sIds, ",", vsIds) ; for ( const string& sId : vsIds) { int nId = GDB_ID_NULL ; if ( FromString( sId, nId) && nId != GDB_ID_NULL) ExeSelectObj( nId) ; } ExeDraw() ; } //------------------------------------------------------------------------------- // EndSelectionMode // // Scopo: // Termina la modalità di selezione e riporta il dialogo in stato modale. //------------------------------------------------------------------------------- static void EndSelectionMode( HWND hDlg) { s_bSelectionMode = false ; s_nActiveRow = -1 ; nDlgModelessItem = -1 ; // disabilito tutti gli edit associati ai BS for ( int i = 0; i < s_nCtrls ; ++ i) { if ( s_sEdit[i].find( "BS:") == 0) { int idEdit = IDC_EDIT1 + i ; EnableWindow( GetDlgItem( hDlg, idEdit), FALSE) ; SetDlgItemText( hDlg, IDC_BUTTON_SEL1 + i, stringtoW( string{ "-"})) ; } } // il dialogo torna modale HWND hMain = GetParent( hDlg) ; EnableWindow( hMain, FALSE) ; SetFocus( hDlg) ; // deseleziono tutto ExeDeselectAll() ; //!<-- NB. avendo messo nDlgModelessItem = -1 il testo non viene rimosso ExeDraw() ; } //------------------------------------------------------------------------------- BOOL CALLBACK DialogBoxModelessProc( HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam) { // variabili static locali per mantenere lo stato tra chiamate per selezione colori static COLORREF selectedColor[MAX_CTRLS] = {0} ; // BLACK static HBRUSH hColorBrush[MAX_CTRLS] = {NULL} ; // non definito switch ( message) { case WM_INITDIALOG : { // imposto il dialogo come modale HWND hMain = GetParent( hwndDlg) ; EnableWindow( hMain, FALSE) ; SetFocus( hwndDlg) ; // imposto il contesto della funzione per recuperalo in futuro (per la funzione di CallBack Lua) SetWindowLongPtr( hwndDlg, GWLP_USERDATA, (LONG_PTR)lParam) ; // colore di default COLORREF defaultColor = RGB( 255, 0, 0) ; // inizializzazione colori e brush for ( int i = 0 ; i < MAX_CTRLS ; ++ i) { selectedColor[i] = defaultColor ; if ( hColorBrush[i] != NULL) DeleteObject( hColorBrush[i]) ; hColorBrush[i] = CreateSolidBrush( selectedColor[i]) ; } // dati del dialogo HWND hwndOwner = GetParent( hwndDlg) ; if ( hwndOwner == nullptr) hwndOwner = GetDesktopWindow() ; RECT rcOwner, rcDlg ; GetWindowRect( hwndOwner, &rcOwner) ; GetWindowRect( hwndDlg, &rcDlg) ; // determino la posizione dell'ultima riga di dati da visualizzare HWND hwndLR = GetDlgItem( hwndDlg, IDC_TEXT1 + Clamp( s_nCtrls, 1, MAX_CTRLS) - 1) ; RECT rcLR ; GetWindowRect( hwndLR, &rcLR) ; POINT ptLR{ rcLR.left, rcLR.top} ; ScreenToClient( hwndDlg, &ptLR) ; // centro e scalo il dialogo int nNewH = rcLR.top - rcOwner.top + 2 * OFFS_CTRLS ; // non chiaro perchè va sottratto rcOwner.top ma funziona sempre SetWindowPos( hwndDlg, HWND_TOP, ( rcOwner.left + rcOwner.right - ( rcDlg.right - rcDlg.left)) / 2, ( rcOwner.top + rcOwner.bottom - nNewH) / 2, ( rcDlg.right - rcDlg.left), nNewH, 0) ; // riposiziono il bottone Ok HWND hwndOk = GetDlgItem( hwndDlg, IDOK) ; RECT rcOk ; GetWindowRect( hwndOk, &rcOk) ; POINT ptOk{ rcOk.left, rcOk.top} ; ScreenToClient( hwndDlg, &ptOk) ; SetWindowPos( hwndOk, hwndDlg, ptOk.x, ptLR.y + OFFS_CTRLS, 0, 0, SWP_NOSIZE | SWP_NOZORDER) ; // riposiziono il bottone Cancel HWND hwndCl = GetDlgItem( hwndDlg, IDCANCEL) ; RECT rcCl ; GetWindowRect( hwndCl, &rcCl) ; POINT ptCl{ rcCl.left, rcCl.top} ; ScreenToClient( hwndDlg, &ptCl) ; SetWindowPos( hwndCl, hwndDlg, ptCl.x, ptLR.y + OFFS_CTRLS, 0, 0, SWP_NOSIZE | SWP_NOZORDER) ; // stile finestra LONG style = GetWindowLong( hwndDlg, GWL_STYLE) ; style |= WS_SYSMENU ; SetWindowLong( hwndDlg, GWL_STYLE, style) ; } // assegno titolo del dialogo SetWindowText( hwndDlg, stringtoW( s_sCaption)) ; // assegno testi e valori di default e nascondo linee dei controlli non usati for ( int i = 0 ; i < MAX_CTRLS ; ++ i) { if ( i < s_nCtrls) { // imposto il testo nella riga corrente SetDlgItemText( hwndDlg, IDC_TEXT1 + i, stringtoW( s_sText[i])) ; // --- se CheckBox if ( s_sEdit[i].find( "CK:") == 0) { bool bChecked = false ; FromString( s_sEdit[i].substr( 3), bChecked) ; CheckDlgButton( hwndDlg, IDC_CHECK1 + i, ( bChecked ? BST_CHECKED : BST_UNCHECKED)) ; ShowWindow( GetDlgItem( hwndDlg, IDC_EDIT1 + i), SW_HIDE) ; // nascondo Edit ShowWindow( GetDlgItem( hwndDlg, IDC_COMBO1 + i), SW_HIDE) ; // nascondo Combo ShowWindow( GetDlgItem( hwndDlg, IDC_BUTTON_SEL1 + i), SW_HIDE) ; // nascondo Button di selezione s_nType[i] = CTRL_CHECK ; } // --- se ComboBox else if ( s_sEdit[i].find( "CB:") == 0) { string sList = s_sEdit[i].substr( 3) ; STRVECTOR vsVal ; Tokenize( sList, ",", vsVal) ; int nSel = 0 ; HWND hwndCBox = GetDlgItem( hwndDlg, IDC_COMBO1 + i) ; for ( int j = 0 ; j < ssize( vsVal) ; ++ j) { string sItem ; if ( vsVal[j][0] == '*') { nSel = j ; sItem = vsVal[j].substr( 1) ; } else sItem = vsVal[j] ; ComboBox_AddString( hwndCBox, stringtoW( sItem)) ; } ComboBox_SetCurSel( hwndCBox, nSel) ; int nEditHeight = int( SendMessage( hwndCBox, CB_GETITEMHEIGHT, (WPARAM)-1, 0)) ; int nItemHeight = int( SendMessage( hwndCBox, CB_GETITEMHEIGHT, 0, 0)) ; int nTotalHeight = nEditHeight + nItemHeight * ( ssize( vsVal) + 1) ; RECT rc ; GetWindowRect( hwndCBox, &rc) ; HWND parent = GetParent(hwndCBox) ; MapWindowPoints( NULL, parent, (LPPOINT)&rc, 2) ; SetWindowPos( hwndCBox, NULL, rc.left, rc.top, rc.right - rc.left, nTotalHeight, SWP_NOZORDER) ; ShowWindow( GetDlgItem( hwndDlg, IDC_EDIT1 + i), SW_HIDE) ; // nascondo Edit ShowWindow( GetDlgItem( hwndDlg, IDC_CHECK1 + i), SW_HIDE) ; // nascondo CheckBox ShowWindow( GetDlgItem( hwndDlg, IDC_BUTTON_SEL1 + i), SW_HIDE) ; // nascondo Button di selezione s_nType[i] = CTRL_COMBO ; } // --- se ColorPicker else if ( s_sEdit[i].find( "CP:") == 0) { string sVal = s_sEdit[i].substr( 3) ; Color CColor ; if ( ! FromString( sVal, CColor)) CColor = INVISIBLE ; selectedColor[i] = RGB( CColor.GetIntRed(), CColor.GetIntGreen(), CColor.GetIntBlue()) ; if ( hColorBrush[i] != NULL) DeleteObject( hColorBrush[i]) ; hColorBrush[i] = CreateSolidBrush( selectedColor[i]) ; // recupero i valori dei colori personalizzati dal file .ini if ( ! s_bCustomColorsInit) { // recupero il file Ini string sIniFile = ExeGetIniFile() ; if ( ! sIniFile.empty()) { string sCustomVals = GetPrivateProfileStringUtf8( SEC_SCENE, KEY_CUSTOMCOLORS, "", sIniFile.c_str()) ; STRVECTOR vsWinColors ; Tokenize( sCustomVals, ",", vsWinColors) ; for ( int j = 0 ; j < ssize( vsWinColors) && j < 16 ; ++ j) { unsigned int unVal ; if ( FromString( vsWinColors[j], unVal)) { unsigned int unR = unVal & 0xFF ; unsigned int unG = ( unVal >> 8) & 0xFF ; unsigned int unB = ( unVal >> 16) & 0xFF ; s_CustomColors[j] = RGB( unR, unG, unB) ; } } } s_bCustomColorsInit = true ; } // nascondo qualsiasi tipo di componente ShowWindow( GetDlgItem( hwndDlg, IDC_EDIT1 + i), SW_HIDE) ; // nascondo Edit ShowWindow( GetDlgItem( hwndDlg, IDC_COMBO1 + i), SW_HIDE) ; // nascondo Combo ShowWindow( GetDlgItem( hwndDlg, IDC_CHECK1 + i), SW_HIDE) ; // nascondo Check ShowWindow( GetDlgItem( hwndDlg, IDC_BUTTON_SEL1 + i), SW_HIDE) ; // nascondo Button di selezione // margini per dimensione del rettangolo preview pickColor const int MARGIN_RIGHT = 8 ; // spazio tra preview e bordo destro dialog const int PREVIEW_HEIGHT = 20 ; // altezza del rettangolo const int PREVIEW_MIN_WIDTH = 40 ; // larghezza minima // creazione della static preview HWND hwndPreview = NULL ; HWND hwndEdit = GetDlgItem( hwndDlg, IDC_EDIT1 + i) ; RECT rcEdit ; GetClientRect( hwndDlg, &rcEdit) ; // coordinate client del dialog if ( hwndEdit != nullptr && GetWindowRect( hwndEdit, &rcEdit)) { // converti rcLabel in coordinate client POINT ptEdit = { rcEdit.left, rcEdit.top } ; ScreenToClient( hwndDlg, &ptEdit) ; int x = ptEdit.x ; int y = ptEdit.y ; int width = rcEdit.right - rcEdit.left ; if ( width < PREVIEW_MIN_WIDTH) width = PREVIEW_MIN_WIDTH ; hwndPreview = CreateWindowEx( 0, L"STATIC", NULL, WS_CHILD | WS_VISIBLE | SS_NOTIFY | SS_CENTERIMAGE | WS_BORDER, x, y, width, PREVIEW_HEIGHT, hwndDlg, ( HMENU)( IDC_COLOR1 + i), GetModuleHandle( NULL), NULL) ; } // pulizia elementi testuali if ( hwndPreview) { SetWindowText( hwndPreview, L"") ; SetWindowPos( hwndPreview, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE) ; InvalidateRect( hwndPreview, NULL, TRUE) ; UpdateWindow( hwndPreview) ; } s_nType[i] = CTRL_COLOR ; } // --- se Button di selezione else if ( s_sEdit[i].find( "BS:") == 0) { ShowWindow( GetDlgItem( hwndDlg, IDC_COMBO1 + i), SW_HIDE) ; // nascondo la Combo ShowWindow( GetDlgItem( hwndDlg, IDC_CHECK1 + i), SW_HIDE) ; // nascondo la Check SetDlgItemText( hwndDlg, IDC_BUTTON_SEL1 + i, stringtoW( string{ "-"})) ; // modalità non Selezione EnableWindow( GetDlgItem( hwndDlg, IDC_EDIT1 + i), FALSE) ; // disattivo la Edit // associo alla casella di testo la funzione di KeyPress su Enter HWND hEdit = GetDlgItem( hwndDlg, IDC_EDIT1 + i) ; if ( hEdit != nullptr) SetWindowSubclass( hEdit, UpdateSelectionModelessDialog, 1, (DWORD_PTR)( IDC_EDIT1 + i)) ; s_nType[i] = CTRL_BUTTON ; } // --- se Testo else { SetDlgItemText( hwndDlg, IDC_EDIT1 + i, stringtoW( s_sEdit[i])) ; ShowWindow( GetDlgItem( hwndDlg, IDC_COMBO1 + i), SW_HIDE) ; // nascondo Combo ShowWindow( GetDlgItem( hwndDlg, IDC_CHECK1 + i), SW_HIDE) ; // nascondo Check ShowWindow( GetDlgItem( hwndDlg, IDC_BUTTON_SEL1 + i), SW_HIDE) ; // nascondo Button di selezione s_nType[i] = CTRL_EDIT ; } } // se numero di controllo superiore al massimo, non visualizzo nullo ( in questo caso aggiungere elementi a Dialog in .rc) else { // nascondo tutto ShowWindow( GetDlgItem( hwndDlg, IDC_TEXT1 + i), SW_HIDE) ; ShowWindow( GetDlgItem( hwndDlg, IDC_EDIT1 + i), SW_HIDE) ; ShowWindow( GetDlgItem( hwndDlg, IDC_COMBO1 + i), SW_HIDE) ; ShowWindow( GetDlgItem( hwndDlg, IDC_CHECK1 + i), SW_HIDE) ; ShowWindow( GetDlgItem( hwndDlg, IDC_BUTTON_SEL1 + i), SW_HIDE) ; s_nType[i] = CTRL_NONE ; } } break ; case WM_CTLCOLORSTATIC : { HDC hdcStatic = ( HDC)wParam ; HWND hwndCtrl = ( HWND)lParam ; int ctrlId = GetDlgCtrlID( hwndCtrl) ; if ( ctrlId >= IDC_COLOR1 && ctrlId <= IDC_COLOR8) { int idx = ctrlId - IDC_COLOR1 ; if ( hColorBrush[idx] == NULL) hColorBrush[idx] = CreateSolidBrush( selectedColor[idx]) ; SetBkMode( hdcStatic, OPAQUE) ; SetBkColor( hdcStatic, selectedColor[idx]) ; return ( INT_PTR)hColorBrush[idx] ; } } break ; case WM_COMMAND : { int id = LOWORD( wParam) ; int code = HIWORD( wParam) ; // --- se click di un Button di selezione if ( id >= IDC_BUTTON_SEL1 && id < IDC_BUTTON_SEL1 + MAX_CTRLS) { int nBtnId = id ; int nEditId = IDC_EDIT1 + ( id - IDC_BUTTON_SEL1) ; int nActiveRow = nEditId - IDC_EDIT1 ; // se il bottone premuto è lo stesso if ( nDlgModelessItem == nEditId) { // se selezione attiva, allora deve terminare if ( s_bSelectionMode) { SetDlgItemText( hwndDlg, nBtnId, stringtoW( string{ "-"})) ; EndSelectionMode( hwndDlg) ; } // se selezione non attiva, allora viene attivata else { SetDlgItemText( hwndDlg, nBtnId, stringtoW( string{ "S"})) ; StartSelectionMode( hwndDlg, nEditId, nActiveRow) ; } } // se nuovo buttone premuto else { // se esisteva una selezione precedente, questa viene annullata if ( nDlgModelessItem != -1) { // recupero il Button di selezione precedente e modifico il suo testo int nPrevBtnId = IDC_BUTTON_SEL1 + ( nDlgModelessItem - IDC_EDIT1) ; SetDlgItemText( hwndDlg, nPrevBtnId, stringtoW( string{ "-"})) ; } // la selezione passa al comando corrente nDlgModelessItem = nEditId ; SetDlgItemText( hwndDlg, nBtnId, stringtoW( string{ "S"})) ; // il dialogo diventa "Modeless" temporaneamente s_nActiveRow = nEditId - IDC_EDIT1 ; StartSelectionMode( hwndDlg, nEditId, nActiveRow) ; } return TRUE ; // !<-- esco } // --- se comando di Preview per brush di colori mediante click del mouse else if ( code == STN_CLICKED && id >= IDC_COLOR1 && id <= IDC_COLOR8) { // se selezione attiva, allora deve terminare if ( s_bSelectionMode) { // se esisteva una selezione precedente, questa viene annullata if ( nDlgModelessItem != -1) { // recupero il Button di selezione precedente e modifico il suo testo int nPrevBtnId = IDC_BUTTON_SEL1 + ( nDlgModelessItem - IDC_EDIT1) ; SetDlgItemText( hwndDlg, nPrevBtnId, stringtoW( string{ "-"})) ; } EndSelectionMode( hwndDlg) ; } int idx = id - IDC_COLOR1 ; HWND hwndPreview = GetDlgItem( hwndDlg, IDC_COLOR1 + idx) ; if ( ! hwndPreview) return TRUE ; // apertura ChooseColor (usa hwndDlg come owner) CHOOSECOLOR cc = {} ; cc.lStructSize = sizeof( cc) ; cc.hwndOwner = hwndDlg ; cc.lpCustColors = s_CustomColors ; cc.rgbResult = selectedColor[idx] ; cc.Flags = CC_FULLOPEN | CC_RGBINIT ; if ( ChooseColor( &cc)) { selectedColor[idx] = cc.rgbResult ; // salvo nel file Ini i nuovi colori personalizzati string sIniFile = ExeGetIniFile() ; if ( ! sIniFile.empty()) { string sOut = "" ; for ( int j = 0 ; j < ssize( s_CustomColors) && j < 16 ; ++ j) sOut += ToString( ( unsigned int)s_CustomColors[j]) + "," ; sOut.pop_back() ; WritePrivateProfileStringUtf8( SEC_SCENE, KEY_CUSTOMCOLORS, sOut.c_str(), sIniFile.c_str()) ; } if ( hColorBrush[idx] != NULL) DeleteObject( hColorBrush[idx]) ; hColorBrush[idx] = CreateSolidBrush( selectedColor[idx]) ; InvalidateRect(hwndPreview, NULL, TRUE) ; UpdateWindow( hwndPreview) ; } return TRUE ; // !<-- Esco } switch ( LOWORD( wParam)) { case IDOK : { // recupero il contesto impostato alla creazione della finestra (durante esecuzione WM_INITDIALOG) DialogContext* ctx = (DialogContext*)GetWindowLongPtr( hwndDlg, GWLP_USERDATA) ; if ( ctx != nullptr) { // inizializzo i risultati ctx->vsResult.clear() ; ctx->vsResult.reserve( s_nCtrls) ; // recupero i valori degli Item for ( int i = 0 ; i < s_nCtrls ; ++ i) { AtoWEX<128> wsEdit( "") ; s_sEdit[i] = "" ; switch ( s_nType[i]) { case CTRL_CHECK : s_sEdit[i] = ( IsDlgButtonChecked( hwndDlg, IDC_CHECK1 + i) == BST_CHECKED ? "1" : "0") ; break ; case CTRL_COMBO : if ( GetDlgItemText( hwndDlg, IDC_COMBO1 + i, LPWSTR( wsEdit), 128) > 0) s_sEdit[i] = wstrztoA( wsEdit) ; break ; case CTRL_EDIT : if ( GetDlgItemText( hwndDlg, IDC_EDIT1 + i, LPWSTR( wsEdit), 128) > 0) s_sEdit[i] = wstrztoA( wsEdit) ; break ; case CTRL_COLOR : { COLORREF col = selectedColor[i] ; BYTE r = GetRValue( col), g = GetGValue( col), b = GetBValue( col) ; char buf[16] ; sprintf_s( buf, sizeof( buf), "%u,%u,%u", r, g, b) ; s_sEdit[i] = buf ; } break ; case CTRL_BUTTON : if ( GetDlgItemText( hwndDlg, IDC_EDIT1 + i, LPWSTR( wsEdit), 128) > 0) s_sEdit[i] = wstrztoA( wsEdit) ; break ; } // inserisco i valori all'interno della tabella Lua ctx->vsResult.push_back( s_sEdit[i]) ; } ctx->bCancelled = false ; ctx->bDone = true ; } // chiudo il dialogo OnClosingDialog( hwndDlg) ; return TRUE ; } [[fallthrough]] ; case IDCANCEL : { // pulizia brush colori for ( int i = 0 ; i < MAX_CTRLS ; ++ i) { if ( hColorBrush[i] != NULL) { DeleteObject( hColorBrush[i]) ; hColorBrush[i] = NULL ; } } // recupero il contesto impostato alla creazione della finestra ( durante esecuzione WM_INITDIALOG) e se esiste lo rimuovo DialogContext* ctx = (DialogContext*)GetWindowLongPtr( hwndDlg, GWLP_USERDATA) ; if ( ctx != nullptr) { ctx->bCancelled = true ; ctx->bDone = true ; } // chiudo il dialogo OnClosingDialog( hwndDlg) ; return TRUE ; } } // se siamo in modalità di Selezione e il comando attivo non si riferisce ad un button di Selezione (BS), il dialogo torna modale if ( s_bSelectionMode) { bool bIsBS = ( id >= IDC_BUTTON_SEL1 && id < IDC_BUTTON_SEL1 + MAX_CTRLS) ; bool bIsActiveEdit = ( id == IDC_EDIT1 + s_nActiveRow) ; // il dialogo torna modale if ( ! bIsBS && ! bIsActiveEdit) EndSelectionMode( hwndDlg) ; } break ; } case WM_CLOSE : { // recupero il contesto impostato alla creazione della finestra ( durante esecuzione WM_INITDIALOG) e se esiste lo rimuovo DialogContext* ctx = (DialogContext*)GetWindowLongPtr( hwndDlg, GWLP_USERDATA) ; if ( ctx != nullptr) { ctx->bCancelled = true ; ctx->bDone = true ; } // chiudo il dialogo OnClosingDialog( hwndDlg) ; return TRUE ; } } return FALSE ; } //------------------------------------------------------------------------------- // LuaDialogBox (Modeless) // // Scopo: // ------ // Questa funzione implementa un dialogo "modale" dal punto di vista del codice Lua, ma "modeless" dal punto di vista della // UI Windows quando necessario. L’obiettivo è permettere al codice Lua di rimanere sospeso finché l’utente non chiude il // dialogo (OK/Cancel/X), mantenendo però la UI attiva e permettendo selezioni nella scena quando l’utente preme un pulsante // BS (Button Selection). // // Perché serve: // ------------- // - I dialoghi modali standard (DialogBox) bloccano completamente la UI, mentre i dialoghi modeless standard (CreateDialog) // NON bloccano il codice Lua. // - Le coroutine Lua (lua_yield/lua_resume) non sono utilizzabili in questo contesto perché il thread principale // dell’applicazione non può essere sospeso tramite yield: il codice Lua non riprende correttamente e la UI non si // aggiorna coerentemente) // // Come funziona: // -------------- // 1) Il dialogo viene creato con CreateDialogParam(), quindi la UI rimane attiva. // 2) La funzione NON ritorna subito: entra in un message loop locale (Esattamente equivalente al loop all'interno di // DialogBox()). Il cuore del loop è GetMessage(), che è una chiamata BLOCCANTE. Significa che il thread rimane in // attesa senza consumare CPU finché non arriva un messaggio. Non c’è polling, non c’è busy loop. Il comportamento è // identico a quello di un dialogo modale nativo. // 3) Il ciclo rimane attivo finché: // - l’utente non chiude il dialogo (OK/Cancel/X) // - oppure la finestra viene distrutta // In quel momento ctx->bDone viene impostato a true. // 4) Durante la vita del dialogo, se l’utente preme un pulsante BS, il dialogo diventa temporaneamente "modeless": // - la main window viene abilitata // - il dialogo rimane abilitato ma passa in secondo piano logico // - l’utente può selezionare oggetti nella scena // Quando la selezione termina, il dialogo torna modale. // 5) Quando il dialogo chiude, i valori vengono copiati in ctx->vsResult e ritornati a Lua come risultato della funzione. // // Vantaggi della soluzione: // ------------------------- // - Lua rimane bloccato come con un dialogo modale tradizionale. // - La UI rimane completamente attiva. // - Le selezioni BS (mediante Button Selection) funzionano senza bloccare il programma. // - Nessun uso di coroutine Lua (che non erano affidabili in questo contesto). // - Nessun consumo CPU anomalo. // - Comportamento stabile e prevedibile. // // Nota importante: // ---------------- // Il dialogo NON viene mai disabilitato durante la selezione BS (Button Selection). Solo la main window viene // abilitata temporaneamente. // Questo è fondamentale: disabilitare il dialogo impedirebbe all’utente di poterlo riselezionare dopo la selezione nella scena. // static int LuaDialogBox( lua_State* L) { // 1 .. 9 parametri : sCaption, { sText, sDefault}, ... LuaCheckParam( L, 1, s_sCaption) s_nCtrls = 0 ; for ( int i = 0 ; i < MAX_CTRLS ; ++ i) { STRVECTOR vData ; if ( LuaGetParam( L, 2 + i, vData) && ssize( vData) >= 2) { s_sText[i] = Trim( vData[0]) ; s_sEdit[i] = Trim( vData[1]) ; ++ s_nCtrls ; } else break ; } LuaClearStack( L) ; // se UI disabilitata, esco if ( ! ExeGetEnableUI()) { LuaSetParam( L) ; return 1 ; } // se dialogo Modeless già aperto, errore if ( phDlgModeless != nullptr) { LuaSetParam( L) ; return 1 ; } // creazione del contesto e della Coroutine da gestire DialogContext* ctx = new DialogContext() ; if ( ctx == nullptr) { LuaSetParam( L) ; return 1 ; } // creazione di un dialogo Modeless HWND hTopWnd = ExeGetMainWindowHandle() ; nDlgModelessItem = -1 ; phDlgModeless = ( CreateDialogParam( GetModuleIstance(), MAKEINTRESOURCE( IDD_LUADLG), hTopWnd, (DLGPROC)DialogBoxModelessProc, (LPARAM)ctx)) ; if ( phDlgModeless == nullptr) { delete( ctx) ; ctx = nullptr ; LuaSetParam( L) ; return 1 ; } // porto la finestra in primo piano ShowWindow( phDlgModeless, SW_SHOW) ; SetForegroundWindow( phDlgModeless) ; // message Loop Modale (ripresa del Loop come da dialogo modale) MSG msg ; while ( ! ctx->bDone && IsWindow( phDlgModeless)) { if ( GetMessage( &msg, NULL, 0, 0) <= 0) break ; if ( ! IsDialogMessage( phDlgModeless, &msg)) { TranslateMessage( &msg) ; DispatchMessage( &msg) ; } } // ritorno i valori lua if ( ctx->bCancelled) LuaSetParam( L, false) ; else LuaSetParam( L, ctx->vsResult) ; // libero la memoria delete ctx ; ctx = nullptr ; return 1 ; } //------------------------------------------------------------------------------- bool LuaInstallGeneral( LuaMgr& luaMgr) { bool bOk = ( &luaMgr != nullptr) ; bOk = bOk && luaMgr.RegisterFunction( "print", MyPrint) ; bOk = bOk && luaMgr.RegisterFunction( "EgtEvalNumExpr", LuaEvalNumExpr) ; bOk = bOk && luaMgr.RegisterFunction( "EgtPause", LuaPause) ; bOk = bOk && luaMgr.RegisterFunction( "EgtGetKeyPressed", LuaGetKeyPressed) ; bOk = bOk && luaMgr.RegisterFunction( "EgtStartCounter", LuaStartCounter) ; bOk = bOk && luaMgr.RegisterFunction( "EgtStopCounter", LuaStopCounter) ; bOk = bOk && luaMgr.RegisterFunction( "EgtNumToString", LuaNumToString) ; bOk = bOk && luaMgr.RegisterFunction( "EgtSplitString", LuaSplitString) ; bOk = bOk && luaMgr.RegisterFunction( "EgtSplitStringPlus", LuaSplitStringPlus) ; bOk = bOk && luaMgr.RegisterFunction( "EgtReplaceString", LuaReplaceString) ; bOk = bOk && luaMgr.RegisterFunction( "EgtSetVal", LuaSetVal) ; bOk = bOk && luaMgr.RegisterFunction( "EgtGetVal", LuaGetVal) ; bOk = bOk && luaMgr.RegisterFunction( "EgtGetUUID", LuaGetUUID) ; bOk = bOk && luaMgr.RegisterFunction( "EgtExecTsc", LuaExecTsc) ; bOk = bOk && luaMgr.RegisterFunction( "EgtExecTscLine", LuaExecTscLine) ; bOk = bOk && luaMgr.RegisterFunction( "EgtSetTscVar", LuaSetTscVar) ; bOk = bOk && luaMgr.RegisterFunction( "EgtGetTscVar", LuaGetTscVar) ; bOk = bOk && luaMgr.RegisterFunction( "EgtGetDebugLevel", LuaGetDebugLevel) ; bOk = bOk && luaMgr.RegisterFunction( "EgtGetUserLevel", LuaGetUserLevel) ; bOk = bOk && luaMgr.RegisterFunction( "EgtOutLog", LuaOutLog) ; bOk = bOk && luaMgr.RegisterFunction( "EgtGetEnableUI", LuaGetEnableUI) ; bOk = bOk && luaMgr.RegisterFunction( "EgtOutBox", LuaOutBox) ; bOk = bOk && luaMgr.RegisterFunction( "EgtProcessEvents", LuaProcessEvents) ; bOk = bOk && luaMgr.RegisterFunction( "EgtOutText", LuaOutText) ; bOk = bOk && luaMgr.RegisterFunction( "EgtFileDialog", LuaFileDialog) ; bOk = bOk && luaMgr.RegisterFunction( "EgtExistsFile", LuaExistsFile) ; bOk = bOk && luaMgr.RegisterFunction( "EgtCopyFile", LuaCopyFile) ; bOk = bOk && luaMgr.RegisterFunction( "EgtRenameFile", LuaRenameFile) ; bOk = bOk && luaMgr.RegisterFunction( "EgtEraseFile", LuaEraseFile) ; bOk = bOk && luaMgr.RegisterFunction( "EgtFindAllFiles", LuaFindAllFiles) ; bOk = bOk && luaMgr.RegisterFunction( "EgtCompareFilesLastWriteTime", LuaCompareFilesLastWriteTime) ; bOk = bOk && luaMgr.RegisterFunction( "EgtDirectoryDialog", LuaDirectoryDialog) ; bOk = bOk && luaMgr.RegisterFunction( "EgtExistsDirectory", LuaExistsDirectory) ; bOk = bOk && luaMgr.RegisterFunction( "EgtCreateDirectory", LuaCreateDirectory) ; bOk = bOk && luaMgr.RegisterFunction( "EgtEmptyDirectory", LuaEmptyDirectory) ; bOk = bOk && luaMgr.RegisterFunction( "EgtEraseDirectory", LuaEraseDirectory) ; bOk = bOk && luaMgr.RegisterFunction( "EgtEraseNonEmptyDirectory", LuaEraseNonEmptyDirectory) ; bOk = bOk && luaMgr.RegisterFunction( "EgtTextFileCompare", LuaTextFileCompare) ; bOk = bOk && luaMgr.RegisterFunction( "EgtBinaryFileCompare", LuaBinaryFileCompare) ; bOk = bOk && luaMgr.RegisterFunction( "EgtGetStringFromIni", LuaGetStringFromIni) ; bOk = bOk && luaMgr.RegisterFunction( "EgtWriteStringToIni", LuaWriteStringToIni) ; bOk = bOk && luaMgr.RegisterFunction( "EgtGetIniFile", LuaGetIniFile) ; bOk = bOk && luaMgr.RegisterFunction( "EgtGetTempDir", LuaGetTempDir) ; bOk = bOk && luaMgr.RegisterFunction( "EgtGetExeVersion", LuaGetExeVersion) ; bOk = bOk && luaMgr.RegisterFunction( "EgtGetVersion", LuaGetVersion) ; bOk = bOk && luaMgr.RegisterFunction( "EgtIs64bit", LuaIs64bit) ; bOk = bOk && luaMgr.RegisterFunction( "EgtGetLanguage", LuaGetLanguage) ; bOk = bOk && luaMgr.RegisterFunction( "EgtMsg", LuaGetMsg) ; bOk = bOk && luaMgr.RegisterFunction( "EgtVerifyKeyOption", LuaVerifyKeyOption) ; bOk = bOk && luaMgr.RegisterFunction( "EgtSetDefaultFont", LuaSetDefaultFont) ; bOk = bOk && luaMgr.RegisterFunction( "EgtGetDefaultFont", LuaGetDefaultFont) ; bOk = bOk && luaMgr.RegisterFunction( "EgtWinExec", LuaWinExec) ; bOk = bOk && luaMgr.RegisterFunction( "EgtCloseExe", LuaCloseExe) ; bOk = bOk && luaMgr.RegisterFunction( "EgtCreateMutex", LuaCreateMutex) ; bOk = bOk && luaMgr.RegisterFunction( "EgtReleaseMutex", LuaReleaseMutex) ; bOk = bOk && luaMgr.RegisterFunction( "EgtDialogBox", LuaDialogBox) ; return bOk ; }