391 lines
8.8 KiB
C
391 lines
8.8 KiB
C
|
#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 <shlwapi.h>
|
||
|
|
||
|
|
||
|
#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;
|
||
|
}
|