diff --git a/AuxDialogBox.cpp b/AuxDialogBox.cpp index f8f6907..072200e 100644 --- a/AuxDialogBox.cpp +++ b/AuxDialogBox.cpp @@ -22,7 +22,7 @@ using namespace std ; -#pragma comment( lib, "Comctl32.lib") +#pragma comment( lib, "Comctl32.lib") // per funzioni LRESULT CALLBACK HWND phDlgModeless = nullptr ; int nDlgModelessItem = -1 ; @@ -53,7 +53,8 @@ UpdateIdsModelessDialog( HWND phDlgModeless, int nDlgModelessItem) } //----------------------------------------------------------------------------- -LRESULT CALLBACK UpdateSelectionModelessDialog( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData) +LRESULT +CALLBACK UpdateSelectionModelessDialog( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData) { if ( msg == WM_GETDLGCODE) return DLGC_WANTALLKEYS ; @@ -61,7 +62,7 @@ LRESULT CALLBACK UpdateSelectionModelessDialog( HWND hwnd, UINT msg, WPARAM wPar if ( msg == WM_KEYDOWN && wParam == VK_RETURN) { // dwRefData contiene l'ID dell'EDIT int nEditId = int( dwRefData) ; - HWND hwndDlg = GetParent(hwnd); + HWND hwndDlg = GetParent(hwnd) ; if ( hwndDlg == nullptr) return FALSE ; // recupero il testo dell'EDIT corretto @@ -75,7 +76,7 @@ LRESULT CALLBACK UpdateSelectionModelessDialog( HWND hwnd, UINT msg, WPARAM wPar if ( ! sIds.empty()) { STRVECTOR vsIds; Tokenize( sIds, ",", vsIds) ; - for ( auto& s : vsIds) { + for ( const string& s : vsIds) { int nId = GDB_ID_NULL ; if ( FromString( s, nId) && nId != GDB_ID_NULL) ExeSelectObj( nId) ; @@ -86,5 +87,5 @@ LRESULT CALLBACK UpdateSelectionModelessDialog( HWND hwnd, UINT msg, WPARAM wPar return TRUE ; } - return ( DefSubclassProc(hwnd, msg, wParam, lParam)) ; + return ( DefSubclassProc( hwnd, msg, wParam, lParam)) ; } diff --git a/EXE_GdbObjSelection.cpp b/EXE_GdbObjSelection.cpp index 2123095..cd7c3af 100644 --- a/EXE_GdbObjSelection.cpp +++ b/EXE_GdbObjSelection.cpp @@ -146,9 +146,6 @@ ExeSelectAll( bool bOnlyIfVisible) " -- bOk=1" ; LOG_INFO( GetCmdLogger(), sLua.c_str()) ; } - // verifico se presente un dialogo modeless per aggiornare i valori - if ( phDlgModeless != nullptr && nDlgModelessItem != -1) - UpdateIdsModelessDialog( phDlgModeless, nDlgModelessItem) ; // restituisco risultato return true ; } diff --git a/EgtExecutor.rc b/EgtExecutor.rc index dafe5c6..856fa02 100644 Binary files a/EgtExecutor.rc and b/EgtExecutor.rc differ diff --git a/LUA_General.cpp b/LUA_General.cpp index 5f48984..1251bf3 100644 --- a/LUA_General.cpp +++ b/LUA_General.cpp @@ -1,4 +1,4 @@ -//---------------------------------------------------------------------------- +//---------------------------------------------------------------------------- // EgalTech 2014-2014 //---------------------------------------------------------------------------- // File : LUA_General.cpp Data : 27.09.14 Versione : 1.5i5 @@ -119,7 +119,7 @@ LuaGetKeyPressed( lua_State* L) int nKeyCode ; LuaCheckParam( L, 1, nKeyCode) LuaClearStack( L) ; - // se abilitata UI, controllo se il tasto indicato č premuto + // se abilitata UI, controllo se il tasto indicato è premuto bool bPressed = false ; if ( ExeGetEnableUI()) { bPressed = (( GetAsyncKeyState( nKeyCode) & 0x8000) != 0) ; @@ -182,7 +182,7 @@ LuaSplitString( lua_State* L) 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) + // 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 @@ -517,7 +517,7 @@ LuaOutLog( lua_State* L) LuaClearStack( L) ; // accodo il messaggio nel file di log ExeOutLog( sOut, nDbgLev) ; - // non c'č risultato + // non c'è risultato return 0 ; } @@ -1179,7 +1179,7 @@ LuaCloseExe( lua_State* 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) + // restituisco il risultato (se arrivo qui vuol dire che non è consnetito terminare l'esecuzione) LuaSetParam( L, false) ; return 1 ; } @@ -1222,30 +1222,145 @@ static bool s_bCustomColorsInit = false ; // flag di ini const char* SEC_SCENE = "Scene" ; const char* KEY_CUSTOMCOLORS = "CustomColors" ; -// Dialogo Modale +// 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] ; - -// Dialogo non modale -const int MAX_CTRLS_ML = IDC_TEXT_ML_8 - IDC_TEXT_ML_1 + 1 ; -static int s_nCtrls_ML = 0 ; -static string s_sCaption_ML ; -static string s_sText_ML[MAX_CTRLS_ML] ; -static string s_sEdit_ML[MAX_CTRLS_ML] ; -static int s_nType_ML[MAX_CTRLS_ML] ; struct DialogContext { - lua_State* L ; // stato Lua per Click bottone OK - int nCallBackFun ; // indice di funzione CallBack + 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 DialogBoxProc( HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam) +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 @@ -1254,6 +1369,14 @@ CALLBACK DialogBoxProc( HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam 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 @@ -1277,60 +1400,61 @@ CALLBACK DialogBoxProc( HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam 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, + 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) ; + 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) ; + 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) ; + 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) ; - ShowWindow( GetDlgItem( hwndDlg, IDC_COMBO1 + i), SW_HIDE) ; + 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 < int( vsVal.size()) ; ++ j) { + for ( int j = 0 ; j < ssize( vsVal) ; ++ j) { string sItem ; if ( vsVal[j][0] == '*') { nSel = j ; @@ -1341,10 +1465,19 @@ CALLBACK DialogBoxProc( HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam ComboBox_AddString( hwndCBox, stringtoW( sItem)) ; } ComboBox_SetCurSel( hwndCBox, nSel) ; - ShowWindow( GetDlgItem( hwndDlg, IDC_EDIT1 + i), SW_HIDE) ; - ShowWindow( GetDlgItem( hwndDlg, IDC_CHECK1 + i), SW_HIDE) ; + 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 ; @@ -1373,306 +1506,11 @@ CALLBACK DialogBoxProc( HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam } s_bCustomColorsInit = true ; } - // nascondo qualsiasi tipo di componente ( per sicurezza) - ShowWindow( GetDlgItem( hwndDlg, IDC_EDIT1 + i), SW_HIDE) ; - ShowWindow( GetDlgItem( hwndDlg, IDC_COMBO1 + i), SW_HIDE) ; - ShowWindow( GetDlgItem( hwndDlg, IDC_CHECK1 + i), SW_HIDE) ; - - // 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 - - // ottieni o crea la static preview (allargata fino al bordo destro del dialog) - HWND hwndPreview = NULL ; - RECT rcLabel ; - HWND hwndLabel = GetDlgItem( hwndDlg, IDC_TEXT1 + i) ; - RECT rcClient ; GetClientRect( hwndDlg, &rcClient) ; // coordinate client del dialog - if ( hwndLabel && GetWindowRect( hwndLabel, &rcLabel)) { - // converti rcLabel in coordinate client - POINT ptLabel = { rcLabel.right, rcLabel.top } ; - ScreenToClient( hwndDlg, &ptLabel) ; - int x = ptLabel.x + 8 ; // distanza dal label - int y = ptLabel.y ; - int width = rcClient.right - x - MARGIN_RIGHT ; - 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 ; - } - else { - SetDlgItemText( hwndDlg, IDC_EDIT1 + i, stringtoW( s_sEdit[i])) ; - ShowWindow( GetDlgItem( hwndDlg, IDC_COMBO1 + i), SW_HIDE) ; - ShowWindow( GetDlgItem( hwndDlg, IDC_CHECK1 + i), SW_HIDE) ; - s_nType[i] = CTRL_EDIT ; - } - } - else { - 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) ; - 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) ; - // comando di Preview per brush di colori mediante click del mouse - if ( code == STN_CLICKED && id >= IDC_COLOR1 && id <= IDC_COLOR8) { - 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 ; - } - - switch ( LOWORD( wParam)) { - case IDOK : - 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 ; - } - } - } - [[fallthrough]] ; - case IDCANCEL : { - // pulizia brush colori - for ( int i = 0 ; i < MAX_CTRLS ; ++ i) { - if ( hColorBrush[i] != NULL) { - DeleteObject( hColorBrush[i]) ; - hColorBrush[i] = NULL ; - } - } - EndDialog( hwndDlg, wParam) ; - return TRUE ; - } - } - } - } - return FALSE ; -} - -//------------------------------------------------------------------------------- -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_ML] = {0} ; // BLACK - static HBRUSH hColorBrush[MAX_CTRLS_ML] = {NULL} ; // non definito - - switch ( message) { - case WM_INITDIALOG : - { - // imposto il contesto 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_ML ; ++ 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_TEXT_ML_1 + Clamp( s_nCtrls_ML, 1, MAX_CTRLS_ML) - 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_ML) ; - 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_ML) ; - 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_ML)) ; - - // assegno testi e valori di default e nascondo linee dei controlli non usati - for ( int i = 0 ; i < MAX_CTRLS_ML ; ++ i) { - if ( i < s_nCtrls_ML) { - - // imposto il testo nella riga corrente - SetDlgItemText( hwndDlg, IDC_TEXT_ML_1 + i, stringtoW( s_sText_ML[i])) ; - - // --- se CheckBox - if ( s_sEdit_ML[i].find( "CK:") == 0) { - bool bChecked = false ; - FromString( s_sEdit_ML[i].substr( 3), bChecked) ; - CheckDlgButton( hwndDlg, IDC_CHECK_ML_1 + i, ( bChecked ? BST_CHECKED : BST_UNCHECKED)) ; - ShowWindow( GetDlgItem( hwndDlg, IDC_EDIT_ML_1 + i), SW_HIDE) ; // nascondo Edit - ShowWindow( GetDlgItem( hwndDlg, IDC_COMBO_ML_1 + i), SW_HIDE) ; // nascondo Combo - ShowWindow( GetDlgItem( hwndDlg, IDC_BUTTON_SEL_ML_1 + i), SW_HIDE) ; // nascondo Button di selezione - s_nType_ML[i] = CTRL_CHECK ; - } - - // --- se ComboBox - else if ( s_sEdit_ML[i].find( "CB:") == 0) { - string sList = s_sEdit_ML[i].substr( 3) ; - STRVECTOR vsVal ; - Tokenize( sList, ",", vsVal) ; - int nSel = 0 ; - HWND hwndCBox = GetDlgItem( hwndDlg, IDC_COMBO_ML_1 + 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_EDIT_ML_1 + i), SW_HIDE) ; // nascondo Edit - ShowWindow( GetDlgItem( hwndDlg, IDC_CHECK_ML_1 + i), SW_HIDE) ; // nascondo CheckBox - ShowWindow( GetDlgItem( hwndDlg, IDC_BUTTON_SEL_ML_1 + i), SW_HIDE) ; // nascondo Button di selezione - s_nType_ML[i] = CTRL_COMBO ; - } - - // --- se ColorPicker - else if ( s_sEdit_ML[i].find( "CP:") == 0) { - string sVal = s_sEdit_ML[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_EDIT_ML_1 + i), SW_HIDE) ; // nascondo Edit - ShowWindow( GetDlgItem( hwndDlg, IDC_COMBO_ML_1 + i), SW_HIDE) ; // nascondo Combo - ShowWindow( GetDlgItem( hwndDlg, IDC_CHECK_ML_1 + i), SW_HIDE) ; // nascondo Check - ShowWindow( GetDlgItem( hwndDlg, IDC_BUTTON_SEL_ML_1 + i), SW_HIDE) ; // nascondo Button di selezione + 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 @@ -1681,7 +1519,7 @@ CALLBACK DialogBoxModelessProc( HWND hwndDlg, UINT message, WPARAM wParam, LPARA // creazione della static preview HWND hwndPreview = NULL ; - HWND hwndEdit = GetDlgItem( hwndDlg, IDC_EDIT_ML_1 + i) ; + 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 @@ -1705,38 +1543,39 @@ CALLBACK DialogBoxModelessProc( HWND hwndDlg, UINT message, WPARAM wParam, LPARA InvalidateRect( hwndPreview, NULL, TRUE) ; UpdateWindow( hwndPreview) ; } - s_nType_ML[i] = CTRL_COLOR ; + s_nType[i] = CTRL_COLOR ; } // --- se Button di selezione - else if ( s_sEdit_ML[i].find( "BS:") == 0) { - ShowWindow( GetDlgItem( hwndDlg, IDC_COMBO_ML_1 + i), SW_HIDE) ; // nascondo la Combo - ShowWindow( GetDlgItem( hwndDlg, IDC_CHECK_ML_1 + i), SW_HIDE) ; // nascondo la Check - SetDlgItemText( hwndDlg, IDC_BUTTON_SEL_ML_1 + i, stringtoW( string{ "-"})) ; // modalitŕ non 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_EDIT_ML_1 + i) ; + HWND hEdit = GetDlgItem( hwndDlg, IDC_EDIT1 + i) ; if ( hEdit != nullptr) - SetWindowSubclass( hEdit, UpdateSelectionModelessDialog, 1, (DWORD_PTR)( IDC_EDIT_ML_1 + i)) ; - s_nType_ML[i] = CTRL_BUTTON ; + SetWindowSubclass( hEdit, UpdateSelectionModelessDialog, 1, (DWORD_PTR)( IDC_EDIT1 + i)) ; + s_nType[i] = CTRL_BUTTON ; } // --- se Testo else { - SetDlgItemText( hwndDlg, IDC_EDIT_ML_1 + i, stringtoW( s_sEdit_ML[i])) ; - ShowWindow( GetDlgItem( hwndDlg, IDC_COMBO_ML_1 + i), SW_HIDE) ; // nascondo Combo - ShowWindow( GetDlgItem( hwndDlg, IDC_CHECK_ML_1 + i), SW_HIDE) ; // nascondo Check - ShowWindow( GetDlgItem( hwndDlg, IDC_BUTTON_SEL_ML_1 + i), SW_HIDE) ; // nascondo Button di selezione - s_nType_ML[i] = CTRL_EDIT ; + 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_TEXT_ML_1 + i), SW_HIDE) ; - ShowWindow( GetDlgItem( hwndDlg, IDC_EDIT_ML_1 + i), SW_HIDE) ; - ShowWindow( GetDlgItem( hwndDlg, IDC_COMBO_ML_1 + i), SW_HIDE) ; - ShowWindow( GetDlgItem( hwndDlg, IDC_CHECK_ML_1 + i), SW_HIDE) ; - ShowWindow( GetDlgItem( hwndDlg, IDC_BUTTON_SEL_ML_1 + i), SW_HIDE) ; + 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 ; } } @@ -1763,32 +1602,52 @@ CALLBACK DialogBoxModelessProc( HWND hwndDlg, UINT message, WPARAM wParam, LPARA int code = HIWORD( wParam) ; // --- se click di un Button di selezione - if ( id >= IDC_BUTTON_SEL_ML_1 && id < IDC_BUTTON_SEL_ML_1 + MAX_CTRLS_ML) { + if ( id >= IDC_BUTTON_SEL1 && id < IDC_BUTTON_SEL1 + MAX_CTRLS) { int nBtnId = id ; - int nEditId = IDC_EDIT_ML_1 + ( id - IDC_BUTTON_SEL_ML_1) ; - // se il bottone premuto č lo stesso, allora termina le selezione degli Ids + int nEditId = IDC_EDIT1 + ( id - IDC_BUTTON_SEL1) ; + int nActiveRow = nEditId - IDC_EDIT1 ; + // se il bottone premuto è lo stesso if ( nDlgModelessItem == nEditId) { - SetDlgItemText( hwndDlg, nBtnId, stringtoW( string{ "-"})) ; - nDlgModelessItem = -1 ; + // 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_SEL_ML_1 + ( nDlgModelessItem - IDC_EDIT_ML_1) ; + 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) ; } - // per semplicitŕ, deseleziono tutto - ExeDeselectAll() ; - ExeDraw() ; + 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) @@ -1817,36 +1676,33 @@ CALLBACK DialogBoxModelessProc( HWND hwndDlg, UINT message, WPARAM wParam, LPARA InvalidateRect(hwndPreview, NULL, TRUE) ; UpdateWindow( hwndPreview) ; } - return TRUE ; + return TRUE ; // !<-- Esco } switch ( LOWORD( wParam)) { - case IDOK_ML : { - // recupero il contesto impostato alla creazione della finestra ( durante esecuzione WM_INITDIALOG) + case IDOK : { + // recupero il contesto impostato alla creazione della finestra (durante esecuzione WM_INITDIALOG) DialogContext* ctx = (DialogContext*)GetWindowLongPtr( hwndDlg, GWLP_USERDATA) ; - if ( ctx != nullptr && ctx->nCallBackFun != LUA_NOREF) { - - // recupero la CallBack - lua_rawgeti( ctx->L, LUA_REGISTRYINDEX, ctx->nCallBackFun) ; - // definisco una tabella per tutti i valori Lua da restituire - lua_newtable( ctx->L) ; - + 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_ML ; ++ i) { + for ( int i = 0 ; i < s_nCtrls ; ++ i) { AtoWEX<128> wsEdit( "") ; - s_sEdit_ML[i] = "" ; + s_sEdit[i] = "" ; - switch ( s_nType_ML[i]) { + switch ( s_nType[i]) { case CTRL_CHECK : - s_sEdit_ML[i] = ( IsDlgButtonChecked( hwndDlg, IDC_CHECK_ML_1 + i) == BST_CHECKED ? "1" : "0") ; + s_sEdit[i] = ( IsDlgButtonChecked( hwndDlg, IDC_CHECK1 + i) == BST_CHECKED ? "1" : "0") ; break ; case CTRL_COMBO : - if ( GetDlgItemText( hwndDlg, IDC_COMBO_ML_1 + i, LPWSTR( wsEdit), 128) > 0) - s_sEdit_ML[i] = wstrztoA( wsEdit) ; + if ( GetDlgItemText( hwndDlg, IDC_COMBO1 + i, LPWSTR( wsEdit), 128) > 0) + s_sEdit[i] = wstrztoA( wsEdit) ; break ; case CTRL_EDIT : - if ( GetDlgItemText( hwndDlg, IDC_EDIT_ML_1 + i, LPWSTR( wsEdit), 128) > 0) - s_sEdit_ML[i] = wstrztoA( wsEdit) ; + if ( GetDlgItemText( hwndDlg, IDC_EDIT1 + i, LPWSTR( wsEdit), 128) > 0) + s_sEdit[i] = wstrztoA( wsEdit) ; break ; case CTRL_COLOR : { @@ -1854,40 +1710,31 @@ CALLBACK DialogBoxModelessProc( HWND hwndDlg, UINT message, WPARAM wParam, LPARA 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_ML[i] = buf ; + s_sEdit[i] = buf ; } break ; case CTRL_BUTTON : - if ( GetDlgItemText( hwndDlg, IDC_EDIT_ML_1 + i, LPWSTR( wsEdit), 128) > 0) - s_sEdit_ML[i] = wstrztoA( wsEdit) ; + 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]) ; } - // Ogni valore letto viene inserito all'interno della Table creata in precedenza e passata alla CallBack di lua - int nIndex = 1 ; - for ( const string& sVal : s_sEdit_ML) { - lua_pushstring( ctx->L, sVal.c_str()) ; - lua_rawseti( ctx->L, -2, nIndex ++) ; - } - // chiamo la CallBack - lua_pcall( ctx->L, 1, 0, 0) ; - // libero la memoria - luaL_unref( ctx->L, LUA_REGISTRYINDEX, ctx->nCallBackFun) ; - delete ctx ; - ctx = nullptr ; + ctx->bCancelled = false ; + ctx->bDone = true ; } - // rimuovo finestra e annullo il contesto - DestroyWindow( hwndDlg) ; - phDlgModeless = nullptr ; - nDlgModelessItem = -1 ; + // chiudo il dialogo + OnClosingDialog( hwndDlg) ; return TRUE ; } [[fallthrough]] ; - case IDCANCEL_ML : { + case IDCANCEL : { // pulizia brush colori - for ( int i = 0 ; i < MAX_CTRLS_ML ; ++ i) { + for ( int i = 0 ; i < MAX_CTRLS ; ++ i) { if ( hColorBrush[i] != NULL) { DeleteObject( hColorBrush[i]) ; hColorBrush[i] = NULL ; @@ -1895,39 +1742,94 @@ CALLBACK DialogBoxModelessProc( HWND hwndDlg, UINT message, WPARAM wParam, LPARA } // 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->nCallBackFun != LUA_NOREF) { - luaL_unref( ctx->L, LUA_REGISTRYINDEX, ctx->nCallBackFun) ; - delete ctx ; - ctx = nullptr ; + if ( ctx != nullptr) { + ctx->bCancelled = true ; + ctx->bDone = true ; } - // rimuovo finestra e annullo il contesto - DestroyWindow( hwndDlg) ; - phDlgModeless = nullptr ; - nDlgModelessItem = -1 ; + // 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 ; } - 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->nCallBackFun != LUA_NOREF) { - luaL_unref( ctx->L, LUA_REGISTRYINDEX, ctx->nCallBackFun) ; - delete ctx ; - ctx = nullptr ; + if ( ctx != nullptr) { + ctx->bCancelled = true ; + ctx->bDone = true ; } - // rimuovo finestra e annullo il contesto - DestroyWindow( hwndDlg) ; - phDlgModeless = nullptr ; - nDlgModelessItem = -1 ; + // 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) { @@ -1936,7 +1838,7 @@ LuaDialogBox( lua_State* L) s_nCtrls = 0 ; for ( int i = 0 ; i < MAX_CTRLS ; ++ i) { STRVECTOR vData ; - if ( LuaGetParam( L, 2 + i, vData) && vData.size() >= 2) { + if ( LuaGetParam( L, 2 + i, vData) && ssize( vData) >= 2) { s_sText[i] = Trim( vData[0]) ; s_sEdit[i] = Trim( vData[1]) ; ++ s_nCtrls ; @@ -1945,89 +1847,62 @@ LuaDialogBox( lua_State* L) break ; } LuaClearStack( L) ; - // se abilitata UI, lancio dialogo - if ( ExeGetEnableUI()) { - // lancio dialogo - HWND hTopWnd = ExeGetMainWindowHandle() ; - bool bOk = ( DialogBox( GetModuleIstance(), MAKEINTRESOURCE( IDD_LUADLG), hTopWnd, (DLGPROC)DialogBoxProc) == IDOK) ; - // restituzione parametri - if ( bOk) { - STRVECTOR vRes ; - for ( int i = 0 ; i < s_nCtrls ; ++ i) - vRes.emplace_back( s_sEdit[i]) ; - LuaSetParam( L, vRes) ; - } - else { - LuaSetParam( L) ; - } - } - else - LuaSetParam( L) ; - return 1 ; -} -//------------------------------------------------------------------------------- -static int -LuaDialogBoxModeless( lua_State* L) -{ - // 1 .. 9 parametri : sCaption, { sText, sDefault}, ... - LuaCheckParam( L, 1, s_sCaption_ML) - s_nCtrls_ML = 0 ; - for ( int i = 0 ; i < MAX_CTRLS_ML ; ++ i) { - STRVECTOR vData ; - if ( LuaGetParam( L, 2 + i, vData) && ssize( vData) >= 2) { - s_sText_ML[i] = Trim( vData[0]) ; - s_sEdit_ML[i] = Trim( vData[1]) ; - ++ s_nCtrls_ML ; - } - else + // 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 ; - } - // se abilitata UI, lancio dialogo - if ( ExeGetEnableUI()) { - // se dialogo giŕ presente, errore ( per ora una sola finestra non modale per volta) - if ( phDlgModeless != nullptr) { - LuaSetParam( L, false) ; - return 1 ; + if ( ! IsDialogMessage( phDlgModeless, &msg)) { + TranslateMessage( &msg) ; + DispatchMessage( &msg) ; } - // definisco il contesto per il dialogo - DialogContext* ctx = new DialogContext() ; - if ( ctx != nullptr) { - // recupero la funzione di CallBack per restituire i valori presenti nella DialogBoxModeless - // questa funzione deve essere l'ultimo parametro - int nCallBackRef = LUA_NOREF ; - int nLastPar = lua_gettop( L) ; - if ( lua_isfunction( L, nLastPar)) { - lua_pushvalue( L, nLastPar) ; // copio la funzione - ctx->nCallBackFun = luaL_ref( L, LUA_REGISTRYINDEX) ; // salvo nel registro - ctx->L = L ; // salvo lo State Lua - // lancio dialogo - HWND hTopWnd = ExeGetMainWindowHandle() ; - nDlgModelessItem = -1 ; - phDlgModeless = ( CreateDialogParam( GetModuleIstance(), MAKEINTRESOURCE( IDD_LUADLG_ML), hTopWnd, - (DLGPROC)DialogBoxModelessProc, (LPARAM)ctx)) ; - if ( phDlgModeless != nullptr) { - // se dialogo creato, porto la finestra in primo piano - ShowWindow( phDlgModeless, SW_SHOW) ; - SetForegroundWindow( phDlgModeless) ; - } - else { - delete ctx ; - LuaSetParam( L) ; - } - } - else { - delete ctx ; - LuaSetParam( L) ; - } - } - else - LuaSetParam( L) ; } - else - LuaSetParam( L) ; - LuaClearStack( L) ; + // ritorno i valori lua + if ( ctx->bCancelled) + LuaSetParam( L, false) ; + else + LuaSetParam( L, ctx->vsResult) ; + + // libero la memoria + delete ctx ; + ctx = nullptr ; return 1 ; } @@ -2092,6 +1967,5 @@ LuaInstallGeneral( LuaMgr& luaMgr) bOk = bOk && luaMgr.RegisterFunction( "EgtCreateMutex", LuaCreateMutex) ; bOk = bOk && luaMgr.RegisterFunction( "EgtReleaseMutex", LuaReleaseMutex) ; bOk = bOk && luaMgr.RegisterFunction( "EgtDialogBox", LuaDialogBox) ; - bOk = bOk && luaMgr.RegisterFunction( "EgtDialogBoxModeless", LuaDialogBoxModeless) ; return bOk ; } diff --git a/resource.h b/resource.h index e010631..7ff80c5 100644 --- a/resource.h +++ b/resource.h @@ -5,8 +5,6 @@ #define VS_VERSION_INFO 1 #define IDD_LUADLG 101 #define IDD_LUASCENE 102 -#define IDD_LUADLG_ML 103 - #define IDC_TEXT1 1001 #define IDC_TEXT2 1002 #define IDC_TEXT3 1003 @@ -52,63 +50,24 @@ #define IDC_COLOR7 1047 #define IDC_COLOR8 1048 +#define IDC_BUTTON_SEL1 1051 +#define IDC_BUTTON_SEL2 1052 +#define IDC_BUTTON_SEL3 1053 +#define IDC_BUTTON_SEL4 1054 +#define IDC_BUTTON_SEL5 1055 +#define IDC_BUTTON_SEL6 1056 +#define IDC_BUTTON_SEL7 1057 +#define IDC_BUTTON_SEL8 1058 + #define IDC_PICTURE1 1101 -#define IDC_TEXT_ML_1 2001 -#define IDC_TEXT_ML_2 2002 -#define IDC_TEXT_ML_3 2003 -#define IDC_TEXT_ML_4 2004 -#define IDC_TEXT_ML_5 2005 -#define IDC_TEXT_ML_6 2006 -#define IDC_TEXT_ML_7 2007 -#define IDC_TEXT_ML_8 2008 - -#define IDC_EDIT_ML_1 2011 -#define IDC_EDIT_ML_2 2012 -#define IDC_EDIT_ML_3 2013 -#define IDC_EDIT_ML_4 2014 -#define IDC_EDIT_ML_5 2015 -#define IDC_EDIT_ML_6 2016 -#define IDC_EDIT_ML_7 2017 -#define IDC_EDIT_ML_8 2018 - -#define IDC_COMBO_ML_1 2021 -#define IDC_COMBO_ML_2 2022 -#define IDC_COMBO_ML_3 2023 -#define IDC_COMBO_ML_4 2024 -#define IDC_COMBO_ML_5 2025 -#define IDC_COMBO_ML_6 2026 -#define IDC_COMBO_ML_7 2027 -#define IDC_COMBO_ML_8 2028 - -#define IDC_CHECK_ML_1 2031 -#define IDC_CHECK_ML_2 2032 -#define IDC_CHECK_ML_3 2033 -#define IDC_CHECK_ML_4 2034 -#define IDC_CHECK_ML_5 2035 -#define IDC_CHECK_ML_6 2036 -#define IDC_CHECK_ML_7 2037 -#define IDC_CHECK_ML_8 2038 - -#define IDC_BUTTON_SEL_ML_1 2041 -#define IDC_BUTTON_SEL_ML_2 2042 -#define IDC_BUTTON_SEL_ML_3 2043 -#define IDC_BUTTON_SEL_ML_4 2044 -#define IDC_BUTTON_SEL_ML_5 2045 -#define IDC_BUTTON_SEL_ML_6 2046 -#define IDC_BUTTON_SEL_ML_7 2047 -#define IDC_BUTTON_SEL_ML_8 2048 - -#define IDOK_ML 2051 -#define IDCANCEL_ML 2052 - // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 109 #define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1073 +#define _APS_NEXT_CONTROL_VALUE 1074 #define _APS_NEXT_SYMED_VALUE 115 #endif #endif