Difference between revisions of "CPlusPlus for Gideros Studio Help"

From GiderosMobile
(24 intermediate revisions by the same user not shown)
Line 2: Line 2:
 
Here you will find various resources to help learn C++ for people who wish to help with Gideros Studio development.
 
Here you will find various resources to help learn C++ for people who wish to help with Gideros Studio development.
  
=== Description ===
+
== WIN32 ==
Trying to add missing functions to win32 build.
 
  
C:\dev\gideros_hgy29\libgid\src\win32\platform-win32.cpp
+
=== KNOWNFOLDERID ===
<source lang="lua">
+
platform-win32.cpp
#include <stdio.h>
 
#include <windows.h>
 
#include <vector>
 
#include <string>
 
#include <stdlib.h>
 
 
 
#include "luaapplication.h"
 
#include <application.h>
 
#include <gapplication-win32.h>
 
//#include "platform.h" // new 20221011 XXX
 
//#include <gfile_p.h> // new 20221011 XXX
 
 
 
extern HWND hwndcopy;
 
extern char commandLine[];
 
//extern std::string commandLine; // new 20221011 XXX
 
// extern int dxChrome,dyChrome;
 
extern LuaApplication *application_;
 
 
 
static std::wstring ws(const char *str) // new 20221011 XXX
 
{
 
    if (!str) return std::wstring();
 
    int sl=strlen(str);
 
    int sz = MultiByteToWideChar(CP_UTF8, 0, str, sl, 0, 0);
 
    std::wstring res(sz, 0);
 
    MultiByteToWideChar(CP_UTF8, 0, str, sl, &res[0], sz);
 
    return res;
 
}
 
 
 
static std::string us(const wchar_t *str) // new 20221011 XXX
 
{
 
    if (!str) return std::string();
 
    int sl=wcslen(str);
 
    int sz = WideCharToMultiByte(CP_UTF8, 0, str, sl, 0, 0,NULL,NULL);
 
    std::string res(sz, 0);
 
    WideCharToMultiByte(CP_UTF8, 0, str, sl, &res[0], sz,NULL,NULL);
 
    return res;
 
}
 
 
 
void GetDesktopResolution(int& horizontal, int& vertical)
 
{
 
  RECT desktop;
 
  // Get a handle to the desktop window
 
  const HWND hDesktop = GetDesktopWindow();
 
  // Get the size of screen to the variable desktop
 
  GetClientRect(hDesktop, &desktop);
 
  // The top left corner will have coordinates (0,0)
 
  // and the bottom right corner will have coordinates
 
  // (horizontal, vertical)
 
  horizontal = desktop.right;
 
  vertical = desktop.bottom;
 
}
 
 
 
std::vector<std::string> getDeviceInfo()
 
{
 
  std::vector<std::string> result;
 
  result.push_back("Win33"); // ;-)
 
  return result;
 
}
 
 
 
void openUrl(const char* url)
 
{
 
  ShellExecute(hwndcopy,NULL,url,NULL,NULL,SW_SHOWNORMAL);
 
//  std::wstring w=ws(url); // new 20221011 XXX
 
//  ShellExecute(hwndcopy,NULL,w.c_str(),NULL,NULL,SW_SHOWNORMAL); // new 20221011 XXX
 
}
 
 
 
bool canOpenUrl(const char *url)
 
{
 
  return true;
 
}
 
 
 
std::string getLocale()
 
{
 
  TCHAR szBuff1[10], szBuff2[10];
 
 
 
  LCID lcid = GetUserDefaultLCID();
 
 
 
  GetLocaleInfo(lcid, LOCALE_SISO639LANGNAME, szBuff1, 10);
 
  GetLocaleInfo(lcid, LOCALE_SISO3166CTRYNAME, szBuff2, 10);
 
  strcat(szBuff1,"_");
 
  strcat(szBuff1,szBuff2);
 
//  std::string s=us(szBuff1)+"_"+us(szBuff2); // new 20221011 XXX
 
 
 
  return szBuff1;
 
//  return s; // new 20221011 XXX
 
}
 
 
 
std::string getLanguage()
 
{
 
  TCHAR szBuff[10];
 
  LCID lcid = GetUserDefaultLCID();
 
  GetLocaleInfo(lcid, LOCALE_SISO639LANGNAME, szBuff, 10);
 
  return szBuff;
 
//  return us(szBuff); // new 20221011 XXX
 
}
 
 
 
std::string getAppId(){
 
return "";
 
}
 
 
 
void getSafeDisplayArea(int &x,int &y,int &w,int &h)
 
{
 
}
 
  
void setWindowSize(int width, int height)
+
'''refs''':
{
+
* KNOWNFOLDERID: https://learn.microsoft.com/en-us/windows/win32/shell/knownfolderid
  printf("setWindowSize: %d x %d. hwndcopy=%p\n",width,height,hwndcopy);
+
* shlobj_core.h header: https://learn.microsoft.com/en-us/windows/win32/api/shlobj_core/
 
+
* SHGetKnownFolderPath function (shlobj_core.h): https://learn.microsoft.com/en-us/windows/win32/api/shlobj_core/nf-shlobj_core-shgetknownfolderpath
  Orientation app_orient=application_->orientation();
 
 
 
  if (app_orient==ePortrait || app_orient==ePortraitUpsideDown){
 
    RECT rect;
 
    rect.left=0;
 
    rect.top=0;
 
    rect.right=width;
 
    rect.bottom=height;
 
 
 
    AdjustWindowRect(&rect,WS_OVERLAPPEDWINDOW,FALSE);
 
 
 
    SetWindowPos(hwndcopy,HWND_TOP,0,0,rect.right-rect.left, rect.bottom-rect.top, SWP_NOMOVE);
 
    printf("SetWindowPos: %d %d\n",rect.right-rect.left, rect.bottom-rect.top);
 
  }
 
  else {
 
    RECT rect;
 
    rect.left=0;
 
    rect.top=0;
 
    rect.right=height;
 
    rect.bottom=width;
 
 
 
    AdjustWindowRect(&rect,WS_OVERLAPPEDWINDOW,FALSE);
 
 
 
    SetWindowPos(hwndcopy,HWND_TOP,0,0,rect.right-rect.left, rect.bottom-rect.top, SWP_NOMOVE);
 
    printf("SetWindowPos: %d %d\n",rect.right-rect.left, rect.bottom-rect.top);
 
  }
 
 
 
  //application_->setHardwareOrientation(app_orient);  // previously eFixed
 
  //application_->getApplication()->setDeviceOrientation(app_orient);
 
}
 
 
 
void W32SetFullScreen(bool fullScreen,HWND wnd,W32FullScreen *save)
 
