nuclear@0: /************************************************************************************ nuclear@0: nuclear@0: Filename : Util_SystemGUI.cpp nuclear@0: Content : OS GUI access, usually for diagnostics. nuclear@0: Created : October 20, 2014 nuclear@0: Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. nuclear@0: nuclear@0: Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License"); nuclear@0: you may not use the Oculus VR Rift SDK except in compliance with the License, nuclear@0: which is provided at the time of installation or download, or which nuclear@0: otherwise accompanies this software in either electronic or hard copy form. nuclear@0: nuclear@0: You may obtain a copy of the License at nuclear@0: nuclear@0: http://www.oculusvr.com/licenses/LICENSE-3.2 nuclear@0: nuclear@0: Unless required by applicable law or agreed to in writing, the Oculus VR SDK nuclear@0: distributed under the License is distributed on an "AS IS" BASIS, nuclear@0: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. nuclear@0: See the License for the specific language governing permissions and nuclear@0: limitations under the License. nuclear@0: nuclear@0: *************************************************************************************/ nuclear@0: nuclear@0: #include "Util_SystemGUI.h" nuclear@0: #include "../Kernel/OVR_UTF8Util.h" nuclear@0: #include nuclear@0: nuclear@0: #if defined(OVR_OS_MS) nuclear@0: #include nuclear@0: #endif nuclear@0: nuclear@0: nuclear@0: namespace OVR { namespace Util { nuclear@0: nuclear@0: nuclear@0: #if defined(OVR_OS_MS) nuclear@0: nuclear@0: // On Windows we implement a manual dialog message box. The reason for this is that there's no way to nuclear@0: // have a message box like this without either using MFC or WinForms or relying on Windows Vista+. nuclear@0: nuclear@0: bool DisplayMessageBox(const char* pTitle, const char* pText) nuclear@0: { nuclear@0: #define ID_EDIT 100 nuclear@0: nuclear@0: struct Dialog nuclear@0: { nuclear@0: static size_t LineCount(const char* pText) nuclear@0: { nuclear@0: size_t count = 0; nuclear@0: while(*pText) nuclear@0: { nuclear@0: if(*pText++ == '\n') nuclear@0: count++; nuclear@0: } nuclear@0: return count; nuclear@0: } nuclear@0: nuclear@0: static WORD* WordUp(WORD* pIn){ return (WORD*)((((uintptr_t)pIn + 3) >> 2) << 2); } nuclear@0: nuclear@0: static BOOL CALLBACK Proc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam) nuclear@0: { nuclear@0: switch (iMsg) nuclear@0: { nuclear@0: case WM_INITDIALOG: nuclear@0: { nuclear@0: HWND hWndEdit = GetDlgItem(hDlg, ID_EDIT); nuclear@0: nuclear@0: const char* pText = (const char*)lParam; nuclear@0: SetWindowTextA(hWndEdit, pText); nuclear@0: nuclear@0: HFONT hFont = CreateFontW(-11, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, L"Courier New"); nuclear@0: if(hFont) nuclear@0: SendMessage(hWndEdit, WM_SETFONT, WPARAM(hFont), TRUE); nuclear@0: nuclear@0: SendMessage(hWndEdit, EM_SETSEL, (WPARAM)0, (LPARAM)0); nuclear@0: nuclear@0: return TRUE; nuclear@0: } nuclear@0: nuclear@0: case WM_COMMAND: nuclear@0: switch (LOWORD(wParam)) nuclear@0: { nuclear@0: case ID_EDIT: nuclear@0: { nuclear@0: // Handle messages from the edit control here. nuclear@0: HWND hWndEdit = GetDlgItem(hDlg, ID_EDIT); nuclear@0: SendMessage(hWndEdit, EM_SETSEL, (WPARAM)0, (LPARAM)0); nuclear@0: return TRUE; nuclear@0: } nuclear@0: nuclear@0: case IDOK: nuclear@0: EndDialog(hDlg, 0); nuclear@0: return TRUE; nuclear@0: } nuclear@0: break; nuclear@0: } nuclear@0: nuclear@0: return FALSE; nuclear@0: } nuclear@0: }; nuclear@0: nuclear@0: nuclear@0: char dialogTemplateMemory[1024]; nuclear@0: memset(dialogTemplateMemory, 0, sizeof(dialogTemplateMemory)); nuclear@0: DLGTEMPLATE* pDlg = (LPDLGTEMPLATE)dialogTemplateMemory; nuclear@0: nuclear@0: const size_t textLineCount = Dialog::LineCount(pText); nuclear@0: nuclear@0: // Sizes are in Windows dialog units, which are relative to a character size. Depends on the font and environment settings. Often the pixel size will be ~3x the dialog unit x size. Often the pixel size will be ~3x the dialog unit y size. nuclear@0: const int kGutterSize = 6; // Empty border space around controls within the dialog nuclear@0: const int kButtonWidth = 24; nuclear@0: const int kButtonHeight = 10; nuclear@0: const int kDialogWidth = 600; // To do: Clip this against screen bounds. nuclear@0: const int kDialogHeight = ((textLineCount > 100) ? 400 : ((textLineCount > 25) ? 300 : 200)); nuclear@0: nuclear@0: // Define a dialog box. nuclear@0: pDlg->style = WS_POPUP | WS_BORDER | WS_SYSMENU | DS_MODALFRAME | WS_CAPTION; nuclear@0: pDlg->cdit = 2; // Control count nuclear@0: pDlg->x = 10; // X position To do: Center the dialog. nuclear@0: pDlg->y = 10; nuclear@0: pDlg->cx = (short)kDialogWidth; nuclear@0: pDlg->cy = (short)kDialogHeight; nuclear@0: WORD* pWord = (WORD*)(pDlg + 1); nuclear@0: *pWord++ = 0; // No menu nuclear@0: *pWord++ = 0; // Default dialog box class nuclear@0: nuclear@0: WCHAR* pWchar = (WCHAR*)pWord; nuclear@0: const size_t titleLength = strlen(pTitle); nuclear@0: size_t wcharCount = OVR::UTF8Util::DecodeString(pWchar, pTitle, (titleLength > 128) ? 128 : titleLength); nuclear@0: pWord += wcharCount + 1; nuclear@0: nuclear@0: // Define an OK button. nuclear@0: pWord = Dialog::WordUp(pWord); nuclear@0: nuclear@0: DLGITEMTEMPLATE* pDlgItem = (DLGITEMTEMPLATE*)pWord; nuclear@0: pDlgItem->x = pDlg->cx - (kGutterSize + kButtonWidth); nuclear@0: pDlgItem->y = pDlg->cy - (kGutterSize + kButtonHeight); nuclear@0: pDlgItem->cx = kButtonWidth; nuclear@0: pDlgItem->cy = kButtonHeight; nuclear@0: pDlgItem->id = IDOK; nuclear@0: pDlgItem->style = WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON; nuclear@0: nuclear@0: pWord = (WORD*)(pDlgItem + 1); nuclear@0: *pWord++ = 0xFFFF; nuclear@0: *pWord++ = 0x0080; // button class nuclear@0: nuclear@0: pWchar = (WCHAR*)pWord; nuclear@0: pWchar[0] = 'O'; pWchar[1] = 'K'; pWchar[2] = '\0'; // Not currently localized. nuclear@0: pWord += 3; // OK\0 nuclear@0: *pWord++ = 0; // no creation data nuclear@0: nuclear@0: // Define an EDIT contol. nuclear@0: pWord = Dialog::WordUp(pWord); nuclear@0: nuclear@0: pDlgItem = (DLGITEMTEMPLATE*)pWord; nuclear@0: pDlgItem->x = kGutterSize; nuclear@0: pDlgItem->y = kGutterSize; nuclear@0: pDlgItem->cx = pDlg->cx - (kGutterSize + kGutterSize); nuclear@0: pDlgItem->cy = pDlg->cy - (kGutterSize + kButtonHeight + kGutterSize + (kGutterSize / 2)); nuclear@0: pDlgItem->id = ID_EDIT; nuclear@0: pDlgItem->style = ES_LEFT | ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN | ES_READONLY | WS_VSCROLL | WS_BORDER | WS_TABSTOP | WS_CHILD | WS_VISIBLE; nuclear@0: nuclear@0: pWord = (WORD*)(pDlgItem + 1); nuclear@0: *pWord++ = 0xFFFF; nuclear@0: *pWord++ = 0x0081; // edit class atom nuclear@0: *pWord++ = 0; // no creation data nuclear@0: nuclear@0: LRESULT ret = DialogBoxIndirectParam(NULL, (LPDLGTEMPLATE)pDlg, NULL, (DLGPROC)Dialog::Proc, (LPARAM)pText); nuclear@0: nuclear@0: return (ret != 0); nuclear@0: } nuclear@0: #elif defined(OVR_OS_MAC) nuclear@0: // For Apple we use the Objective C implementation in Util_GUI.mm nuclear@0: #else nuclear@0: // To do. nuclear@0: bool DisplayMessageBox(const char* pTitle, const char* pText) nuclear@0: { nuclear@0: printf("\n\nMessageBox\n%s\n", pTitle); nuclear@0: printf("%s\n\n", pText); nuclear@0: return false; nuclear@0: } nuclear@0: #endif nuclear@0: nuclear@0: nuclear@0: } } // namespace OVR::Util nuclear@0: nuclear@0: nuclear@0: nuclear@0: