framework2
777 строк · 24.4 Кб
1
2#include "ofSystemUtils.h"
3#include "ofFileUtils.h"
4#include "ofLog.h"
5#include "ofUtils.h"
6#include "ofConstants.h"
7
8#include <condition_variable>
9#include <mutex>
10
11#ifdef TARGET_OSX
12// ofSystemUtils.cpp is configured to build as
13// objective-c++ so as able to use Cocoa dialog panels
14// This is done with this compiler flag
15// -x objective-c++
16// http://www.yakyak.org/viewtopic.php?p=1475838&sid=1e9dcb5c9fd652a6695ac00c5e957822#p1475838
17
18#include <Cocoa/Cocoa.h>
19#include "ofAppRunner.h"
20#endif
21
22#ifdef TARGET_WIN32
23
24#define _WIN32_DCOM
25#include <winuser.h>
26#include <commdlg.h>
27#include <windows.h>
28#include <shlobj.h>
29#include <tchar.h>
30#include <stdio.h>
31#include <locale>
32#include <sstream>
33#include <string>
34
35std::string convertWideToNarrow( const wchar_t *s, char dfault = '?',
36const std::locale& loc = std::locale() )
37{
38std::ostringstream stm;
39
40while( *s != L'\0' ) {
41stm << std::use_facet< std::ctype<wchar_t> >( loc ).narrow( *s++, dfault );
42}
43return stm.str();
44}
45
46std::wstring convertNarrowToWide( const std::string& as ){
47// deal with trivial case of empty string
48if( as.empty() ) return std::wstring();
49
50// determine required length of new string
51size_t reqLength = ::MultiByteToWideChar( CP_UTF8, 0, as.c_str(), (int)as.length(), 0, 0 );
52
53// construct new string of required length
54std::wstring ret( reqLength, L'\0' );
55
56// convert old string to new string
57::MultiByteToWideChar( CP_UTF8, 0, as.c_str(), (int)as.length(), &ret[0], (int)ret.length() );
58
59// return new string ( compiler should optimize this away )
60return ret;
61}
62
63#endif
64
65#if defined( TARGET_OSX )
66static void restoreAppWindowFocus(){
67NSWindow * appWindow = (__bridge NSWindow *)ofGetCocoaWindow();
68if(appWindow) {
69[appWindow makeKeyAndOrderFront:nil];
70}
71}
72#endif
73
74#if defined( TARGET_LINUX ) && defined (OF_USING_GTK)
75#include <gtk/gtk.h>
76#include "ofGstUtils.h"
77#include <thread>
78#include <X11/Xlib.h>
79
80#if GTK_MAJOR_VERSION>=3
81#define OPEN_BUTTON "_Open"
82#define SELECT_BUTTON "_Select All"
83#define SAVE_BUTTON "_Save"
84#define CANCEL_BUTTON "_Cancel"
85#else
86#define OPEN_BUTTON GTK_STOCK_OPEN
87#define SELECT_BUTTON GTK_STOCK_SELECT_ALL
88#define SAVE_BUTTON GTK_STOCK_SAVE
89#define CANCEL_BUTTON GTK_STOCK_CANCEL
90#endif
91
92
93gboolean init_gtk(gpointer userdata){
94int argc=0; char **argv = nullptr;
95gtk_init (&argc, &argv);
96
97return FALSE;
98}
99
100struct FileDialogData{
101GtkFileChooserAction action;
102std::string windowTitle;
103std::string defaultName;
104std::string results;
105bool done;
106std::condition_variable condition;
107std::mutex mutex;
108};
109
110gboolean file_dialog_gtk(gpointer userdata){
111FileDialogData * dialogData = (FileDialogData*)userdata;
112const gchar* button_name = nullptr;
113switch(dialogData->action){
114case GTK_FILE_CHOOSER_ACTION_OPEN:
115button_name = OPEN_BUTTON;
116break;
117case GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER:
118button_name = SELECT_BUTTON;
119break;
120case GTK_FILE_CHOOSER_ACTION_SAVE:
121button_name = SAVE_BUTTON;
122break;
123default:
124break;
125}
126
127if(button_name!=nullptr){
128GtkWidget *dialog = gtk_file_chooser_dialog_new (dialogData->windowTitle.c_str(),
129nullptr,
130dialogData->action,
131button_name, GTK_RESPONSE_ACCEPT,
132CANCEL_BUTTON, GTK_RESPONSE_CANCEL,
133nullptr);
134
135if(ofFile(dialogData->defaultName, ofFile::Reference).isDirectory()){
136gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), dialogData->defaultName.c_str());
137}else{
138gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), dialogData->defaultName.c_str());
139}
140
141if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
142dialogData->results = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
143}
144gtk_widget_destroy (dialog);
145}
146
147std::unique_lock<std::mutex> lck(dialogData->mutex);
148dialogData->condition.notify_all();
149dialogData->done = true;
150return G_SOURCE_REMOVE;
151}
152
153struct TextDialogData{
154std::string text;
155std::string question;
156bool done;
157std::condition_variable condition;
158std::mutex mutex;
159};
160
161gboolean alert_dialog_gtk(gpointer userdata){
162TextDialogData * dialogData = (TextDialogData*)userdata;
163GtkWidget* dialog = gtk_message_dialog_new (nullptr, (GtkDialogFlags) 0, GTK_MESSAGE_INFO, GTK_BUTTONS_OK, "%s", dialogData->text.c_str());
164gtk_widget_grab_focus(gtk_dialog_get_widget_for_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK));
165gtk_dialog_run (GTK_DIALOG (dialog));
166gtk_widget_destroy (dialog);
167dialogData->mutex.lock();
168dialogData->condition.notify_all();
169dialogData->done = true;
170dialogData->mutex.unlock();
171
172return G_SOURCE_REMOVE;
173}
174
175gboolean text_dialog_gtk(gpointer userdata){
176TextDialogData * dialogData = (TextDialogData*)userdata;
177GtkWidget* dialog = gtk_message_dialog_new (nullptr, (GtkDialogFlags) 0, GTK_MESSAGE_QUESTION, (GtkButtonsType) GTK_BUTTONS_OK_CANCEL, "%s", dialogData->question.c_str() );
178GtkWidget* content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
179GtkWidget* textbox = gtk_entry_new();
180gtk_entry_set_text(GTK_ENTRY(textbox),dialogData->text.c_str());
181gtk_container_add (GTK_CONTAINER (content_area), textbox);
182gtk_widget_show_all (dialog);
183if(gtk_dialog_run (GTK_DIALOG (dialog))==GTK_RESPONSE_OK){
184dialogData->text = gtk_entry_get_text(GTK_ENTRY(textbox));
185} else {
186dialogData->text = "";
187}
188gtk_widget_destroy (dialog);
189dialogData->mutex.lock();
190dialogData->condition.notify_all();
191dialogData->done = true;
192dialogData->mutex.unlock();
193
194return G_SOURCE_REMOVE;
195}
196
197static void initGTK(){
198static bool initialized = false;
199if(!initialized){
200#if !defined(TARGET_RASPBERRY_PI_LEGACY)
201XInitThreads();
202#endif
203int argc=0; char **argv = nullptr;
204gtk_init (&argc, &argv);
205ofGstUtils::startGstMainLoop();
206initialized = true;
207}
208
209}
210
211static std::string gtkFileDialog(GtkFileChooserAction action,std::string windowTitle,std::string defaultName=""){
212initGTK();
213FileDialogData dialogData;
214dialogData.action = action;
215dialogData.windowTitle = windowTitle;
216dialogData.defaultName = defaultName;
217dialogData.done = false;
218
219g_main_context_invoke(g_main_loop_get_context(ofGstUtils::getGstMainLoop()), &file_dialog_gtk, &dialogData);
220if(!dialogData.done){
221std::unique_lock<std::mutex> lck(dialogData.mutex);
222dialogData.condition.wait(lck);
223}
224
225return dialogData.results;
226}
227
228void resetLocale(std::locale locale){
229try{
230std::locale::global(locale);
231}catch(...){
232if(ofToLower(std::locale("").name()).find("utf-8")==std::string::npos){
233ofLogWarning("ofSystemUtils") << "GTK changes the locale when opening a dialog which can "
234"break number parsing. We tried to change back to " <<
235locale.name() <<
236"but failed some string parsing functions might behave differently "
237"after this";
238}
239}
240}
241#endif
242
243#ifdef TARGET_ANDROID
244#include "ofxAndroidUtils.h"
245#endif
246
247#ifdef TARGET_EMSCRIPTEN
248#include <emscripten/emscripten.h>
249#endif
250
251
252//------------------------------------------------------------------------------
253ofFileDialogResult::ofFileDialogResult(){
254filePath = "";
255fileName = "";
256bSuccess = false;
257}
258
259//------------------------------------------------------------------------------
260std::string ofFileDialogResult::getName(){
261return fileName;
262}
263
264//------------------------------------------------------------------------------
265std::string ofFileDialogResult::getPath(){
266return filePath;
267}
268
269
270//------------------------------------------------------------------------------
271void ofSystemAlertDialog(std::string errorMessage){
272#ifdef TARGET_WIN32
273// we need to convert error message to a wide char message.
274std::wstring errorMessageW{errorMessage.begin(),errorMessage.end()};
275// launch the alert:
276MessageBoxW(nullptr, errorMessageW.c_str(), L"alert", MB_OK);
277#endif
278
279#ifdef TARGET_OSX
280@autoreleasepool {
281NSAlert* alertDialog = [[NSAlert alloc] init];
282alertDialog.messageText = [NSString stringWithUTF8String:errorMessage.c_str()];
283[alertDialog runModal];
284restoreAppWindowFocus();
285}
286#endif
287
288#if defined( TARGET_LINUX ) && defined (OF_USING_GTK)
289auto locale = std::locale();
290initGTK();
291TextDialogData dialogData;
292dialogData.text = errorMessage;
293dialogData.done = false;
294g_main_context_invoke(g_main_loop_get_context(ofGstUtils::getGstMainLoop()), &alert_dialog_gtk, &dialogData);
295if(!dialogData.done){
296std::unique_lock<std::mutex> lock(dialogData.mutex);
297dialogData.condition.wait(lock);
298}
299resetLocale(locale);
300#endif
301
302#ifdef TARGET_ANDROID
303ofxAndroidAlertBox(errorMessage);
304#endif
305
306#ifdef TARGET_EMSCRIPTEN
307emscripten_run_script((std::string("alert(")+errorMessage+");").c_str());
308#endif
309}
310
311//----------------------------------------------------------------------------------------
312#ifdef TARGET_WIN32
313//---------------------------------------------------------------------
314static int CALLBACK loadDialogBrowseCallback(
315HWND hwnd,
316UINT uMsg,
317LPARAM lParam,
318LPARAM lpData
319){
320std::string defaultPath = *(std::string*)lpData;
321if(defaultPath!="" && uMsg==BFFM_INITIALIZED){
322wchar_t wideCharacterBuffer[MAX_PATH];
323wcscpy(wideCharacterBuffer, convertNarrowToWide(ofToDataPath(defaultPath)).c_str());
324SendMessage(hwnd,BFFM_SETSELECTION,1,(LPARAM)wideCharacterBuffer);
325}
326
327return 0;
328}
329//----------------------------------------------------------------------------------------
330#endif
331//---------------------------------------------------------------------
332
333// OS specific results here. "" = cancel or something bad like can't load, can't save, etc...
334ofFileDialogResult ofSystemLoadDialog(std::string windowTitle, bool bFolderSelection, std::string defaultPath){
335
336ofFileDialogResult results;
337
338//----------------------------------------------------------------------------------------
339//------------------------------------------------------------------------------ OSX
340//----------------------------------------------------------------------------------------
341#ifdef TARGET_OSX
342@autoreleasepool {
343NSOpenGLContext *context = [NSOpenGLContext currentContext];
344
345NSOpenPanel * loadDialog = [NSOpenPanel openPanel];
346[loadDialog setAllowsMultipleSelection:NO];
347[loadDialog setCanChooseDirectories:bFolderSelection];
348[loadDialog setCanChooseFiles:!bFolderSelection];
349[loadDialog setResolvesAliases:YES];
350
351if(!windowTitle.empty()) {
352// changed from setTitle to setMessage
353// https://stackoverflow.com/questions/36879212/title-bar-missing-in-nsopenpanel
354[loadDialog setMessage:[NSString stringWithUTF8String:windowTitle.c_str()]];
355}
356
357if(!defaultPath.empty()) {
358NSString * s = [NSString stringWithUTF8String:defaultPath.c_str()];
359s = [[s stringByExpandingTildeInPath] stringByResolvingSymlinksInPath];
360NSURL * defaultPathUrl = [NSURL fileURLWithPath:s];
361[loadDialog setDirectoryURL:defaultPathUrl];
362}
363
364NSInteger buttonClicked = [loadDialog runModal];
365[context makeCurrentContext];
366restoreAppWindowFocus();
367
368if(buttonClicked == NSModalResponseOK) {
369NSURL * selectedFileURL = [[loadDialog URLs] objectAtIndex:0];
370results.filePath = std::string([[selectedFileURL path] UTF8String]);
371}
372}
373#endif
374//----------------------------------------------------------------------------------------
375//----------------------------------------------------------------------------------------
376//----------------------------------------------------------------------------------------
377
378//----------------------------------------------------------------------------------------
379//------------------------------------------------------------------------------ windoze
380//----------------------------------------------------------------------------------------
381#ifdef TARGET_WIN32
382std::wstring windowTitleW{windowTitle.begin(), windowTitle.end()};
383
384if (bFolderSelection == false){
385
386OPENFILENAME ofn;
387
388ZeroMemory(&ofn, sizeof(ofn));
389ofn.lStructSize = sizeof(ofn);
390HWND hwnd = WindowFromDC(wglGetCurrentDC());
391ofn.hwndOwner = hwnd;
392
393//the file name and path
394wchar_t szFileName[MAX_PATH];
395memset(szFileName, 0, sizeof(szFileName));
396
397//the dir, if specified
398wchar_t szDir[MAX_PATH];
399
400//the title if specified
401wchar_t szTitle[MAX_PATH];
402if(defaultPath!=""){
403wcscpy(szDir,convertNarrowToWide(ofToDataPath(defaultPath)).c_str());
404ofn.lpstrInitialDir = szDir;
405}
406
407if (windowTitle != "") {
408wcscpy(szTitle, convertNarrowToWide(windowTitle).c_str());
409ofn.lpstrTitle = szTitle;
410} else {
411ofn.lpstrTitle = nullptr;
412}
413
414ofn.lpstrFilter = L"All\0";
415ofn.lpstrFile = szFileName;
416ofn.nMaxFile = MAX_PATH;
417ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
418ofn.lpstrDefExt = 0;
419ofn.lpstrTitle = windowTitleW.c_str();
420
421if(GetOpenFileName(&ofn)) {
422results.filePath = convertWideToNarrow(szFileName);
423}
424else {
425//this should throw an error on failure unless its just the user canceling out
426//DWORD err = CommDlgExtendedError();
427}
428
429} else {
430
431BROWSEINFOW bi;
432wchar_t wideCharacterBuffer[MAX_PATH];
433wchar_t wideWindowTitle[MAX_PATH];
434LPITEMIDLIST pidl;
435LPMALLOC lpMalloc;
436
437if (windowTitle != "") {
438wcscpy(wideWindowTitle, convertNarrowToWide(windowTitle).c_str());
439} else {
440wcscpy(wideWindowTitle, L"Select Directory");
441}
442
443// Get a pointer to the shell memory allocator
444if(SHGetMalloc(&lpMalloc) != S_OK){
445//TODO: deal with some sort of error here?
446}
447bi.hwndOwner = nullptr;
448bi.pidlRoot = nullptr;
449bi.pszDisplayName = wideCharacterBuffer;
450bi.lpszTitle = wideWindowTitle;
451bi.ulFlags = BIF_RETURNFSANCESTORS | BIF_RETURNONLYFSDIRS | BIF_USENEWUI;
452bi.lpfn = &loadDialogBrowseCallback;
453bi.lParam = (LPARAM) &defaultPath;
454bi.lpszTitle = windowTitleW.c_str();
455
456if( (pidl = SHBrowseForFolderW(&bi)) ){
457// Copy the path directory to the buffer
458if(SHGetPathFromIDListW(pidl,wideCharacterBuffer)){
459results.filePath = convertWideToNarrow(wideCharacterBuffer);
460}
461lpMalloc->Free(pidl);
462}
463lpMalloc->Release();
464}
465
466//----------------------------------------------------------------------------------------
467//------------------------------------------------------------------------------ windoze
468//----------------------------------------------------------------------------------------
469#endif
470
471
472
473
474//----------------------------------------------------------------------------------------
475//------------------------------------------------------------------------------ linux
476//----------------------------------------------------------------------------------------
477#if defined( TARGET_LINUX ) && defined (OF_USING_GTK)
478auto locale = std::locale();
479if(bFolderSelection)
480results.filePath = gtkFileDialog(GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, windowTitle, ofToDataPath(defaultPath).c_str());
481else
482results.filePath = gtkFileDialog(GTK_FILE_CHOOSER_ACTION_OPEN, windowTitle, ofToDataPath(defaultPath).c_str());
483resetLocale(locale);
484#endif
485//----------------------------------------------------------------------------------------
486//----------------------------------------------------------------------------------------
487//----------------------------------------------------------------------------------------
488
489
490
491if( results.filePath.length() > 0 ){
492results.bSuccess = true;
493results.fileName = ofFilePath::getFileName(results.filePath);
494}
495
496return results;
497}
498
499
500
501ofFileDialogResult ofSystemSaveDialog(std::string defaultName, std::string messageName){
502
503ofFileDialogResult results;
504
505//----------------------------------------------------------------------------------------
506//------------------------------------------------------------------------------ OSX
507//----------------------------------------------------------------------------------------
508#ifdef TARGET_OSX
509@autoreleasepool {
510NSSavePanel * saveDialog = [NSSavePanel savePanel];
511NSOpenGLContext *context = [NSOpenGLContext currentContext];
512[saveDialog setMessage:[NSString stringWithUTF8String:messageName.c_str()]];
513[saveDialog setNameFieldStringValue:[NSString stringWithUTF8String:defaultName.c_str()]];
514
515NSInteger buttonClicked = [saveDialog runModal];
516restoreAppWindowFocus();
517[context makeCurrentContext];
518
519if(buttonClicked == NSModalResponseOK){
520results.filePath = std::string([[[saveDialog URL] path] UTF8String]);
521}
522}
523#endif
524//----------------------------------------------------------------------------------------
525//----------------------------------------------------------------------------------------
526//----------------------------------------------------------------------------------------
527
528//----------------------------------------------------------------------------------------
529//------------------------------------------------------------------------------ windoze
530//----------------------------------------------------------------------------------------
531#ifdef TARGET_WIN32
532
533
534wchar_t fileName[MAX_PATH] = L"";
535OPENFILENAMEW ofn;
536memset(&ofn, 0, sizeof(OPENFILENAME));
537ofn.lStructSize = sizeof(OPENFILENAME);
538HWND hwnd = WindowFromDC(wglGetCurrentDC());
539ofn.hwndOwner = hwnd;
540ofn.hInstance = GetModuleHandle(0);
541ofn.nMaxFileTitle = 31;
542ofn.lpstrFile = fileName;
543ofn.nMaxFile = MAX_PATH;
544ofn.lpstrFilter = L"All Files (*.*)\0*.*\0";
545ofn.lpstrDefExt = L""; // we could do .rxml here?
546ofn.Flags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT | OFN_HIDEREADONLY;
547ofn.lpstrTitle = L"Select Output File";
548
549if (GetSaveFileNameW(&ofn)){
550results.filePath = convertWideToNarrow(fileName);
551}
552
553#endif
554//----------------------------------------------------------------------------------------
555//----------------------------------------------------------------------------------------
556//----------------------------------------------------------------------------------------
557
558
559//----------------------------------------------------------------------------------------
560//------------------------------------------------------------------------------ linux
561//----------------------------------------------------------------------------------------
562#if defined( TARGET_LINUX ) && defined (OF_USING_GTK)
563auto locale = std::locale();
564// results.filePath = gtkFileDialog(GTK_FILE_CHOOSER_ACTION_SAVE, messageName, ofToDataPath(defaultName).string());
565results.filePath = gtkFileDialog(GTK_FILE_CHOOSER_ACTION_SAVE, messageName, ofToDataPath(defaultName));
566resetLocale(locale);
567#endif
568//----------------------------------------------------------------------------------------
569//----------------------------------------------------------------------------------------
570//----------------------------------------------------------------------------------------
571
572if( results.filePath.length() > 0 ){
573results.bSuccess = true;
574results.fileName = ofFilePath::getFileName(results.filePath);
575}
576
577return results;
578}
579
580#ifdef TARGET_WIN32
581LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
582{
583//switch(msg)
584//{
585// case WM_CLOSE:
586// DestroyWindow(hwnd);
587// break;
588// case WM_DESTROY:
589// PostQuitMessage(0);
590// break;
591// default:
592return DefWindowProc(hwnd, msg, wParam, lParam);
593//}
594}
595#endif
596
597
598std::string ofSystemTextBoxDialog(std::string question, std::string text){
599#if defined( TARGET_LINUX ) && defined (OF_USING_GTK)
600auto locale = std::locale();
601initGTK();
602TextDialogData dialogData;
603dialogData.text = text;
604dialogData.done = false;
605dialogData.question = question;
606g_main_context_invoke(g_main_loop_get_context(ofGstUtils::getGstMainLoop()), &text_dialog_gtk, &dialogData);
607if(!dialogData.done){
608std::unique_lock<std::mutex> lock(dialogData.mutex);
609dialogData.condition.wait(lock);
610}
611resetLocale(locale);
612text = dialogData.text;
613#endif
614
615#ifdef TARGET_OSX
616@autoreleasepool {
617// create alert dialog
618NSAlert *alert = [[NSAlert alloc] init];
619[alert addButtonWithTitle:@"OK"];
620[alert addButtonWithTitle:@"Cancel"];
621[alert setMessageText:[NSString stringWithCString:question.c_str()
622encoding:NSUTF8StringEncoding]];
623// create text field
624NSTextField* label = [[NSTextField alloc] initWithFrame:NSRectFromCGRect(CGRectMake(0,0,300,40))];
625[label setStringValue:[NSString stringWithCString:text.c_str()
626encoding:NSUTF8StringEncoding]];
627// add text field to alert dialog
628[alert setAccessoryView:label];
629[[alert window] setInitialFirstResponder: label];
630
631NSInteger returnCode = [alert runModal];
632restoreAppWindowFocus();
633// if OK was clicked, assign value to text
634if ( returnCode == NSAlertFirstButtonReturn )
635text = [[label stringValue] UTF8String];
636else
637text = "";
638}
639#endif
640
641#ifdef TARGET_WIN32
642// we need to convert error message to a wide char message.
643// first, figure out the length and allocate a wchar_t at that length + 1 (the +1 is for a terminating character)
644
645WNDCLASSEX wc;
646MSG Msg;
647
648#define TMP_STR_CONVERT LPCWSTR
649
650const LPCWSTR g_szClassName = L"myWindowClass\0";
651
652//Step 1: Registering the Window Class
653wc.cbSize = sizeof(WNDCLASSEX);
654wc.style = CS_HREDRAW | CS_VREDRAW;
655wc.lpfnWndProc = WndProc;
656wc.cbClsExtra = 0;
657wc.cbWndExtra = 0;
658wc.hInstance = GetModuleHandle(0);
659wc.lpszClassName = g_szClassName;
660wc.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1);
661wc.lpszMenuName = nullptr;
662wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
663wc.hIcon = LoadIcon(nullptr, IDI_APPLICATION);
664wc.hIconSm = LoadIcon(nullptr, IDI_APPLICATION);
665if(!RegisterClassEx(&wc)){
666DWORD err=GetLastError();
667if ((err==ERROR_CLASS_ALREADY_EXISTS)){
668; // we are ok
669// http://stackoverflow.com/questions/5791996/re-registering-user-defined-window-class-c
670} else {
671MessageBox(nullptr, L"Window Registration Failed!\0", L"Error!\0",
672MB_ICONEXCLAMATION | MB_OK);
673return text;
674}
675}
676
677HWND dialog = CreateWindowEx(WS_EX_DLGMODALFRAME,
678g_szClassName,
679convertNarrowToWide(question).c_str(),
680WS_POPUP | WS_CAPTION | DS_MODALFRAME | WS_SYSMENU,
681CW_USEDEFAULT, CW_USEDEFAULT, 240, 140,
682WindowFromDC(wglGetCurrentDC()), nullptr, GetModuleHandle(0),nullptr);
683
684if(dialog == nullptr)
685{
686
687MessageBox(nullptr,L"Window Creation Failed!\0", L"Error!\0",
688MB_ICONEXCLAMATION | MB_OK);
689return text;
690
691}
692
693EnableWindow(WindowFromDC(wglGetCurrentDC()), FALSE);
694HWND hEdit = CreateWindowEx(WS_EX_CLIENTEDGE, L"EDIT\0", convertNarrowToWide(text).c_str(),
695WS_CHILD | WS_VISIBLE | WS_TABSTOP,
69610, 10, 210, 40, dialog, (HMENU)101, GetModuleHandle(nullptr), nullptr);
697
698
699HWND okButton = CreateWindowEx(WS_EX_CLIENTEDGE, L"BUTTON\0", L"OK\0",
700WS_CHILD | WS_VISIBLE | WS_TABSTOP,
70110, 60, 60, 30, dialog, (HMENU)IDOK, GetModuleHandle(nullptr), nullptr);
702
703HWND cancelButton = CreateWindowEx(WS_EX_CLIENTEDGE, L"BUTTON\0", L"Cancel\0",
704WS_CHILD | WS_VISIBLE,
70580, 60, 60, 30, dialog, (HMENU)IDCANCEL, GetModuleHandle(nullptr), nullptr);
706
707SetFocus( hEdit );
708
709ShowWindow(dialog, SW_SHOWNORMAL);
710bool bFirstEmpty = true;
711while (true){
712if (!PeekMessageW( &Msg, 0, 0, 0, PM_REMOVE )){
713if (bFirstEmpty){
714// ShowWindow the first time the queue goes empty
715ShowWindow( dialog, SW_SHOWNORMAL );
716bFirstEmpty = FALSE;
717}
718if (!(GetWindowLongW( dialog, GWL_STYLE ) & DS_NOIDLEMSG)){
719// No message present -> send ENTERIDLE and wait
720SendMessageW( WindowFromDC(wglGetCurrentDC()), WM_ENTERIDLE, MSGF_DIALOGBOX, (LPARAM)dialog );
721}
722GetMessageW( &Msg, 0, 0, 0 );
723}
724
725if (Msg.message == WM_QUIT){
726PostQuitMessage( Msg.wParam );
727if (!IsWindow( dialog )){
728EnableWindow(WindowFromDC(wglGetCurrentDC()), TRUE);
729return text;
730}
731break;
732}
733
734if (!IsWindow( dialog )){
735EnableWindow(WindowFromDC(wglGetCurrentDC()), TRUE);
736return text;
737}
738
739TranslateMessage( &Msg );
740DispatchMessageW( &Msg );
741
742if((Msg.hwnd == okButton && Msg.message==WM_LBUTTONUP) || (Msg.message==WM_KEYUP && Msg.wParam==13)){
743break;
744}else if((Msg.hwnd == cancelButton && Msg.message==WM_LBUTTONUP) || (Msg.message==WM_KEYUP && Msg.wParam==27)){
745EnableWindow(WindowFromDC(wglGetCurrentDC()), TRUE);
746DestroyWindow(dialog);
747return "";
748}
749
750if (!IsWindow( dialog )){
751EnableWindow(WindowFromDC(wglGetCurrentDC()), TRUE);
752return text;
753}
754
755if (bFirstEmpty && Msg.message == WM_TIMER){
756ShowWindow( dialog, SW_SHOWNORMAL );
757bFirstEmpty = FALSE;
758}
759}
760
761char buf[16384];
762GetDlgItemTextA( dialog, 101, buf, 16384 );
763text = buf;
764
765DestroyWindow(dialog);
766EnableWindow(WindowFromDC(wglGetCurrentDC()), TRUE);
767
768#endif
769
770#ifdef TARGET_ANDROID
771ofxAndroidAlertTextBox(question,text);
772#endif
773
774#ifdef TARGET_EMSCRIPTEN
775text = emscripten_run_script_string((std::string("prompt('") + question + "','')").c_str());
776#endif
777return text;
778}
779