{
 
  bool for_metro=false;
 
  if (fullScreen==save->isFullScreen) return;
 
 
 
  // Save current window state if not already fullscreen.
 
  if (!save->isFullScreen) {
 
      // Save current window information.  We force the window into restored mode
 
      // before going fullscreen because Windows doesn't seem to hide the
 
      // taskbar if the window is in the maximized state.
 
  save->maximized = !!::IsZoomed(wnd);
 
      if (save->maximized)
 
        ::SendMessage(wnd, WM_SYSCOMMAND, SC_RESTORE, 0);
 
      save->style = GetWindowLong(wnd, GWL_STYLE);
 
      save->ex_style = GetWindowLong(wnd, GWL_EXSTYLE);
 
      GetWindowRect(wnd, &save->window_rect);
 
    }
 
 
 
    if (fullScreen) {
 
      // Set new window style and size.
 
      SetWindowLong(wnd, GWL_STYLE,
 
      save->style & ~(WS_CAPTION | WS_THICKFRAME));
 
      SetWindowLong(wnd, GWL_EXSTYLE,
 
      save->ex_style & ~(WS_EX_DLGMODALFRAME |
 
                    WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE));
 
 
 
      // On expand, if we're given a window_rect, grow to it, otherwise do
 
      // not resize.
 
      if (!for_metro) {
 
        MONITORINFO monitor_info;
 
        monitor_info.cbSize = sizeof(monitor_info);
 
        GetMonitorInfo(MonitorFromWindow(wnd, MONITOR_DEFAULTTONEAREST),
 
                      &monitor_info);
 
        SetWindowPos(wnd, NULL, monitor_info.rcMonitor.left, monitor_info.rcMonitor.top,
 
        monitor_info.rcMonitor.right-monitor_info.rcMonitor.left,
 
monitor_info.rcMonitor.bottom-monitor_info.rcMonitor.top,
 
                    SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
 
      }
 
    } else {
 
      // Reset original window style and size.  The multiple window size/moves
 
      // here are ugly, but if SetWindowPos() doesn't redraw, the taskbar won't be
 
      // repainted.  Better-looking methods welcome.
 
      SetWindowLong(wnd, GWL_STYLE, save->style);
 
      SetWindowLong(wnd, GWL_EXSTYLE, save->ex_style);
 
 
 
      if (!for_metro) {
 
        // On restore, resize to the previous saved rect size.
 
        SetWindowPos(wnd, NULL, save->window_rect.left,save->window_rect.top,
 
        save->window_rect.right-save->window_rect.left,
 
save->window_rect.bottom-save->window_rect.top,
 
                    SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
 
      }
 
      if (save->maximized)
 
        SendMessage(wnd, WM_SYSCOMMAND, SC_MAXIMIZE, 0);
 
    }
 
 
 
  save->isFullScreen=fullScreen;
 
}
 
 
 
static W32FullScreen saved_window_info_;
 
 
 
void setFullScreen(bool fullScreen)
 
{
 
W32SetFullScreen(fullScreen,hwndcopy,&saved_window_info_);
 
}
 
 
 
void vibrate(int ms)
 
{
 
}
 
 
 
void setKeepAwake(bool awake)
 
{
 
}
 
 
 
bool setKeyboardVisibility(bool visible){
 
return false;
 
}
 
 
 
bool setTextInput(int type,const char *buffer,int selstart,int selend,const char *label,const char *actionLabel, const char *hintText)
 
{
 
return false;
 
}
 
 
 
int setClipboard(std::string data,std::string mimeType, int luaFunc) {
 
return -1;
 
}
 
 
 
int getClipboard(std::string &data,std::string &mimeType, int luaFunc) {
 
return -1;
 
}
 
 
 
int getKeyboardModifiers() {
 
int m=0; // new 20221011 XXX
 
if (GetKeyState(VK_CONTROL)) m|=GINPUT_CTRL_MODIFIER; // new 20221011 XXX
 
if (GetKeyState(VK_SHIFT)) m|=GINPUT_SHIFT_MODIFIER; // new 20221011 XXX
 
if (GetKeyState(VK_MENU)) m|=GINPUT_ALT_MODIFIER; // new 20221011 XXX
 
// return 0;
 
return m; // new 20221011 XXX
 
}
 
 
 
static int s_fps = 60;
 
 
 
extern "C" {
 
  int g_getFps()
 
  {
 
    return s_fps;
 
  }
 
  void g_setFps(int fps)
 
  {
 
    s_fps = fps;
 
  }
 
}
 
 
 
void g_exit()
 
{
 
  exit(0);
 
}
 
 
 
bool g_checkStringProperty(bool isSet, const char* what){
 
    if (isSet){
 
        if ( (strcmp(what, "cursor") == 0)
 
            || (strcmp(what, "windowTitle") == 0)
 
            || (strcmp(what, "windowModel") == 0)
 
            || (strcmp(what, "clipboard") == 0)
 
            || (strcmp(what, "mkDir") == 0)
 
            || (strcmp(what, "documentDirectory") == 0)
 
            || (strcmp(what, "temporaryDirectory") == 0)
 
          )
 
        {
 
            return true;
 
        }else{
 
            return false;
 
        }
 
    }else{
 
        if ( (strcmp(what, "openFileDialog") == 0)
 
            || (strcmp(what, "openDirectoryDialog") == 0)
 
            || (strcmp(what, "saveFileDialog") == 0)
 
            || (strcmp(what, "directory") == 0)
 
          )
 
        {
 
            return true;
 
        }else{
 
            return false;
 
        }
 
    }
 
}
 
 
 
void g_setProperty(const char* what, const char* arg){
 
//    QString argGet = QString::fromUtf8(arg);
 
    std::string argGet = arg;
 
    int arg1 = 0;
 
    int arg2 = 0;
 
    int arg3 = 0;
 
//    QString argString = "";
 
    std::string argString = "";
 
 
 
    if ( g_checkStringProperty(true,what)){
 
        argString = argGet;
 
//        argString.replace("\\","\\\\");
 
//        std::replace(argString.begin(), argString.end(), "\\", "\\\\");
 
//        printf(argString);
 
    }else{
 
//        QStringList arrayArg = argGet.split("|",Qt::KeepEmptyParts);
 
//        std::vector<std::string> split =
 
//        QStringList arrayArg = argGet.split("|",Qt::KeepEmptyParts);
 
//        arg1 = arrayArg.at(0).toInt();
 
//        arg2 = arrayArg.at(1).toInt();
 
//        arg3 = arrayArg.at(2).toInt();
 
    }
 
 
 
  if (strcmp(what, "windowPosition") == 0) // I should move the windows here, like we do in platform-qt.cpp!
 
  {
 
//    if (args.size()>=2) {
 
      printf("*** windowPosition Y *** \n");
 
//    SetWindowPos(wnd,HWND_TOP,rect.left,rect.top, rect.right-rect.left, rect.bottom-rect.top, SWP_NOSIZE);
 
      SetWindowPos(hwndcopy,0,128,128,0,0,SWP_NOSIZE);
 
//      SetWindowPos(hwndcopy,HWND_TOP,128,128,0,0,SWP_NOSIZE);
 
  }else if (strcmp(what, "windowSize") == 0)
 
  {
 
    // XXX
 
  }
 
}
 
 
 
const char* g_getProperty(const char* what, const char* arg)
 
{
 
  if (strcmp(what,"commandLine")==0)
 
    return commandLine;
 
 
 
  return 0; // new 20221011 XXX
 
}
 
</source>
 
 
 
=== Description ===
 
Trying to add missing functions to win32 build. Refs:
 
*KNOWNFOLDERID: https://learn.microsoft.com/en-us/windows/win32/shell/knownfolderid
 
*shlobj_core.h header: https://learn.microsoft.com/en-us/windows/win32/api/shlobj_core/
 
*SHGetKnownFolderPath function (shlobj_core.h): https://learn.microsoft.com/en-us/windows/win32/api/shlobj_core/nf-shlobj_core-shgetknownfolderpath
 
 
* SO (cc-by): https://stackoverflow.com/a/50660989/870125
 
* SO (cc-by): https://stackoverflow.com/a/50660989/870125
  
 
C:\dev\gideros_hgy29\libgid\src\win32\platform-win32.cpp
 
C:\dev\gideros_hgy29\libgid\src\win32\platform-win32.cpp
<source lang="lua">
 
#include <ShlObj.h> // new 20221013 XXX
 
...
 
        }else if (strcmp(what, "directory") == 0)
 
        {
 
/* TODO
 
            QStringList acceptedValue;
 
            acceptedValue << "executable" << "document"  << "desktop" << "temporary" << "data" ;
 
            acceptedValue << "music" << "movies"  << "pictures" << "cache" << "download" ;
 
            acceptedValue << "home";
 
  
            if (args.size()>0)&&(acceptedValue.contains(args[0].s)){
 
                QString argString=args[0].s;
 
                QString pathGet = "";
 
                if (argString == "executable"){
 
                    pathGet = QDir::currentPath();
 
                }else if (argString == "document"){
 
                    pathGet = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
 
                }else if (argString == "desktop"){
 
                    pathGet = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
 
                }else if (argString == "temporary"){
 
                    pathGet = QStandardPaths::writableLocation(QStandardPaths::TempLocation);
 
                }else if (argString == "data"){
 
    #ifdef RASPBERRY_PI
 
                    pathGet = QStandardPaths::writableLocation(QStandardPaths::DataLocation);
 
    #else
 
                    pathGet = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
 
    #endif
 
                }else if (argString == "music"){
 
                    pathGet = QStandardPaths::writableLocation(QStandardPaths::MusicLocation);
 
                }else if (argString == "movies"){
 
                    pathGet = QStandardPaths::writableLocation(QStandardPaths::MoviesLocation);
 
                }else if (argString == "pictures"){
 
                    pathGet = QStandardPaths::writableLocation(QStandardPaths::PicturesLocation);
 
                }else if (argString == "cache"){
 
                    pathGet = QStandardPaths::writableLocation(QStandardPaths::CacheLocation);
 
                }else if (argString == "download"){
 
                    pathGet = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation);
 
                }else if (argString == "home"){
 
                    pathGet = QStandardPaths::writableLocation(QStandardPaths::HomeLocation);
 
  
                }else{
+
=== Convert wstring <-> string ===
 
+
platform-win32.cpp
                }
 
                r.type=gapplication_Variant::STRING;
 
                r.s=pathGet.toStdString();
 
                rets.push_back(r);
 
            }else{
 
                QString info = "Accepted value for ";
 
                info.append(what);
 
                info.append(" :");
 
                MainWindow::getInstance()->printToOutput(info.toStdString().c_str());
 
                for( int i=0; i<acceptedValue.size(); ++i ){
 
                    MainWindow::getInstance()->printToOutput( QString("- ").append(acceptedValue.at(i)).toStdString().c_str() );
 
                }
 
            }
 
*/
 
            printf("*** FOLDERID_Documents ***");
 
//        wchar_t xpath[1024];
 
//        GetWindowText(hwndcopy,xpath,1024);
 
            PWSTR  ppszPath; // variable to receive the path memory block pointer
 
            HRESULT hr = SHGetKnownFolderPath(FOLDERID_Documents, 0, NULL, &ppszPath);
 
            std::wstring myPath;
 
            if (SUCCEEDED(hr)) {
 
                myPath = ppszPath; // make a local copy of the path
 
            }
 
            CoTaskMemFree(ppszPath); // free up the path memory block
 
  
            r.type=gapplication_Variant::STRING;
+
'''refs''':
            r.s=us(myPath);
 
            rets.push_back(r);
 
            /*------------------------------------------------------------------*/
 
        }else if ((strcmp(what, "openDirectoryDialog") == 0)
 
                || (strcmp(what, "openFileDialog") == 0)
 
                || (strcmp(what, "saveFileDialog") == 0))
 
</source>
 
 
 
=== Convert wstring <-> string ===
 
 
* SO (cc-by): https://stackoverflow.com/a/18374698/870125
 
* SO (cc-by): https://stackoverflow.com/a/18374698/870125
  
 
C:\dev\gideros_hgy29\libgid\src\win32\platform-win32.cpp
 
C:\dev\gideros_hgy29\libgid\src\win32\platform-win32.cpp
<source lang="lua">
+
<source lang="c++">
 
#include <locale> // new 20221014 XXX
 
#include <locale> // new 20221014 XXX
 
#include <codecvt> // new 20221014 XXX
 
#include <codecvt> // new 20221014 XXX
Line 449: Line 45:
 
}
 
}
 
