/* This file is part of BKBTL. BKBTL is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. BKBTL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with BKBTL. If not, see . */ // Dialogs.cpp #include "stdafx.h" #include #include #include #include "Dialogs.h" #include "Emulator.h" #include "Main.h" #include "Views.h" ////////////////////////////////////////////////////////////////////// INT_PTR CALLBACK AboutBoxProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); INT_PTR CALLBACK CommandLineHelpBoxProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); INT_PTR CALLBACK InputBoxProc(HWND, UINT, WPARAM, LPARAM); INT_PTR CALLBACK LoadBinProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); void Dialogs_DoLoadBinPrepare(HWND hDlg, LPCTSTR strFileName); void Dialogs_DoLoadBinLoad(LPCTSTR strFileName); BOOL InputBoxValidate(HWND hDlg); INT_PTR CALLBACK SettingsProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); INT_PTR CALLBACK SettingsColorsProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); LPCTSTR m_strInputBoxTitle = NULL; WORD* m_pInputBoxValueOctal = NULL; // Show the standard Choose Color dialog box BOOL ShowColorDialog(COLORREF& color); COLORREF m_DialogSettings_acrCustClr[16]; // array of custom colors to use in ChooseColor() COLORREF m_DialogSettings_OsdLineColor = RGB(120, 0, 0); ////////////////////////////////////////////////////////////////////// // About Box void ShowAboutBox() { DialogBox(g_hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), g_hwnd, AboutBoxProc); } INT_PTR CALLBACK AboutBoxProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { UNREFERENCED_PARAMETER(lParam); switch (message) { case WM_INITDIALOG: { const size_t buffersize = 64; TCHAR buffer[buffersize]; _sntprintf(buffer, buffersize - 1, _T("BKBTL version %s revision %d"), _T(APP_VERSION_STRING), APP_REVISION); ::SetDlgItemText(hDlg, IDC_VERSION, buffer); _sntprintf(buffer, buffersize - 1, _T("Build date: %S %S"), __DATE__, __TIME__); ::SetDlgItemText(hDlg, IDC_BUILDDATE, buffer); return (INT_PTR)TRUE; } case WM_COMMAND: if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) { EndDialog(hDlg, LOWORD(wParam)); return (INT_PTR)TRUE; } break; case WM_NOTIFY: if (wParam == IDC_SYSLINK1 && ((LPNMHDR)lParam)->code == NM_CLICK || ((LPNMHDR)lParam)->code == NM_RETURN) { ::ShellExecute(NULL, _T("open"), _T("https://github.com/nzeemin/bkbtl"), NULL, NULL, SW_SHOW); break; } break; } return (INT_PTR)FALSE; } ////////////////////////////////////////////////////////////////////// // Command Line Help Box void ShowCommandLineHelpBox() { DialogBox(g_hInst, MAKEINTRESOURCE(IDD_COMMANDLINEHELP), g_hwnd, CommandLineHelpBoxProc); } INT_PTR CALLBACK CommandLineHelpBoxProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { UNREFERENCED_PARAMETER(lParam); switch (message) { case WM_INITDIALOG: { HWND hwndText = ::GetDlgItem(hDlg, IDC_EDIT1); HFONT hfont = CreateMonospacedFont(); SendMessage(hwndText, WM_SETFONT, (WPARAM)hfont, 0); ::SetDlgItemText(hDlg, IDC_EDIT1, g_CommandLineHelp); return (INT_PTR)TRUE; } case WM_COMMAND: if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) { EndDialog(hDlg, LOWORD(wParam)); return (INT_PTR)TRUE; } break; } return (INT_PTR)FALSE; } ////////////////////////////////////////////////////////////////////// BOOL InputBoxOctal(HWND hwndOwner, LPCTSTR strTitle, WORD* pValue) { m_strInputBoxTitle = strTitle; m_pInputBoxValueOctal = pValue; INT_PTR result = DialogBox(g_hInst, MAKEINTRESOURCE(IDD_INPUTBOX), hwndOwner, InputBoxProc); if (result != IDOK) return FALSE; return TRUE; } INT_PTR CALLBACK InputBoxProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM /*lParam*/) { switch (message) { case WM_INITDIALOG: { SetWindowText(hDlg, m_strInputBoxTitle); HWND hEdit = GetDlgItem(hDlg, IDC_EDIT1); TCHAR buffer[8]; _sntprintf(buffer, sizeof(buffer) / sizeof(TCHAR) - 1, _T("%06ho"), *m_pInputBoxValueOctal); SetWindowText(hEdit, buffer); SendMessage(hEdit, EM_SETSEL, 0, -1); SetFocus(hEdit); return (INT_PTR)FALSE; } case WM_COMMAND: switch (LOWORD(wParam)) { case IDC_EDIT1: { const size_t buffersize = 8; TCHAR buffer[buffersize]; GetDlgItemText(hDlg, IDC_EDIT1, buffer, buffersize); if (_sntscanf_s(buffer, buffersize, _T("%ho"), m_pInputBoxValueOctal) > 0) { GetDlgItemText(hDlg, IDC_EDIT2, buffer, buffersize); WORD otherValue; if (_sntscanf_s(buffer, buffersize, _T("%hx"), &otherValue) <= 0 || *m_pInputBoxValueOctal != otherValue) { _sntprintf(buffer, buffersize - 1, _T("%04hx"), *m_pInputBoxValueOctal); SetDlgItemText(hDlg, IDC_EDIT2, buffer); } } } return (INT_PTR)TRUE; case IDC_EDIT2: { const size_t buffersize = 8; TCHAR buffer[buffersize]; GetDlgItemText(hDlg, IDC_EDIT2, buffer, buffersize); if (_sntscanf_s(buffer, buffersize, _T("%hx"), m_pInputBoxValueOctal) > 0) { GetDlgItemText(hDlg, IDC_EDIT1, buffer, buffersize); WORD otherValue; if (_sntscanf_s(buffer, buffersize, _T("%ho"), &otherValue) <= 0 || *m_pInputBoxValueOctal != otherValue) { _sntprintf(buffer, buffersize - 1, _T("%06ho"), *m_pInputBoxValueOctal); SetDlgItemText(hDlg, IDC_EDIT1, buffer); } } } return (INT_PTR)TRUE; case IDOK: if (! InputBoxValidate(hDlg)) return (INT_PTR)FALSE; EndDialog(hDlg, LOWORD(wParam)); return (INT_PTR)TRUE; case IDCANCEL: EndDialog(hDlg, LOWORD(wParam)); return (INT_PTR)TRUE; default: return (INT_PTR)FALSE; } break; } return (INT_PTR)FALSE; } BOOL InputBoxValidate(HWND hDlg) { HWND hEdit = GetDlgItem(hDlg, IDC_EDIT1); TCHAR buffer[8]; GetWindowText(hEdit, buffer, 8); WORD value; if (! ParseOctalValue(buffer, &value)) { MessageBox(NULL, _T("Please enter correct octal value."), _T("Input Box Validation"), MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL); return FALSE; } *m_pInputBoxValueOctal = value; return TRUE; } ////////////////////////////////////////////////////////////////////// BOOL ShowSaveDialog(HWND hwndOwner, LPCTSTR strTitle, LPCTSTR strFilter, LPCTSTR strDefExt, TCHAR* bufFileName) { *bufFileName = 0; OPENFILENAME ofn; ZeroMemory(&ofn, sizeof(ofn)); ofn.lStructSize = sizeof(ofn); ofn.hwndOwner = hwndOwner; ofn.hInstance = g_hInst; ofn.lpstrTitle = strTitle; ofn.lpstrFilter = strFilter; ofn.lpstrDefExt = strDefExt; ofn.Flags = OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT | OFN_NOCHANGEDIR; ofn.lpstrFile = bufFileName; ofn.nMaxFile = MAX_PATH; BOOL okResult = GetSaveFileName(&ofn); return okResult; } BOOL ShowOpenDialog(HWND hwndOwner, LPCTSTR strTitle, LPCTSTR strFilter, TCHAR* bufFileName) { *bufFileName = 0; OPENFILENAME ofn; ZeroMemory(&ofn, sizeof(ofn)); ofn.lStructSize = sizeof(ofn); ofn.hwndOwner = hwndOwner; ofn.hInstance = g_hInst; ofn.lpstrTitle = strTitle; ofn.lpstrFilter = strFilter; ofn.Flags = OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR; ofn.lpstrFile = bufFileName; ofn.nMaxFile = MAX_PATH; BOOL okResult = GetOpenFileName(&ofn); return okResult; } ////////////////////////////////////////////////////////////////////// // Create Disk Dialog void ShowLoadBinDialog() { DialogBox(g_hInst, MAKEINTRESOURCE(IDD_LOADBIN), g_hwnd, LoadBinProc); } INT_PTR CALLBACK LoadBinProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM /*lParam*/) { switch (message) { case WM_INITDIALOG: { ::PostMessage(hDlg, WM_COMMAND, IDC_BUTTONBROWSE, 0); return (INT_PTR)FALSE; } case WM_COMMAND: switch (LOWORD(wParam)) { case IDC_BUTTONBROWSE: { TCHAR bufFileName[MAX_PATH]; BOOL okResult = ShowOpenDialog(g_hwnd, _T("Select BIN file to load"), _T("BK binary files (*.bin)\0*.bin\0All Files (*.*)\0*.*\0\0"), bufFileName); if (! okResult) break; Dialogs_DoLoadBinPrepare(hDlg, bufFileName); } break; case IDOK: { TCHAR bufFileName[MAX_PATH]; ::GetDlgItemText(hDlg, IDC_EDITFILE, bufFileName, sizeof(bufFileName) / sizeof(TCHAR)); Dialogs_DoLoadBinLoad(bufFileName); } EndDialog(hDlg, LOWORD(wParam)); return (INT_PTR)TRUE; case IDCANCEL: EndDialog(hDlg, LOWORD(wParam)); return (INT_PTR)TRUE; default: return (INT_PTR)FALSE; } break; } return (INT_PTR) FALSE; } void Dialogs_DoLoadBinPrepare(HWND hDlg, LPCTSTR strFileName) { ::SetDlgItemText(hDlg, IDC_EDITFILE, NULL); // Open file for reading HANDLE hFile = ::CreateFile(strFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) { AlertWarning(_T("Failed to load binary file.")); return; } // Load BIN header BYTE bufHeader[20]; DWORD bytesRead; ::ReadFile(hFile, bufHeader, 4, &bytesRead, NULL); if (bytesRead != 4) { ::CloseHandle(hFile); AlertWarning(_T("Failed to load binary file.")); return; } WORD baseAddress = *((WORD*)bufHeader); WORD dataSize = *(((WORD*)bufHeader) + 1); //TCHAR bufName[17]; //::MultiByteToWideChar(CP_ACP, 0, (LPCSTR)(bufHeader + 4), 16, bufName, 17); //bufName[16] = 0; // Set controls text TCHAR bufValue[8]; ::SetDlgItemText(hDlg, IDC_EDITFILE, strFileName); PrintOctalValue(bufValue, baseAddress); ::SetDlgItemText(hDlg, IDC_EDITADDR, bufValue); PrintOctalValue(bufValue, dataSize); ::SetDlgItemText(hDlg, IDC_EDITSIZE, bufValue); //::SetDlgItemText(hDlg, IDC_EDITNAME, bufName); ::CloseHandle(hFile); } void Dialogs_DoLoadBinLoad(LPCTSTR strFileName) { // Open file for reading HANDLE hFile = ::CreateFile(strFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) { AlertWarning(_T("Failed to load binary file.")); return; } // Load BIN header BYTE bufHeader[20]; DWORD bytesRead; ::ReadFile(hFile, bufHeader, 4, &bytesRead, NULL); if (bytesRead != 4) { ::CloseHandle(hFile); AlertWarning(_T("Failed to load binary file.")); return; } WORD baseAddress = *((WORD*)bufHeader); WORD dataSize = *(((WORD*)bufHeader) + 1); // Get file size DWORD bytesToRead = dataSize; WORD memoryBytes = (dataSize + 1) & 0xfffe; // Allocate memory BYTE* pBuffer = (BYTE*)::LocalAlloc(LPTR, memoryBytes); // Load file data ::ReadFile(hFile, pBuffer, dataSize, &bytesRead, NULL); if (bytesRead != bytesToRead) { ::LocalFree(pBuffer); ::CloseHandle(hFile); AlertWarning(_T("Failed to load binary file.")); return; } // Copy data to BK memory WORD address = baseAddress; WORD* pData = (WORD*)pBuffer; while (address < baseAddress + memoryBytes) { WORD value = *pData++; g_pBoard->SetRAMWord(address, value); address += 2; } ::LocalFree(pBuffer); ::CloseHandle(hFile); ScreenView_KeyEvent(0123, TRUE); ScreenView_KeyEvent(0123, FALSE); if (baseAddress == 01000) { ScreenView_KeyEvent(061, TRUE); ScreenView_KeyEvent(061, FALSE); ScreenView_KeyEvent(060, TRUE); ScreenView_KeyEvent(060, FALSE); ScreenView_KeyEvent(060, TRUE); ScreenView_KeyEvent(060, FALSE); ScreenView_KeyEvent(060, TRUE); ScreenView_KeyEvent(060, FALSE); } } ////////////////////////////////////////////////////////////////////// // Color Dialog BOOL ShowColorDialog(COLORREF& color, HWND hWndOwner) { CHOOSECOLOR cc; memset(&cc, 0, sizeof(cc)); cc.lStructSize = sizeof(cc); cc.hwndOwner = hWndOwner; cc.lpCustColors = (LPDWORD)m_DialogSettings_acrCustClr; cc.rgbResult = color; cc.Flags = CC_FULLOPEN | CC_RGBINIT; if (!::ChooseColor(&cc)) return FALSE; color = cc.rgbResult; return TRUE; } ////////////////////////////////////////////////////////////////////// // Settings Dialog void ShowSettingsDialog() { DialogBox(g_hInst, MAKEINTRESOURCE(IDD_SETTINGS), g_hwnd, SettingsProc); } INT_PTR CALLBACK SettingsProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM /*lParam*/) { switch (message) { case WM_INITDIALOG: { HWND hVolume = GetDlgItem(hDlg, IDC_VOLUME); SendMessage(hVolume, TBM_SETRANGEMIN, 0, (LPARAM)0); SendMessage(hVolume, TBM_SETRANGEMAX, 0, (LPARAM)0xffff); SendMessage(hVolume, TBM_SETTICFREQ, 0x1000, 0); SendMessage(hVolume, TBM_SETPOS, TRUE, (LPARAM)Settings_GetSoundVolume()); return (INT_PTR)FALSE; } case WM_COMMAND: switch (LOWORD(wParam)) { case IDOK: { HWND hVolume = GetDlgItem(hDlg, IDC_VOLUME); DWORD volume = SendMessage(hVolume, TBM_GETPOS, 0, 0); Settings_SetSoundVolume((WORD)volume); } EndDialog(hDlg, LOWORD(wParam)); return (INT_PTR)TRUE; case IDCANCEL: EndDialog(hDlg, LOWORD(wParam)); return (INT_PTR)TRUE; default: return (INT_PTR)FALSE; } break; } return (INT_PTR) FALSE; } ////////////////////////////////////////////////////////////////////// // Settings Colors Dialog BOOL ShowSettingsColorsDialog() { return IDOK == DialogBox(g_hInst, MAKEINTRESOURCE(IDD_SETTINGS_COLORS), g_hwnd, SettingsColorsProc); } int CALLBACK SettingsDialog_EnumFontProc(const LOGFONT* lpelfe, const TEXTMETRIC* /*lpntme*/, DWORD /*FontType*/, LPARAM lParam) { if ((lpelfe->lfPitchAndFamily & FIXED_PITCH) == 0) return TRUE; if (lpelfe->lfFaceName[0] == _T('@')) // Skip vertical fonts return TRUE; HWND hCombo = (HWND)lParam; int item = ::SendMessage(hCombo, CB_FINDSTRING, 0, (LPARAM)lpelfe->lfFaceName); if (item < 0) ::SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM)lpelfe->lfFaceName); return TRUE; } void SettingsDialog_FillDebugFontCombo(HWND hCombo) { LOGFONT logfont; ZeroMemory(&logfont, sizeof logfont); logfont.lfCharSet = DEFAULT_CHARSET; logfont.lfWeight = FW_NORMAL; logfont.lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE; HDC hdc = GetDC(NULL); EnumFontFamiliesEx(hdc, &logfont, (FONTENUMPROC)SettingsDialog_EnumFontProc, (LPARAM)hCombo, 0); VERIFY(::ReleaseDC(NULL, hdc)); Settings_GetDebugFontName(logfont.lfFaceName); ::SendMessage(hCombo, CB_SELECTSTRING, 0, (LPARAM)logfont.lfFaceName); } void SettingsDialog_FillColorsList(HWND hList) { for (int itemIndex = 0; itemIndex < ColorIndicesCount; itemIndex++) { LPCTSTR colorName = Settings_GetColorFriendlyName((ColorIndices)itemIndex); ::SendMessage(hList, LB_ADDSTRING, 0, (LPARAM)colorName); ::SendMessage(hList, LB_SETITEMDATA, itemIndex, (LPARAM)Settings_GetColor((ColorIndices)itemIndex)); } ::SendMessage(hList, LB_SETCURSEL, 0, 0); } void SettingsDialog_InitColorDialog(HWND hDlg) { HWND hDebugFont = GetDlgItem(hDlg, IDC_DEBUGFONT); SettingsDialog_FillDebugFontCombo(hDebugFont); HWND hColorList = GetDlgItem(hDlg, IDC_LIST1); SettingsDialog_FillColorsList(hColorList); } void SettingsDialog_OnColorListDrawItem(PDRAWITEMSTRUCT lpDrawItem) { if (lpDrawItem->itemID == -1) return; HDC hdc = lpDrawItem->hDC; switch (lpDrawItem->itemAction) { case ODA_DRAWENTIRE: case ODA_SELECT: { HBRUSH hBrushBk = ::GetSysColorBrush((lpDrawItem->itemState & ODS_SELECTED) ? COLOR_HIGHLIGHT : COLOR_WINDOW); ::FillRect(hdc, &lpDrawItem->rcItem, hBrushBk); int colorIndex = lpDrawItem->itemID; COLORREF color = (COLORREF)(lpDrawItem->itemData); HBRUSH hBrush = ::CreateSolidBrush(color); RECT rcFill; ::CopyRect(&rcFill, &lpDrawItem->rcItem); ::InflateRect(&rcFill, -1, -1); rcFill.left = rcFill.right - 50; ::FillRect(hdc, &rcFill, hBrush); ::SetTextColor(hdc, ::GetSysColor((lpDrawItem->itemState & ODS_SELECTED) ? COLOR_HIGHLIGHTTEXT : COLOR_WINDOWTEXT)); RECT rcText; ::CopyRect(&rcText, &lpDrawItem->rcItem); ::InflateRect(&rcText, -2, 0); LPCTSTR colorName = Settings_GetColorFriendlyName((ColorIndices)colorIndex); ::DrawText(hdc, colorName, _tcslen(colorName), &rcText, DT_LEFT | DT_NOPREFIX); } break; case ODA_FOCUS: break; } } void SettingsDialog_OnChooseColor(HWND hDlg) { HWND hList = GetDlgItem(hDlg, IDC_LIST1); int itemIndex = ::SendMessage(hList, LB_GETCURSEL, 0, 0); COLORREF color = ::SendMessage(hList, LB_GETITEMDATA, itemIndex, 0); if (ShowColorDialog(color, hDlg)) { ::SendMessage(hList, LB_SETITEMDATA, itemIndex, (LPARAM)color); ::InvalidateRect(hList, NULL, TRUE); } } void SettingsDialog_OnResetColor(HWND hDlg) { HWND hList = GetDlgItem(hDlg, IDC_LIST1); int itemIndex = ::SendMessage(hList, LB_GETCURSEL, 0, 0); COLORREF color = Settings_GetDefaultColor((ColorIndices)itemIndex); ::SendMessage(hList, LB_SETITEMDATA, itemIndex, color); ::InvalidateRect(hList, NULL, TRUE); } void SettingsDialog_SaveFontsAndColors(HWND hDlg) { TCHAR buffer[32]; GetDlgItemText(hDlg, IDC_DEBUGFONT, buffer, 32); Settings_SetDebugFontName(buffer); HWND hList = GetDlgItem(hDlg, IDC_LIST1); for (int itemIndex = 0; itemIndex < ColorIndicesCount; itemIndex++) { COLORREF color = ::SendMessage(hList, LB_GETITEMDATA, itemIndex, 0); Settings_SetColor((ColorIndices)itemIndex, color); } } INT_PTR CALLBACK SettingsColorsProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_INITDIALOG: SettingsDialog_InitColorDialog(hDlg); return (INT_PTR)FALSE; case WM_COMMAND: switch (LOWORD(wParam)) { case IDC_BUTTON1: SettingsDialog_OnChooseColor(hDlg); break; case IDC_BUTTON2: SettingsDialog_OnResetColor(hDlg); break; case IDOK: SettingsDialog_SaveFontsAndColors(hDlg); EndDialog(hDlg, LOWORD(wParam)); return (INT_PTR)TRUE; case IDCANCEL: EndDialog(hDlg, LOWORD(wParam)); return (INT_PTR)TRUE; default: return (INT_PTR)FALSE; } break; case WM_CTLCOLORLISTBOX: return (LRESULT)CreateSolidBrush(GetSysColor(COLOR_WINDOW)); case WM_DRAWITEM: SettingsDialog_OnColorListDrawItem((PDRAWITEMSTRUCT)lParam); break; } return (INT_PTR)FALSE; } //////////////////////////////////////////////////////////////////////