#include "stdafx.h" #include "Nfo.h" #include "BGM.h" #include "Debug.h" #include "Dialog.h" #include "Generator.h" #include "Nfo.h" #include "resource.h" #include "Starfield.h" #include #define TIMER_SBANIM 0x1 #define PAUSE_TEXT _T("Pause") #define PLAY_TEXT _T("Play") #define WINE_USER_TEXT _T("Hey Wine user! Press F1 for more info.") static LPCTSTR PLACEHOLDER_TEXT = _T("they/them, she/her, he/him, etc."); static LPCTSTR szStatusBarText = _T("Now Playing: Space Debris - Captain"); static BOOL bEditFocused = FALSE; static WNDPROC OldEditWndProc; LPCTSTR szBannedWords[] = { _T("helicopter"), }; static BOOL UserIsRunningWine(void) { HMODULE hNtdll = GetModuleHandle(_T("ntdll.dll")); if (hNtdll) { LPVOID lpWineGetVersion = GetProcAddress(hNtdll, _T("wine_get_version")); return (lpWineGetVersion != NULL); } return FALSE; } static LRESULT CALLBACK EditWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { /* Oho, this one feels *cursed*. * * Here's the general theory: Windows XP provides EM_SETCUEBANNER, * meaning Windows 2000/Me and below don't have placeholder text. * Additionally, if your Windows XP is set to a CJK locale, no * placeholder text for you. * * So, let's work around it by implementing our own placeholder! * What could go wrong? */ switch (uMsg) { case WM_PAINT: // Let the original proc paint as needed CallWindowProc(OldEditWndProc, hWnd, uMsg, wParam, lParam); { HDC hDC = GetDC(hWnd); COLORREF crNormal; TCHAR szInput[8] = {7,0}; // I don't know if it's okay to just call a WndProc like // this, but they won't know, right? LRESULT lResult = CallWindowProc( OldEditWndProc, hWnd, EM_GETLINE, 0, (LPARAM)szInput); if (!lResult && !bEditFocused) { RECT rcArea = {0}; // Get the control font HFONT hFont = (HFONT)CallWindowProc( OldEditWndProc, hWnd, WM_GETFONT, 0, 0), hOldFont; hOldFont = SelectObject(hDC, hFont); // Get the selection rect, so the placeholder text lines up CallWindowProc( OldEditWndProc, hWnd, EM_GETRECT, 0, (LPARAM)&rcArea); // TODO: is GRAYTEXT the correct color? crNormal = SetTextColor(hDC, GetSysColor(COLOR_GRAYTEXT)); DrawText(hDC, PLACEHOLDER_TEXT, (int)_tcslen(PLACEHOLDER_TEXT), &rcArea, DT_VCENTER | DT_SINGLELINE); SelectObject(hDC, hOldFont); SetTextColor(hDC, crNormal); } DeleteDC(hDC); return 0; } break; default: return CallWindowProc(OldEditWndProc, hWnd, uMsg, wParam, lParam); } return 0; } INT_PTR CALLBACK MainDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { static int iParts[2]; static HCURSOR hPointer = NULL; static BgmState bgmState = NULL; static LPTSTR szToggleText = NULL; static RECT rcDialog = {0}; static COLORREF crLink = 0; TCHAR szInput[65] = {0}; static OSVERSIONINFO osver = {sizeof(OSVERSIONINFO),0}; switch (uMsg) { case WM_INITDIALOG: { // At least *try* to support Windows <2000 if (GetVersionEx(&osver)) { if (osver.dwMajorVersion >= 5) { // COLOR_HOTLIGHT is only supported in 2k+ crLink = GetSysColor(26); } else { HWND hStarfield = GetDlgItem( hDlg, IDC_STARFIELD); // Borrowing the link color from HTML5 spec crLink = RGB(0, 0, 0xee); // Win98 also seems grumpy about the amount of GDI // rendering, so slow it down a bit SendMessage(hStarfield, WMU_FRAMERATE, 30, 0); } } } { // Wine doesn't always (ever?) show the [?] button. Give the // user another way to access it. if (UserIsRunningWine()) { szStatusBarText = WINE_USER_TEXT; } } // initialize static vars hPointer = LoadCursor(NULL, MAKEINTRESOURCE(32649)); bgmState = (BgmState)lParam; szToggleText = PAUSE_TEXT; OldEditWndProc = (WNDPROC)SetWindowLong( GetDlgItem(hDlg, IDC_PNTYPE), GWL_WNDPROC, (LONG)EditWndProc); { // Set up status bar parts LONG lDlgWidth = LOWORD(GetDialogBaseUnits()), lRightWidth = (lDlgWidth * 6); GetClientRect(hDlg, &rcDialog); iParts[0] = rcDialog.right - lRightWidth; iParts[1] = -1; SendDlgItemMessage(hDlg, IDC_STATUSBAR, SB_SETPARTS, 2, (LPARAM)iParts); } SendDlgItemMessage(hDlg, IDC_STATUSBAR, SB_SETTEXT, SBT_OWNERDRAW | 0, 0); SendDlgItemMessage(hDlg, IDC_STATUSBAR, SB_SETTEXT, SBT_OWNERDRAW | 1, 0); break; case WM_SYSCOMMAND: if (wParam == SC_CONTEXTHELP) { DialogBox( GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_ABOUT), hDlg, NfoDlgProc); return TRUE; } else { return FALSE; } break; case WM_HELP: DialogBox( GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_ABOUT), hDlg, NfoDlgProc); return TRUE; case WM_DRAWITEM: if (wParam == IDC_STATUSBAR) { LPDRAWITEMSTRUCT lpDraw = (LPDRAWITEMSTRUCT)lParam; HFONT hFont = (HFONT)SendMessage( lpDraw->hwndItem, WM_GETFONT, (WPARAM)0, (LPARAM)0); int iOldBkMode = SetBkMode(lpDraw->hDC, TRANSPARENT); if (lpDraw->itemID == 0) { // Draw the status bar text DrawText( lpDraw->hDC, szStatusBarText, -1, &lpDraw->rcItem, DT_VCENTER | DT_SINGLELINE); } else if (lpDraw->itemID == 1) { // Draw the Play/Pause "link" HFONT hLinkFont, hOldFont; LOGFONT lf; COLORREF crOldColor; GetObject(hFont, sizeof(lf), &lf); lf.lfUnderline = TRUE; hLinkFont = CreateFontIndirect(&lf); hOldFont = SelectObject(lpDraw->hDC, hLinkFont); crOldColor = SetTextColor(lpDraw->hDC, crLink); DrawText(lpDraw->hDC, szToggleText, -1, &lpDraw->rcItem, DT_CENTER | DT_VCENTER | DT_SINGLELINE); // put everything back how we found it SelectObject(lpDraw->hDC, hOldFont); SetTextColor(lpDraw->hDC, crOldColor); DeleteObject(hLinkFont); } SetBkMode(lpDraw->hDC, iOldBkMode); } break; case WM_NOTIFY: if (wParam == IDC_STATUSBAR) { LPNMMOUSE lpnm = (LPNMMOUSE)lParam; if (lpnm->hdr.code == NM_CLICK && lpnm->dwItemSpec == 1) { // Play/Pause "link" switch (TogglePlayPause(bgmState)) { case 0: szToggleText = PAUSE_TEXT; break; case 1: szToggleText = PLAY_TEXT; break; } SendDlgItemMessage(hDlg, IDC_STATUSBAR, SB_SETTEXT, SBT_OWNERDRAW | 1, 0); // Make the border dynamic, like the original iParts[0] = (rcDialog.right - rcDialog.left) - (LOWORD(GetDialogBaseUnits()) * (int)_tcslen(szToggleText)); SendDlgItemMessage(hDlg, IDC_STATUSBAR, SB_SETPARTS, 2, (LPARAM)iParts); } } break; case WM_SETCURSOR: if ((HWND)wParam == GetDlgItem(hDlg, IDC_STATUSBAR)) { // Make the Play/Pause link act like a link POINT ptCur; GetCursorPos(&ptCur); if (ScreenToClient(hDlg, &ptCur) && ptCur.x >= iParts[0]) { SetCursor(hPointer); SetWindowLong(hDlg, DWL_MSGRESULT, TRUE); return TRUE; } } break; case WM_COMMAND: if (LOWORD(wParam) == IDOK) { // Generate button pressed LRESULT lResult; TCHAR szKeyOut[19] = {0}; szInput[0] = 64; lResult = SendDlgItemMessage( hDlg, IDC_PNTYPE, EM_GETLINE, 0, (LPARAM)szInput); if (!lResult) break; if (GenerateKey(szInput, szKeyOut)) { SendDlgItemMessage(hDlg, IDC_KEYDATA, WM_SETTEXT, 0, (LPARAM)szKeyOut); } } else if (LOWORD(wParam) == IDC_PNTYPE) { // Pro Nouns edition edit control if (HIWORD(wParam) == EN_UPDATE) { int i; BOOL bEnable = TRUE; LRESULT lResult; szInput[0] = 64; lResult = SendDlgItemMessage( hDlg, IDC_PNTYPE, EM_GETLINE, 0, (LPARAM)szInput); if (!lResult) { bEnable = FALSE; } else { // Handle word validation for (i = 0; i < (sizeof(szBannedWords) / sizeof(szBannedWords[0])); i++) { int j, x = 0, iWordLen = (int)_tcslen(szBannedWords[i]); for (j = 0; j < (int)_tcslen(szInput); j++) { if (iswalpha(szInput[j]) && (towlower(szInput[j]) == szBannedWords[i][x])) { if (++x >= iWordLen) { bEnable = FALSE; break; } } } } } EnableWindow(GetDlgItem(hDlg, IDOK), bEnable); } else if (HIWORD(wParam) == EN_SETFOCUS) { // edit control focused, don't show the placeholder bEditFocused = TRUE; } else if (HIWORD(wParam) == EN_KILLFOCUS) { bEditFocused = FALSE; } } break; case WM_CLOSE: EndDialog(hDlg, 0); break; default: return FALSE; } return TRUE; }