</source>
 
</source>
 +
  
 
=== win32 minimum, maximum screen size ===
 
=== win32 minimum, maximum screen size ===
https://www.youtube.com/watch?v=-kg4TG7GoYI
+
platform-win32.cpp
 +
 
 +
'''refs''':
 +
* https://www.youtube.com/watch?v=-kg4TG7GoYI
 
* https://gamedev.net/forums/topic/569148-c-windows-api-minimum-resize-dimensions/4638297/
 
* https://gamedev.net/forums/topic/569148-c-windows-api-minimum-resize-dimensions/4638297/
 
* SO (cc-by): https://stackoverflow.com/q/19035481/870125
 
* SO (cc-by): https://stackoverflow.com/q/19035481/870125
Line 459: Line 59:
  
 
C:\dev\gideros_hgy29\libgid\src\win32\platform-win32.cpp
 
C:\dev\gideros_hgy29\libgid\src\win32\platform-win32.cpp
<source lang="lua">
+
<source lang="c++">
 
</source>
 
</source>
 +
  
 
=== win32 LFS problem with separator ===
 
=== win32 LFS problem with separator ===
Line 472: Line 73:
 
slash direction for file-paths.
 
slash direction for file-paths.
  
<source lang="lua">
+
<source lang="c++">
 
  * \note If you want a trailing slash, add `SEP_STR` as the last path argument,
 
  * \note If you want a trailing slash, add `SEP_STR` as the last path argument,
 
  * duplicate slashes will be cleaned up.
 
  * duplicate slashes will be cleaned up.
Line 485: Line 86:
 
</source>
 
</source>
  
<source lang="lua">
+
<source lang="c++">
 
#define SEP_CHR    '#'
 
#define SEP_CHR    '#'
 
#define SEP_STR    "#"
 
