mirror of
https://github.com/Heretek-AI/GDevelop.git
synced 2026-07-23 18:45:48 -04:00
453 lines
12 KiB
C++
453 lines
12 KiB
C++
/**
|
|
|
|
GDevelop - Common Dialogs Extension
|
|
Copyright (c) 2008-2015 Florian Rival (Florian.Rival@gmail.com)
|
|
This project is released under the MIT License.
|
|
*/
|
|
|
|
#include <vector>
|
|
#include <string>
|
|
#include <iostream>
|
|
#include <sstream>
|
|
#include <vector>
|
|
#include <algorithm>
|
|
|
|
#include "GDCpp/Object.h"
|
|
#include "GDCpp/RuntimeScene.h"
|
|
#include "GDCpp/Variable.h"
|
|
#include "GDCpp/Utf8Tools.h"
|
|
|
|
//Windows build uses native windows-dialogs
|
|
#if defined(WINDOWS)
|
|
#include <windows.h>
|
|
#include <Commdlg.h>
|
|
#include <unistd.h>
|
|
#endif
|
|
|
|
//Linux build uses dlib for dialogs
|
|
#if defined(LINUX) || defined(MAC)
|
|
#include "nwidgets/MessageBox.h"
|
|
#include "nwidgets/YesNoMsgBox.h"
|
|
#include "nwidgets/OpenFile.h"
|
|
#include "nwidgets/TextInput.h"
|
|
#endif
|
|
|
|
using namespace std;
|
|
|
|
namespace GDpriv
|
|
{
|
|
namespace CommonDialogs
|
|
{
|
|
|
|
/**
|
|
* Display a simple message box.
|
|
*/
|
|
void GD_EXTENSION_API ShowMessageBox( RuntimeScene & scene, const std::string & message, const std::string & title )
|
|
{
|
|
sf::Clock timeSpent;
|
|
|
|
//Display the box
|
|
#if defined(WINDOWS)
|
|
MessageBoxW(NULL, gd::utf8::ToWString(message).c_str(), gd::utf8::ToWString(title).c_str(), MB_ICONINFORMATION);
|
|
#endif
|
|
#if defined(LINUX) || defined(MAC)
|
|
nw::MsgBox msgBox(gd::utf8::ToLocaleString(title), gd::utf8::ToLocaleString(message));
|
|
msgBox.wait_until_closed();
|
|
#endif
|
|
|
|
scene.NotifyPauseWasMade(timeSpent.getElapsedTime().asMicroseconds());//Don't take the time spent in this function in account.
|
|
}
|
|
|
|
/**
|
|
* Display an "open file" dialog
|
|
*/
|
|
void GD_EXTENSION_API ShowOpenFile( RuntimeScene & scene, gd::Variable & variable, const std::string & title, std::string filters )
|
|
{
|
|
sf::Clock timeSpent;
|
|
|
|
string result;
|
|
|
|
//Display the dialog
|
|
#if defined(WINDOWS)
|
|
//Process filters to match windows dialogs filters style.
|
|
filters = filters+'\0';
|
|
std::replace(filters.begin(), filters.end(), '|', '\0');
|
|
|
|
OPENFILENAMEW toGetFileName; //Struct for the dialog
|
|
wchar_t filePath[MAX_PATH];
|
|
_wgetcwd(filePath, MAX_PATH);
|
|
|
|
ZeroMemory(&toGetFileName, sizeof(OPENFILENAMEW));
|
|
toGetFileName.lStructSize = sizeof(OPENFILENAMEW);
|
|
toGetFileName.hwndOwner = NULL;
|
|
toGetFileName.lpstrFile = filePath;
|
|
toGetFileName.nMaxFile = MAX_PATH;
|
|
toGetFileName.lpstrFilter = filters == "\0" ? NULL : gd::utf8::ToWString(filters).c_str();
|
|
toGetFileName.nFilterIndex = 1;
|
|
toGetFileName.Flags = OFN_PATHMUSTEXIST | OFN_NOCHANGEDIR;;
|
|
|
|
if(GetOpenFileNameW(&toGetFileName) == TRUE)
|
|
result = gd::utf8::FromWString(filePath);
|
|
#endif
|
|
#if defined(LINUX) || defined(MAC)
|
|
nw::OpenFile * dialog = new nw::OpenFile(gd::utf8::ToLocaleString(title), true, result);
|
|
dialog->wait_until_closed();
|
|
result = gd::utf8::FromLocaleString(result); //Convert the path to UTF8
|
|
#endif
|
|
|
|
scene.NotifyPauseWasMade(timeSpent.getElapsedTime().asMicroseconds());//Don't take the time spent in this function in account.
|
|
|
|
//Update the variable
|
|
variable.SetString(result);
|
|
}
|
|
|
|
/**
|
|
* Show a message box with Yes/No buttons
|
|
*/
|
|
void GD_EXTENSION_API ShowYesNoMsgBox( RuntimeScene & scene, gd::Variable & variable, const std::string & message, const std::string & title )
|
|
{
|
|
sf::Clock timeSpent;
|
|
|
|
string result;
|
|
|
|
//Display the box
|
|
#if defined(WINDOWS)
|
|
if( MessageBoxW(NULL, gd::utf8::ToWString(message).c_str(), gd::utf8::ToWString(title).c_str(), MB_ICONQUESTION | MB_YESNO) == IDYES)
|
|
result = "yes";
|
|
else
|
|
result = "no";
|
|
#endif
|
|
#if defined(LINUX) || defined(MAC)
|
|
nw::YesNoMsgBox dialog(gd::utf8::ToLocaleString(title), gd::utf8::ToLocaleString(message), result);
|
|
dialog.wait_until_closed();
|
|
#endif
|
|
|
|
scene.NotifyPauseWasMade(timeSpent.getElapsedTime().asMicroseconds());//Don't take the time spent in this function in account.
|
|
|
|
//Update the variable
|
|
variable.SetString(result); //Can only be "yes" or "no", no need to encode in UTF8
|
|
}
|
|
|
|
//Declaration and definition of a simple input box for windows
|
|
#if defined(WINDOWS)
|
|
|
|
#define INPUTBOX_WIDTH 400
|
|
#define INPUTBOX_HEIGHT 125
|
|
|
|
/*
|
|
Author : mah
|
|
Date : 13.06.2002
|
|
Description :
|
|
similar to Visual Basic InputBox
|
|
*/
|
|
class CInputBox
|
|
{
|
|
static HFONT m_hFont;
|
|
static HWND m_hWndInputBox;
|
|
static HWND m_hWndParent;
|
|
static HWND m_hWndEdit;
|
|
static HWND m_hWndOK;
|
|
static HWND m_hWndCancel;
|
|
static HWND m_hWndPrompt;
|
|
|
|
static HINSTANCE m_hInst;
|
|
|
|
static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
|
|
public:
|
|
// text from InputBox
|
|
LPWSTR Text;
|
|
BOOL DoModal(LPCWSTR szCaption, LPCWSTR szPrompt);
|
|
|
|
CInputBox(HWND hWndParent);
|
|
virtual ~CInputBox();
|
|
|
|
};
|
|
|
|
HFONT CInputBox::m_hFont = NULL;
|
|
HWND CInputBox::m_hWndInputBox = NULL;
|
|
HWND CInputBox::m_hWndParent = NULL;
|
|
HWND CInputBox::m_hWndEdit = NULL;
|
|
HWND CInputBox::m_hWndOK = NULL;
|
|
HWND CInputBox::m_hWndCancel = NULL;
|
|
HWND CInputBox::m_hWndPrompt = NULL;
|
|
|
|
HINSTANCE CInputBox::m_hInst = NULL;
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// CInputBox Class
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Construction/Destruction
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
/*
|
|
Author : mah
|
|
Date : 13.06.2002
|
|
Description :
|
|
Constructs window class InputBox
|
|
*/
|
|
CInputBox::CInputBox(HWND hWndParent)
|
|
{
|
|
HINSTANCE hInst = GetModuleHandle(NULL);
|
|
|
|
WNDCLASSEX wcex;
|
|
|
|
if (!GetClassInfoEx(hInst, "InputBox", &wcex))
|
|
{
|
|
wcex.cbSize = sizeof(WNDCLASSEX);
|
|
|
|
wcex.style = CS_HREDRAW | CS_VREDRAW;
|
|
wcex.lpfnWndProc = (WNDPROC)WndProc;
|
|
wcex.cbClsExtra = 0;
|
|
wcex.cbWndExtra = 0;
|
|
wcex.hInstance = hInst;
|
|
wcex.hIcon = NULL;//LoadIcon(hInst, (LPCTSTR)IDI_MYINPUTBOX);
|
|
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
|
|
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW);
|
|
wcex.lpszMenuName = NULL;
|
|
wcex.lpszClassName = "InputBox";
|
|
wcex.hIconSm = NULL;
|
|
|
|
if (RegisterClassEx(&wcex) == 0)
|
|
MessageBox(NULL, "Can't create CInputBox!", "Error", MB_OK);
|
|
}
|
|
|
|
m_hWndParent = hWndParent;
|
|
|
|
Text = NULL;
|
|
|
|
}
|
|
|
|
CInputBox::~CInputBox()
|
|
{
|
|
if (Text) delete[] Text;
|
|
}
|
|
|
|
/*
|
|
Author : mah
|
|
Date : 13.06.2002
|
|
Description : Window procedure
|
|
*/
|
|
LRESULT CALLBACK CInputBox::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
LOGFONT lfont;
|
|
|
|
switch (message)
|
|
{
|
|
case WM_CREATE:
|
|
// font
|
|
memset(&lfont, 0, sizeof(lfont));
|
|
lstrcpy(lfont.lfFaceName, ("Arial"));
|
|
lfont.lfHeight = 16;
|
|
lfont.lfWeight = FW_NORMAL;//FW_BOLD;
|
|
lfont.lfItalic = FALSE;
|
|
lfont.lfCharSet = DEFAULT_CHARSET;
|
|
lfont.lfOutPrecision = OUT_DEFAULT_PRECIS;
|
|
lfont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
|
|
lfont.lfQuality = DEFAULT_QUALITY;
|
|
lfont.lfPitchAndFamily = DEFAULT_PITCH;
|
|
m_hFont = CreateFontIndirect(&lfont);
|
|
|
|
m_hInst = GetModuleHandle(NULL);
|
|
|
|
// creating Edit
|
|
m_hWndEdit = CreateWindowEx(WS_EX_STATICEDGE,
|
|
"edit","",
|
|
WS_VISIBLE | WS_CHILD | WS_TABSTOP | ES_AUTOHSCROLL,
|
|
5, INPUTBOX_HEIGHT - 50, INPUTBOX_WIDTH - 16, 20,
|
|
hWnd,
|
|
NULL,
|
|
m_hInst,
|
|
NULL);
|
|
|
|
// setting font
|
|
SendMessage(m_hWndEdit, WM_SETFONT, (WPARAM)m_hFont, 0);
|
|
|
|
// button OK
|
|
m_hWndOK = CreateWindowEx(WS_EX_STATICEDGE,
|
|
"button","OK",
|
|
WS_VISIBLE | WS_CHILD | WS_TABSTOP,
|
|
INPUTBOX_WIDTH - 100, 10, 90, 25,
|
|
hWnd,
|
|
NULL,
|
|
m_hInst,
|
|
NULL);
|
|
|
|
// setting font
|
|
SendMessage(m_hWndOK, WM_SETFONT, (WPARAM)m_hFont, 0);
|
|
|
|
// button Cancel
|
|
m_hWndCancel = CreateWindowEx(WS_EX_STATICEDGE,
|
|
"button","Cancel",
|
|
WS_VISIBLE | WS_CHILD | WS_TABSTOP,
|
|
INPUTBOX_WIDTH - 100, 40, 90, 25,
|
|
hWnd,
|
|
NULL,
|
|
m_hInst,
|
|
NULL);
|
|
|
|
// setting font
|
|
SendMessage(m_hWndCancel, WM_SETFONT, (WPARAM)m_hFont, 0);
|
|
|
|
// static Propmpt
|
|
m_hWndPrompt = CreateWindowEx(WS_EX_STATICEDGE,
|
|
"static","",
|
|
WS_VISIBLE | WS_CHILD,
|
|
5, 10, INPUTBOX_WIDTH - 110, INPUTBOX_HEIGHT - 70,
|
|
hWnd,
|
|
NULL,
|
|
m_hInst,
|
|
NULL);
|
|
|
|
// setting font
|
|
SendMessage(m_hWndPrompt, WM_SETFONT, (WPARAM)m_hFont, 0);
|
|
|
|
SetFocus(m_hWndEdit);
|
|
break;
|
|
case WM_DESTROY:
|
|
|
|
DeleteObject(m_hFont);
|
|
|
|
|
|
EnableWindow(m_hWndParent, TRUE);
|
|
SetForegroundWindow(m_hWndParent);
|
|
DestroyWindow(hWnd);
|
|
PostQuitMessage(0);
|
|
|
|
break;
|
|
case WM_COMMAND:
|
|
switch (HIWORD(wParam))
|
|
{
|
|
case BN_CLICKED:
|
|
if ((HWND)lParam == m_hWndOK)
|
|
PostMessage(m_hWndInputBox, WM_KEYDOWN, VK_RETURN, 0);
|
|
if ((HWND)lParam == m_hWndCancel)
|
|
PostMessage(m_hWndInputBox, WM_KEYDOWN, VK_ESCAPE, 0);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return DefWindowProc(hWnd, message, wParam, lParam);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
Author : mah
|
|
Date : 13.06.2002
|
|
Description :
|
|
Constructs InputBox window
|
|
*/
|
|
BOOL CInputBox::DoModal(LPCWSTR szCaption, LPCWSTR szPrompt)
|
|
{
|
|
RECT r;
|
|
GetWindowRect(GetDesktopWindow(), &r);
|
|
|
|
m_hWndInputBox = CreateWindowExW(WS_EX_TOOLWINDOW,
|
|
L"InputBox",
|
|
szCaption,
|
|
WS_POPUPWINDOW | WS_CAPTION | WS_TABSTOP,
|
|
(r.right - INPUTBOX_WIDTH) / 2, (r.bottom - INPUTBOX_HEIGHT) / 2,
|
|
INPUTBOX_WIDTH, INPUTBOX_HEIGHT,
|
|
m_hWndParent,
|
|
NULL,
|
|
m_hInst,
|
|
NULL);
|
|
if(m_hWndInputBox == NULL)
|
|
return FALSE;
|
|
|
|
|
|
SetWindowTextW(m_hWndPrompt, szPrompt);
|
|
|
|
SetForegroundWindow(m_hWndInputBox);
|
|
BringWindowToTop(m_hWndInputBox);
|
|
|
|
EnableWindow(m_hWndParent, FALSE);
|
|
|
|
ShowWindow(m_hWndInputBox, SW_SHOW);
|
|
UpdateWindow(m_hWndInputBox);
|
|
|
|
BOOL ret = 0;
|
|
|
|
MSG msg;
|
|
|
|
HWND hWndFocused;
|
|
|
|
while (GetMessage(&msg, NULL, 0, 0))
|
|
{
|
|
if (msg.message == WM_KEYDOWN)
|
|
{
|
|
if (msg.wParam == VK_ESCAPE)
|
|
{
|
|
SendMessage(m_hWndInputBox, WM_DESTROY, 0, 0);
|
|
ret = 0;
|
|
}
|
|
if (msg.wParam == VK_RETURN)
|
|
{
|
|
int nCount = GetWindowTextLengthW(m_hWndEdit);
|
|
nCount++;
|
|
if (Text)
|
|
{
|
|
delete[] Text;
|
|
Text = NULL;
|
|
}
|
|
Text = new WCHAR[nCount];
|
|
GetWindowTextW(m_hWndEdit, Text, nCount);
|
|
SendMessage(m_hWndInputBox, WM_DESTROY, 0, 0);
|
|
ret = 1;
|
|
}
|
|
if (msg.wParam == VK_TAB)
|
|
{
|
|
hWndFocused = GetFocus();
|
|
if (hWndFocused == m_hWndEdit) SetFocus(m_hWndOK);
|
|
if (hWndFocused == m_hWndOK) SetFocus(m_hWndCancel);
|
|
if (hWndFocused == m_hWndCancel) SetFocus(m_hWndEdit);
|
|
}
|
|
|
|
}
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
#undef INPUTBOX_WIDTH
|
|
#undef INPUTBOX_HEIGHT
|
|
#endif
|
|
|
|
/**
|
|
* Show a dialog so as to get a text from user
|
|
*/
|
|
bool GD_EXTENSION_API ShowTextInput( RuntimeScene & scene, gd::Variable & variable, const std::string & message, const std::string & title )
|
|
{
|
|
sf::Clock timeSpent;
|
|
string result;
|
|
|
|
//Display the box
|
|
#if defined(WINDOWS)
|
|
CInputBox ibox(NULL);
|
|
if (ibox.DoModal(gd::utf8::ToWString(title).c_str(), gd::utf8::ToWString(message).c_str()))
|
|
result = gd::utf8::FromWString(ibox.Text);
|
|
#endif
|
|
#if defined(LINUX) || defined(MAC)
|
|
nw::TextInput dialog(title, message, result);
|
|
dialog.wait_until_closed();
|
|
result = gd::utf8::FromLocaleString(result); //Convert from locale
|
|
#endif
|
|
|
|
scene.NotifyPauseWasMade(timeSpent.getElapsedTime().asMicroseconds());//Don't take the time spent in this function in account.
|
|
|
|
//Update the variable
|
|
variable.SetString(result);
|
|
|
|
return true;
|
|
}
|
|
|
|
}
|
|
} //namespace GDpriv
|
|
|