#define SEP_STR    "#"
Line 501: Line 102:
 
   if (found_ofs + len_num + len_move > len_max) {
 
   if (found_ofs + len_num + len_move > len_max) {
 
</source>
 
</source>
 
 
  
  
Line 508: Line 107:
 
platform-win32.cpp
 
platform-win32.cpp
  
'''ref''': '''https://learn.microsoft.com/en-us/windows/win32/learnwin32/learn-to-program-for-windows'''
+
'''refs''':
 +
* '''https://learn.microsoft.com/en-us/windows/win32/learnwin32/learn-to-program-for-windows'''
 +
* '''https://weblogs.asp.net/kennykerr/Windows-Vista-for-Developers-_1320_-Part-6-_1320_-The-New-File-Dialogs'''
 +
* '''https://www.codeproject.com/Articles/16678/Vista-Goodies-in-C-Using-the-New-Vista-File-Dialog'''
 +
* '''https://learn.microsoft.com/en-us/windows/win32/shell/common-file-dialog'''
 
<source lang="c++">
 
<source lang="c++">
         }else if (strcmp(what, "openDirectoryDialog") == 0)
+
#include <wchar.h> // new 20221026 XXX
 +
...
 +
         }else if ((strcmp(what, "openDirectoryDialog") == 0)
 +
                || (strcmp(what, "openFileDialog") == 0)
 +
                || (strcmp(what, "saveFileDialog") == 0))
 
         {
 
         {
          /* TODO */
+
        /* TODO parse extension :-( */
             /*------------------------------------------------------------------*/
+
             // for win32 args ("title|path|extensions//help") is only 1 arg
 +
            // unlike Qt which seems to cut the | into different args
 +
            if(args.size() == 1){ // do we need to deal with "help" as arg or leave it to Qt?
 +
                // we cut the args
 +
                std::wstring s=ws(args[0].s.c_str()); // "Title|c:\\tmp|Text (*.txt);; Image (*.png)"
 +
                size_t index = s.find(L"|");
 +
                size_t index2 = s.find(L"|", index+1);
 +
                std::wstring title = s.substr(0, index);
 +
                std::wstring place = s.substr(index+1, index2-index-1);
 +
                std::wstring extension = s.substr(index2+1);
 +
//                printf("t p e:\n %ls\n %ls\n %ls\n", title.c_str(),place.c_str(),extension.c_str()); // TEST OK
  
        }else if (strcmp(what, "openFileDialog") == 0)
+
                DWORD dwFlags; // new 20221028 XXX
        {
 
            /* TODO */
 
            if (args.size()>0)
 
            {
 
 
                 HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
 
                 HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
 
                 if (SUCCEEDED(hr))
 
                 if (SUCCEEDED(hr))
 
                 {
 
                 {
                     IFileOpenDialog *pFile;
+
                     if (strcmp(what, "openDirectoryDialog") == 0){
 +
                        /* TO DO */
 +
                        /*--------------------------------------------------*/
 +
                    }else if (strcmp(what, "openFileDialog") == 0){
 +
                        IFileOpenDialog *pFile;
 +
                        COMDLG_FILTERSPEC fileTypes[] = /* TODO parse from wstring extension :-( */
 +
                        {
 +
                            { L"Text Documents", L"*.txt" },
 +
                            { L"All Files", L"*.*" },
 +
                        };
  
                    // Create the FileOpenDialog object.
+
                        // Create the FileOpenDialog object.
                    hr = CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_ALL,  
+
                        hr = CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_ALL,  
                            IID_IFileOpenDialog, reinterpret_cast<void**>(&pFile));
+
                                IID_IFileOpenDialog, reinterpret_cast<void**>(&pFile));
 
 
                    if (SUCCEEDED(hr))
 
                    {
 
                        // Show the Open dialog box.
 
                        hr = pFile->Show(NULL);
 
 
 
                        // Get the file name from the dialog box.
 
 
                         if (SUCCEEDED(hr))
 
                         if (SUCCEEDED(hr))
 
                         {
 
                         {
                             IShellItem *pItem;
+
                            // get/set options
                             hr = pFile->GetResult(&pItem);
+
                            pFile->GetOptions(&dwFlags);
 +
                            pFile->SetOptions(dwFlags | FOS_FORCEFILESYSTEM);
 +
                            pFile->SetFileTypes(ARRAYSIZE(fileTypes), fileTypes); // SEE ABOVE fileTypes
 +
                            pFile->SetFileTypeIndex(1); // index starts at 1
 +
//                            pFile->SetDefaultExtension(L"obj;fbx"); // XXX
 +
                            hr = pFile->SetTitle(title.c_str()); // need more check?
 +
 
 +
                            // set starting folder
 +
                             IShellItem *pItem = NULL;
 +
                             hr = SHCreateItemFromParsingName(place.c_str(), NULL, IID_IShellItem, (LPVOID *)&pItem);
 
                             if (SUCCEEDED(hr))
 
                             if (SUCCEEDED(hr))
 
                             {
 
                             {
                                 PWSTR pszFilePath;
+
                                 pFile->SetFolder(pItem);
                                 hr = pItem->GetDisplayName(SIGDN_FILESYSPATH, &pszFilePath);
+
                                 pItem->Release();
 +
                                pItem = NULL;
 +
                            }
  
                                // Display the file name to the user.
+
                            // Show the Open dialog box.
 +
                            hr = pFile->Show(NULL);
 +
                            // Get the file name from the dialog box.
 +
                            if (SUCCEEDED(hr))
 +
                            {
 +
                                IShellItem *pItem;
 +
                                hr = pFile->GetResult(&pItem);
 
                                 if (SUCCEEDED(hr))
 
                                 if (SUCCEEDED(hr))
 
                                 {
 
                                 {
//                                  MessageBoxW(NULL, pszFilePath, L"File Path", MB_OK);
+
                                    PWSTR pszFilePath;
                                     r.type=gapplication_Variant::STRING;
+
                                    hr = pItem->GetDisplayName(SIGDN_FILESYSPATH, &pszFilePath);
                                    r.s=us(pszFilePath);
+
                                     if (SUCCEEDED(hr))
                                    rets.push_back(r);
+
                                    {
 +
                                        r.type=gapplication_Variant::STRING;
 +
                                        r.s=us(pszFilePath);
 +
                                        rets.push_back(r);
  
                                    CoTaskMemFree(pszFilePath);
+
                                        CoTaskMemFree(pszFilePath);
 +
                                    }
 +
                                    pItem->Release();
 
                                 }
 
                                 }
                                pItem->Release();
 
 
                             }
 
                             }
 +
                            pFile->Release();
 
                         }
 
                         }
                         pFile->Release();
+
                         CoUninitialize();
 +
                        /*--------------------------------------------------*/
 +
                    }else if (strcmp(what, "saveFileDialog") == 0){
 +
                        /* TO DO */
 +
                        /*--------------------------------------------------*/
 
                     }
 
                     }
                    CoUninitialize();
 
 
                 }
 
                 }
 
             }
 
             }
 
             /*------------------------------------------------------------------*/
 
             /*------------------------------------------------------------------*/
 +
        }else if (strcmp(what, "temporaryDirectory") == 0)
 +
</source>
 +
 +
=== openFileDialog Latest ===
 +
platform-win32.cpp ('''updated and working piece of code''')
 +
 +
'''Added''':
 +
* append file extension to saved files (1st extension from filters)
 +
 +
<source lang="c++">
 +
        }else if ((strcmp(what, "openDirectoryDialog") == 0)
 +
                || (strcmp(what, "openFileDialog") == 0)
 +
                || (strcmp(what, "saveFileDialog") == 0))
 +
            {
 +
            if(args.size() <= 2){
 +
                /* INFO SHOWN IN GIDEROS STUDIO DEBUGGER, IMPLEMENTED IN QT, NOT NEEDED HERE? */
 +
            }
 +
            else
 +
            {
 +
                std::wstring title = ws(args[0].s.c_str());
 +
                std::wstring place = ws(args[1].s.c_str());
 +
                std::vector<std::pair<std::wstring,std::wstring>> filters;
 +
                if (args.size()>=3) {
 +
                std::wstring ext = ws(args[2].s.c_str());
 +
                while (!ext.empty()) {
 +
                    std::wstring next;
 +
                size_t semicolon=ext.find(L";;");
 +
                if (semicolon!=std::wstring::npos) {
 +
                next=ext.substr(semicolon+2);
 +
                ext=ext.substr(0,semicolon);
 +
                }
 +
                size_t p1=ext.find_first_of(L'(');
 +
                size_t p2=ext.find_last_of(L')');
 +
                if ((p1!=std::wstring::npos)&&(p2!=std::wstring::npos)&&(p2>p1))
 +
                {
 +
                //Valid filter, extract label and extensions
 +
                std::wstring label=ext.substr(0,p1);
 +
                std::wstring exts=ext.substr(p1+1,p2-p1-1);
 +
                //QT uses space for extensions separator, while windows expects semicolon. Convert them.
 +
                std::replace(exts.begin(),exts.end(),L' ',L';');
 +
                filters.push_back(std::pair<std::wstring,std::wstring>(label,exts));
 +
                }
 +
                ext=next;
 +
                }
 +
                }
 +
 +
                DWORD dwFlags;
 +
                HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
 +
                if (SUCCEEDED(hr))
 +
                {
 +
                    COMDLG_FILTERSPEC *fileTypes=new COMDLG_FILTERSPEC[filters.size()];
 +
                    for (size_t i=0;i<filters.size();i++) {
 +
                    fileTypes[i].pszName=filters[i].first.c_str();
 +
                    fileTypes[i].pszSpec=filters[i].second.c_str();
 +
                    }
 +
                    IFileDialog *pFile;
 +
if (strcmp(what, "saveFileDialog") == 0)
 +
                        hr = CoCreateInstance(CLSID_FileSaveDialog, NULL, CLSCTX_ALL,
 +
                                IID_IFileSaveDialog, reinterpret_cast<void**>(&pFile));
 +
else
 +
                        hr = CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_ALL,
 +
                                IID_IFileOpenDialog, reinterpret_cast<void**>(&pFile));
 +
if (SUCCEEDED(hr))
 +
{
 +
bool isFolder=(strcmp(what, "openDirectoryDialog") == 0);
 +
// get/set options
 +
pFile->GetOptions(&dwFlags);
 +
pFile->SetOptions(dwFlags | FOS_FORCEFILESYSTEM | (isFolder?FOS_PICKFOLDERS:0));
 +
if (!isFolder) {
 +
pFile->SetFileTypes(filters.size(), fileTypes);
 +
pFile->SetFileTypeIndex(1); // index starts at 1
 +
//pFile->SetDefaultExtension(L"obj;fbx"); // append default extension
 +
                            //printf("* fileTypes *, set default extension to %ls\n", fileTypes[0].pszSpec); OK
 +
pFile->SetDefaultExtension(fileTypes[0].pszSpec); // append default 1st extension
 +
}
 +
hr = pFile->SetTitle(title.c_str()); // need more check?
 +
 +
// set starting folder
 +
IShellItem *pItem = NULL;
 +
hr = SHCreateItemFromParsingName(place.c_str(), NULL, IID_IShellItem, (LPVOID *)&pItem);
 +
if (SUCCEEDED(hr))
 +
{
 +
pFile->SetFolder(pItem);
 +
pItem->Release();
 +
pItem = NULL;
 +
}
 +
 +
// Show the Open dialog box.
 +
hr = pFile->Show(NULL);
 +
// Get the file name from the dialog box.
 +
if (SUCCEEDED(hr))
 +
{
 +
IShellItem *pItem;
 +
hr = pFile->GetResult(&pItem);
 +
if (SUCCEEDED(hr))
 +
{
 +
PWSTR pszFilePath;
 +
hr = pItem->GetDisplayName(SIGDN_FILESYSPATH, &pszFilePath);
 +
if (SUCCEEDED(hr))
 +
{
 +
r.type=gapplication_Variant::STRING;
 +
r.s=us(pszFilePath);
 +
rets.push_back(r);
 +
 +
CoTaskMemFree(pszFilePath);
 +
}
 +
pItem->Release();
 +
}
 +
}
 +
pFile->Release();
 +
}
 +
                CoUninitialize();
 +
                delete[] fileTypes;
 +
                }
 +
            }
 +
            /*------------------------------------------------------------------*/
 +
        }else if (strcmp(what, "temporaryDirectory") == 0)
 +
</source>
 +
 +
 +
=== Locate first occurrence of character in wide string ===
 +
platform-win32.cpp
 +
 +
'''refs''':
 +
* https://cplusplus.com/reference/cwchar/wcschr/
 +
* https://cplusplus.com/reference/string/string/find/
 +
<source lang="c++">
 +
std::wstring gs=ws(args[0].s.c_str()); // "Title|C:/tmp/|Text (*.txt);; Image (*.png)"
 +
size_t index = gs.find(L"|");
 +
size_t index2 = gs.find(L"|", index+1);
 +
printf("args0: %ls\n", gs.c_str()); // output: Title|C:/tmp/|Text (*.txt);; Image (*.png)
 +
printf("indices: %d, %d\n", index,index2); // output 5, 13
 +
std::wstring title = gs.substr(0, index);
 +
std::wstring path = gs.substr(index+1, index2-index-1);
 +
std::wstring exts = gs.substr(index2+1);
 +
printf("t p e:\n %ls\n %ls\n %ls\n", title.c_str(),path.c_str(),exts.c_str()); // Title C:/tmp/ Text (*.txt);; Image (*.png)
 +
</source>
 +
 +
 +
=== application:getKeyboardModifiers() ===
 +
platform-win32.cpp
 +
 +
'''refs''':
 +
* SO (cc-by): https://stackoverflow.com/questions/1811206/on-win32-how-to-detect-whether-a-left-shift-or-right-alt-is-pressed-using-perl
 +
<source lang="c++">
 +
if(GetAsyncKeyState(VK_LSHIFT) & 0x8000)
 +
    ; // left shift is currently down
 +
</source>
 +
 +
 +
=== mkDir ===
 +
platform-win32.cpp
 +
 +
'''Tested and seems ok :-)'''
 +
 +
'''refs''':
 +
* '''https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/mkdir-wmkdir?view=msvc-170'''
 +
<source lang="c++">
 +
        }else if (strcmp(what, "mkDir") == 0)
 +
        {
 +
            // new 20221114 XXX
 +
            std::wstring dir = ws(args[0].s.c_str());
 +
            if (_wmkdir(dir.c_str()) == 0)
 +
                printf("mkDir OK: %S\n", dir.c_str()); // can be useful for the w32 console
 +
            else
 +
                printf("mkDir failed or Dir may already exist: %S\n", dir.c_str()); // can be useful for the w32 console
 +
            /*------------------------------------------------------------------*/
 +
        }else if (strcmp(what, "documentDirectory") == 0)
 +
</source>
 +
 +
 +
=== pathfileexists ===
 +
platform-win32.cpp
 +
 +
'''Tested and seems ok but not sure about what the return value should be :-/ and we can also check for access mode!'''
 +
 +
'''refs''':
 +
* SO (cc-by): https://stackoverflow.com/a/28011583/870125
 +
* https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/access-waccess?view=msvc-170
 +
<source lang="c++">
 +
        }else if (strcmp(what, "pathfileexists") == 0) // new 20221116 XXX
 +
        {
 +
            if (args.size() > 0) {
 +
                std::wstring path = ws(args[0].s.c_str());
 +
                int retValue;
 +
                if (_waccess(path.c_str(), 0) == 0) { // modes: 0=Existence only, 2=Write-only, 4=Read-only, 6=Read and write
 +
                    // path exists
 +
                    retValue = 1;
 +
                } else {
 +
                    retValue = 0;
 +
                }
 +
                r.type=gapplication_Variant::DOUBLE;
 +
                r.d=retValue;
 +
                rets.push_back(r);
 +
            }
 +
            /*------------------------------------------------------------------*/
 +
        }else if ((strcmp(what, "openDirectoryDialog") == 0)
 +
</source>
  
         }else if (strcmp(what, "saveFileDialog") == 0)
+
=== pathfileexists Qt ===
 +
platform-qt.cpp
 +
 
 +
QFile Class seems to be "kind of" the equivalent?
 +
 
 +
'''refs''':
 +
* https://doc.qt.io/qt-6/qfile.html
 +
 
 +
bool '''QFile::exists'''(const QString &fileName)
 +
Returns true if the file specified by fileName exists; otherwise returns false.
 +
Note: If fileName is a symlink that points to a non-existing file, false is returned.
 +
 
 +
I will need to mix this and _waccess.
 +
 
 +
=== WM_GETMINMAXINFO ===
 +
win32.cpp
 +
 
 +
'''WIP'''
 +
 
 +
'''refs''':
 +
* SO (cc-by): https://stackoverflow.com/questions/22261804/how-to-set-minimum-window-size-using-winapi
 +
* https://learn.microsoft.com/en-gb/windows/win32/winmsg/wm-getminmaxinfo?redirectedfrom=MSDN
 +
<source lang="c++">
 +
</source>
 +
 
 +
 
 +
=== LoadCursorA ===
 +
platform-win32.cpp
 +
 
 +
'''WIP'''
 +
 
 +
'''refs''':
 +
* SO (cc-by): https://stackoverflow.com/questions/19257237/reset-cursor-in-wm-setcursor-handler-properly
 +
* https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-loadcursora
 +
<source lang="c++">
 +
    else { // SET
 +
        if (strcmp(what, "cursor") == 0)
 +
        {
 +
        /* TODO */
 +
            std::string &shape = args[0].s;
 +
//            QStringList acceptedValue;
 +
//            acceptedValue << "arrow" << "upArrow" << "cross" << "wait" << "IBeam";
 +
//            acceptedValue << "sizeVer" << "sizeHor" << "sizeBDiag" << "sizeFDiag" << "sizeAll";
 +
//            acceptedValue << "blank" << "splitV" << "splitH" << "pointingHand" << "forbidden";
 +
//            acceptedValue << "whatsThis" << "busy" << "openHand" << "closedHand" << "dragCopy";
 +
//            acceptedValue << "dragMove" << "dragLink";
 +
            HCURSOR cursor;
 +
            if (shape == "arrow") {
 +
                printf("** cursor arrow\n");
 +
                cursor = LoadCursorA(NULL, (LPCSTR)IDC_ARROW);
 +
                SetCursor(cursor);
 +
            } else if (shape == "upArrow") {
 +
                printf("** cursor uparrow\n"); // LUA DEBUG OK BUT ARROW SHAPE DOESN'T CHANGE :-(
 +
                cursor = LoadCursorA(NULL, (LPCSTR)IDC_UPARROW);
 +
                SetCursor(cursor);
 +
            }
 +
            /*------------------------------------------------------------------*/
 +
         }else if (strcmp(what, "windowPosition") == 0)
 
</source>
 
</source>
  
 +
=== modal windows dialog ===
 +
'''Test01'''
 +
 +
'''refs''':
 +
*'''https://learn.microsoft.com/en-us/windows/win32/dlgbox/using-dialog-boxes#creating-a-modeless-dialog-box'''
 +
*'''https://learn.microsoft.com/en-us/windows/win32/api/olectl/nf-olectl-olecreatepropertyframe#remarks'''
 +
 +
C:\dev\gideros_dev\libgid\src\win32\platform-win32.cpp
 +
<source lang="c++">
 +
                    COMDLG_FILTERSPEC *fileTypes=new COMDLG_FILTERSPEC[filters.size()];
 +
                    for (size_t i=0;i<filters.size();i++) {
 +
                    fileTypes[i].pszName=filters[i].first.c_str();
 +
                    fileTypes[i].pszSpec=filters[i].second.c_str();
 +
                    }
 +
                    IFileDialog *pFile;
 +
if (strcmp(what, "saveFileDialog") == 0)
 +
//                        hr = CoCreateInstance(CLSID_FileSaveDialog, NULL, CLSCTX_ALL,
 +
//                                IID_IFileSaveDialog, reinterpret_cast<void**>(&pFile));
 +
                        hr = CoCreateInstance(CLSID_FileSaveDialog, hwndcopy, CLSCTX_ALL,
 +
                                IID_IFileSaveDialog, reinterpret_cast<void**>(&pFile));
 +
else
 +
//                        hr = CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_ALL,
 +
//                                IID_IFileOpenDialog, reinterpret_cast<void**>(&pFile));
 +
                        hr = CoCreateInstance(CLSID_FileOpenDialog, hwndcopy, CLSCTX_ALL,
 +
                                IID_IFileOpenDialog, reinterpret_cast<void**>(&pFile));
 +
if (SUCCEEDED(hr))
 +
{
 +
</source>
  
 +
== CBUMP ==
  
 +
=== the TODOs ===
 +
bump.cpp
  
 +
<source lang="c++">
 +
static bool rect_getSegmentIntersectionIndices(double x, double y, double w,
 +
double h, double x1, double y1, double x2, double y2, double &ti1,
 +
double &ti2, double &nx1, double &ny1, double &nx2, double &ny2) {
 +
//ti1, ti2 = ti1 or 0, ti2 or 1 TODO
 +
double dx = x2 - x1;
 +
double dy = y2 - y1;
 +
...
 +
</source>
  
 +
<source lang="c++">
 +
static bool rect_detectCollision(double x1, double y1, double w1, double h1,
 +
double x2, double y2, double w2, double h2, double goalX, double goalY,
 +
Collision &col) {
 +
//goalX = goalX or x1 TODO
 +
//goalY = goalY or y1
  
 +
double dx = goalX - x1, dy = goalY - y1;
 +
...
 +
</source>
 +
It is time to do the TODOs ;-)
  
  
 
{{GIDEROS IMPORTANT LINKS}}
 
{{GIDEROS IMPORTANT LINKS}}

Revision as of 03:56, 15 February 2023

Here you will find various resources to help learn C++ for people who wish to help with Gideros Studio development.

WIN32

KNOWNFOLDERID

platform-win32.cpp

refs:

C:\dev\gideros_hgy29\libgid\src\win32\platform-win32.cpp


Convert wstring <-> string

platform-win32.cpp

refs:

C:\dev\gideros_hgy29\libgid\src\win32\platform-win32.cpp

#include <locale> // new 20221014 XXX
#include <codecvt> // new 20221014 XXX

...

std::wstring s2ws(const std::string& str)
{
    using convert_typeX = std::codecvt_utf8<wchar_t>;
    std::wstring_convert<convert_typeX, wchar_t> converterX;

    return converterX.from_bytes(str);
}

std::string ws2s(const std::wstring& wstr)
{
    using convert_typeX = std::codecvt_utf8<wchar_t>;
    std::wstring_convert<convert_typeX, wchar_t> converterX;

    return converterX.to_bytes(wstr);
}


win32 minimum, maximum screen size

platform-win32.cpp

refs:

C:\dev\gideros_hgy29\libgid\src\win32\platform-win32.cpp


win32 LFS problem with separator

Recent changes to path handling (most likely [0]) caused AssetCatalogTest.create_catalog_after_loading_file to fail on WIN32.

The test relied on the resulting path to be joined with "/" as a path separator. The resulting path used both forward and back-slashes. While these do work for some API's on WIN32, mixing both in a file path isn't expected behavior in most cases, so update the tests to use native slash direction for file-paths.

 * \note If you want a trailing slash, add `SEP_STR` as the last path argument,
 * duplicate slashes will be cleaned up.
 */
size_t BLI_path_join(char *__restrict dst, size_t dst_len, const char *path, ...)
#  define SEP '\\'
#  define ALTSEP '/'
#  define SEP_STR "\\"
#  define ALTSEP_STR "/"
#else
#  define SEP '/'
#define SEP_CHR     '#'
#define SEP_STR     "#"

#define EPS 0.001

#define UN_SC_KM    1000.0f
#define UN_SC_HM    100.0f
      str_tmp, TEMP_STR_SIZE, "*%.9g" SEP_STR, unit->scalar / scale_pref);

  if (len_num > len_max) {
    len_num = len_max;
  }

  if (found_ofs + len_num + len_move > len_max) {


openFileDialog

platform-win32.cpp

refs:

#include <wchar.h> // new 20221026 XXX
...
        }else if ((strcmp(what, "openDirectoryDialog") == 0)
                || (strcmp(what, "openFileDialog") == 0)
                || (strcmp(what, "saveFileDialog") == 0))
        {
        	/* TODO parse extension :-( */
            // for win32 args ("title|path|extensions//help") is only 1 arg
            // unlike Qt which seems to cut the | into different args
            if(args.size() == 1){ // do we need to deal with "help" as arg or leave it to Qt?
                // we cut the args
                std::wstring s=ws(args[0].s.c_str()); // "Title|c:\\tmp|Text (*.txt);; Image (*.png)"
                size_t index = s.find(L"|");
                size_t index2 = s.find(L"|", index+1);
                std::wstring title = s.substr(0, index);
                std::wstring place = s.substr(index+1, index2-index-1);
                std::wstring extension = s.substr(index2+1);
//                printf("t p e:\n %ls\n %ls\n %ls\n", title.c_str(),place.c_str(),extension.c_str()); // TEST OK

                DWORD dwFlags; // new 20221028 XXX
                HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
                if (SUCCEEDED(hr))
                {
                    if (strcmp(what, "openDirectoryDialog") == 0){
                        /* TO DO */
                        /*--------------------------------------------------*/
                    }else if (strcmp(what, "openFileDialog") == 0){
                        IFileOpenDialog *pFile;
                        COMDLG_FILTERSPEC fileTypes[] = /* TODO parse from wstring extension :-( */
                        {
                            { L"Text Documents", L"*.txt" },
                            { L"All Files", L"*.*" },
                        };

                        // Create the FileOpenDialog object.
                        hr = CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_ALL, 
                                IID_IFileOpenDialog, reinterpret_cast<void**>(&pFile));
                        if (SUCCEEDED(hr))
                        {
                            // get/set options
                            pFile->GetOptions(&dwFlags);
                            pFile->SetOptions(dwFlags | FOS_FORCEFILESYSTEM);
                            pFile->SetFileTypes(ARRAYSIZE(fileTypes), fileTypes); // SEE ABOVE fileTypes
                            pFile->SetFileTypeIndex(1); // index starts at 1
//                            pFile->SetDefaultExtension(L"obj;fbx"); // XXX
                            hr = pFile->SetTitle(title.c_str()); // need more check?

                            // set starting folder
                            IShellItem *pItem = NULL;
                            hr = SHCreateItemFromParsingName(place.c_str(), NULL, IID_IShellItem, (LPVOID *)&pItem);
                            if (SUCCEEDED(hr))
                            {
                                pFile->SetFolder(pItem);
                                pItem->Release();
                                pItem = NULL;
                            }

                            // Show the Open dialog box.
                            hr = pFile->Show(NULL);
                            // Get the file name from the dialog box.
                            if (SUCCEEDED(hr))
                            {
                                IShellItem *pItem;
                                hr = pFile->GetResult(&pItem);
                                if (SUCCEEDED(hr))
                                {
                                    PWSTR pszFilePath;
                                    hr = pItem->GetDisplayName(SIGDN_FILESYSPATH, &pszFilePath);
                                    if (SUCCEEDED(hr))
                                    {
                                        r.type=gapplication_Variant::STRING;
                                        r.s=us(pszFilePath);
                                        rets.push_back(r);

                                        CoTaskMemFree(pszFilePath);
                                    }
                                    pItem->Release();
                                }
                            }
                            pFile->Release();
                        }
                        CoUninitialize();
                        /*--------------------------------------------------*/
                    }else if (strcmp(what, "saveFileDialog") == 0){
                        /* TO DO */
                        /*--------------------------------------------------*/
                    }
                }
            }
            /*------------------------------------------------------------------*/
        }else if (strcmp(what, "temporaryDirectory") == 0)

openFileDialog Latest

platform-win32.cpp (updated and working piece of code)

Added:

  • append file extension to saved files (1st extension from filters)
        }else if ((strcmp(what, "openDirectoryDialog") == 0)
                || (strcmp(what, "openFileDialog") == 0)
                || (strcmp(what, "saveFileDialog") == 0))
            {
            if(args.size() <= 2){
                /* INFO SHOWN IN GIDEROS STUDIO DEBUGGER, IMPLEMENTED IN QT, NOT NEEDED HERE? */
            }
            else
            {
                std::wstring title = ws(args[0].s.c_str());
                std::wstring place = ws(args[1].s.c_str());
                std::vector<std::pair<std::wstring,std::wstring>> filters;
                if (args.size()>=3) {
                	std::wstring ext = ws(args[2].s.c_str());
                	while (!ext.empty()) {
                    	std::wstring next;
                		size_t semicolon=ext.find(L";;");
                		if (semicolon!=std::wstring::npos) {
                			next=ext.substr(semicolon+2);
                			ext=ext.substr(0,semicolon);
                		}
                		size_t p1=ext.find_first_of(L'(');
                		size_t p2=ext.find_last_of(L')');
                		if ((p1!=std::wstring::npos)&&(p2!=std::wstring::npos)&&(p2>p1))
                		{
                			//Valid filter, extract label and extensions
                			std::wstring label=ext.substr(0,p1);
                			std::wstring exts=ext.substr(p1+1,p2-p1-1);
                			//QT uses space for extensions separator, while windows expects semicolon. Convert them.
                			std::replace(exts.begin(),exts.end(),L' ',L';');
                			filters.push_back(std::pair<std::wstring,std::wstring>(label,exts));
                		}
                		ext=next;
                	}
                }

                DWORD dwFlags;
                HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
                if (SUCCEEDED(hr))
                {
                    COMDLG_FILTERSPEC *fileTypes=new COMDLG_FILTERSPEC[filters.size()];
                    for (size_t i=0;i<filters.size();i++) {
                    	fileTypes[i].pszName=filters[i].first.c_str();
                    	fileTypes[i].pszSpec=filters[i].second.c_str();
                    }
                    IFileDialog *pFile;
					if (strcmp(what, "saveFileDialog") == 0)
                        hr = CoCreateInstance(CLSID_FileSaveDialog, NULL, CLSCTX_ALL,
                                IID_IFileSaveDialog, reinterpret_cast<void**>(&pFile));
					else
                        hr = CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_ALL,
                                IID_IFileOpenDialog, reinterpret_cast<void**>(&pFile));
					if (SUCCEEDED(hr))
					{
						bool isFolder=(strcmp(what, "openDirectoryDialog") == 0);
						// get/set options
						pFile->GetOptions(&dwFlags);
						pFile->SetOptions(dwFlags | FOS_FORCEFILESYSTEM | (isFolder?FOS_PICKFOLDERS:0));
						if (!isFolder) {
							pFile->SetFileTypes(filters.size(), fileTypes);
							pFile->SetFileTypeIndex(1); // index starts at 1
							//pFile->SetDefaultExtension(L"obj;fbx"); // append default extension
                            //printf("* fileTypes *, set default extension to %ls\n", fileTypes[0].pszSpec); OK
							pFile->SetDefaultExtension(fileTypes[0].pszSpec); // append default 1st extension
						}
						hr = pFile->SetTitle(title.c_str()); // need more check?

						// set starting folder
						IShellItem *pItem = NULL;
						hr = SHCreateItemFromParsingName(place.c_str(), NULL, IID_IShellItem, (LPVOID *)&pItem);
						if (SUCCEEDED(hr))
						{
							pFile->SetFolder(pItem);
							pItem->Release();
							pItem = NULL;
						}

						// Show the Open dialog box.
						hr = pFile->Show(NULL);
						// Get the file name from the dialog box.
						if (SUCCEEDED(hr))
						{
							IShellItem *pItem;
							hr = pFile->GetResult(&pItem);
							if (SUCCEEDED(hr))
							{
								PWSTR pszFilePath;
								hr = pItem->GetDisplayName(SIGDN_FILESYSPATH, &pszFilePath);
								if (SUCCEEDED(hr))
								{
									r.type=gapplication_Variant::STRING;
									r.s=us(pszFilePath);
									rets.push_back(r);

									CoTaskMemFree(pszFilePath);
								}
								pItem->Release();
							}
						}
						pFile->Release();
					}
	                CoUninitialize();
	                delete[] fileTypes;
                }
            }
            /*------------------------------------------------------------------*/
        }else if (strcmp(what, "temporaryDirectory") == 0)


Locate first occurrence of character in wide string

platform-win32.cpp

refs:

std::wstring gs=ws(args[0].s.c_str()); // "Title|C:/tmp/|Text (*.txt);; Image (*.png)"
size_t index = gs.find(L"|");
size_t index2 = gs.find(L"|", index+1);
printf("args0: %ls\n", gs.c_str()); // output: Title|C:/tmp/|Text (*.txt);; Image (*.png)
printf("indices: %d, %d\n", index,index2); // output 5, 13
std::wstring title = gs.substr(0, index);
std::wstring path = gs.substr(index+1, index2-index-1);
std::wstring exts = gs.substr(index2+1);
printf("t p e:\n %ls\n %ls\n %ls\n", title.c_str(),path.c_str(),exts.c_str()); // Title C:/tmp/ Text (*.txt);; Image (*.png)


application:getKeyboardModifiers()

platform-win32.cpp

refs:

if(GetAsyncKeyState(VK_LSHIFT) & 0x8000)
    ; // left shift is currently down


mkDir

platform-win32.cpp

Tested and seems ok :-)

refs:

        }else if (strcmp(what, "mkDir") == 0)
        {
            // new 20221114 XXX
            std::wstring dir = ws(args[0].s.c_str());
            if (_wmkdir(dir.c_str()) == 0)
                printf("mkDir OK: %S\n", dir.c_str()); // can be useful for the w32 console
            else
                printf("mkDir failed or Dir may already exist: %S\n", dir.c_str()); // can be useful for the w32 console
            /*------------------------------------------------------------------*/
        }else if (strcmp(what, "documentDirectory") == 0)


pathfileexists

platform-win32.cpp

Tested and seems ok but not sure about what the return value should be :-/ and we can also check for access mode!

refs:

        }else if (strcmp(what, "pathfileexists") == 0) // new 20221116 XXX
        {
            if (args.size() > 0) {
                std::wstring path = ws(args[0].s.c_str());
                int retValue;
                if (_waccess(path.c_str(), 0) == 0) { // modes: 0=Existence only, 2=Write-only, 4=Read-only, 6=Read and write
                    // path exists
                    retValue = 1;
                } else {
                    retValue = 0;
                }
                r.type=gapplication_Variant::DOUBLE;
                r.d=retValue;
                rets.push_back(r);
            }
            /*------------------------------------------------------------------*/
        }else if ((strcmp(what, "openDirectoryDialog") == 0)

pathfileexists Qt

platform-qt.cpp

QFile Class seems to be "kind of" the equivalent?

refs:

bool QFile::exists(const QString &fileName) Returns true if the file specified by fileName exists; otherwise returns false. Note: If fileName is a symlink that points to a non-existing file, false is returned.

I will need to mix this and _waccess.

WM_GETMINMAXINFO

win32.cpp

WIP

refs:


LoadCursorA

platform-win32.cpp

WIP

refs:

    else { // SET
        if (strcmp(what, "cursor") == 0)
        {
        	/* TODO */
            std::string &shape = args[0].s;
//            QStringList acceptedValue;
//            acceptedValue << "arrow" << "upArrow" << "cross" << "wait" << "IBeam";
//            acceptedValue << "sizeVer" << "sizeHor" << "sizeBDiag" << "sizeFDiag" << "sizeAll";
//            acceptedValue << "blank" << "splitV" << "splitH" << "pointingHand" << "forbidden";
//            acceptedValue << "whatsThis" << "busy" << "openHand" << "closedHand" << "dragCopy";
//            acceptedValue << "dragMove" << "dragLink";
            HCURSOR cursor;
            if (shape == "arrow") {
                printf("** cursor arrow\n");
                cursor = LoadCursorA(NULL, (LPCSTR)IDC_ARROW);
                SetCursor(cursor);
            } else if (shape == "upArrow") {
                printf("** cursor uparrow\n"); // LUA DEBUG OK BUT ARROW SHAPE DOESN'T CHANGE :-(
                cursor = LoadCursorA(NULL, (LPCSTR)IDC_UPARROW);
                SetCursor(cursor);
            }
            /*------------------------------------------------------------------*/
        }else if (strcmp(what, "windowPosition") == 0)

modal windows dialog

Test01

refs:

C:\dev\gideros_dev\libgid\src\win32\platform-win32.cpp

                    COMDLG_FILTERSPEC *fileTypes=new COMDLG_FILTERSPEC[filters.size()];
                    for (size_t i=0;i<filters.size();i++) {
                    	fileTypes[i].pszName=filters[i].first.c_str();
                    	fileTypes[i].pszSpec=filters[i].second.c_str();
                    }
                    IFileDialog *pFile;
					if (strcmp(what, "saveFileDialog") == 0)
//                        hr = CoCreateInstance(CLSID_FileSaveDialog, NULL, CLSCTX_ALL,
//                                IID_IFileSaveDialog, reinterpret_cast<void**>(&pFile));
                        hr = CoCreateInstance(CLSID_FileSaveDialog, hwndcopy, CLSCTX_ALL,
                                IID_IFileSaveDialog, reinterpret_cast<void**>(&pFile));
					else
//                        hr = CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_ALL,
//                                IID_IFileOpenDialog, reinterpret_cast<void**>(&pFile));
                        hr = CoCreateInstance(CLSID_FileOpenDialog, hwndcopy, CLSCTX_ALL,
                                IID_IFileOpenDialog, reinterpret_cast<void**>(&pFile));
					if (SUCCEEDED(hr))
					{

CBUMP

the TODOs

bump.cpp

static bool rect_getSegmentIntersectionIndices(double x, double y, double w,
		double h, double x1, double y1, double x2, double y2, double &ti1,
		double &ti2, double &nx1, double &ny1, double &nx2, double &ny2) {
	//ti1, ti2 = ti1 or 0, ti2 or 1 TODO
	double dx = x2 - x1;
	double dy = y2 - y1;
...
static bool rect_detectCollision(double x1, double y1, double w1, double h1,
		double x2, double y2, double w2, double h2, double goalX, double goalY,
		Collision &col) {
	//goalX = goalX or x1 TODO
	//goalY = goalY or y1

	double dx = goalX - x1, dy = goalY - y1;
...

It is time to do the TODOs ;-)