Difference between revisions of "CPlusPlus for Gideros Studio Help"

From GiderosMobile
 
(34 intermediate revisions by 2 users 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.
+
 
 +
=== KNOWNFOLDERID ===
 +
platform-win32.cpp
 +
 
 +
'''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
  
 
C:\dev\gideros_hgy29\libgid\src\win32\platform-win32.cpp
 
C:\dev\gideros_hgy29\libgid\src\win32\platform-win32.cpp
<source lang="lua">
 
#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;
+
=== Convert wstring <-> string ===
extern char commandLine[];
+
platform-win32.cpp
//extern std::string commandLine; // new 20221011 XXX
 
// extern int dxChrome,dyChrome;
 
extern LuaApplication *application_;
 
  
static std::wstring ws(const char *str) // new 20221011 XXX
+
'''refs''':
{
+
* SO (cc-by): https://stackoverflow.com/a/18374698/870125
    if (!str) return std::wstring();
+
 
    int sl=strlen(str);
+
C:\dev\gideros_hgy29\libgid\src\win32\platform-win32.cpp
    int sz = MultiByteToWideChar(CP_UTF8, 0, str, sl, 0, 0);
+
<syntaxhighlight lang="c++">
    std::wstring res(sz, 0);
+
#include <locale> // new 20221014 XXX
    MultiByteToWideChar(CP_UTF8, 0, str, sl, &res[0], sz);
+
#include <codecvt> // new 20221014 XXX
    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)
+
std::wstring s2ws(const std::string& str)
 
{
 
{
  RECT desktop;
+
    using convert_typeX = std::codecvt_utf8<wchar_t>;
  // Get a handle to the desktop window
+
    std::wstring_convert<convert_typeX, wchar_t> converterX;
  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()
+
    return converterX.from_bytes(str);
{
 
  std::vector<std::string> result;
 
  result.push_back("Win33"); // ;-)
 
  return result;
 
 
}
 
}
  
void openUrl(const char* url)
+
std::string ws2s(const std::wstring& wstr)
 
{
 
{
  ShellExecute(hwndcopy,NULL,url,NULL,NULL,SW_SHOWNORMAL);
+
    using convert_typeX = std::codecvt_utf8<wchar_t>;
//  std::wstring w=ws(url); // new 20221011 XXX
+
    std::wstring_convert<convert_typeX, wchar_t> converterX;
//  ShellExecute(hwndcopy,NULL,w.c_str(),NULL,NULL,SW_SHOWNORMAL); // new 20221011 XXX
 
}
 
  
bool canOpenUrl(const char *url)
+
    return converterX.to_bytes(wstr);
{
 
  return true;
 
 
}
 
}
 +
</syntaxhighlight>
  
std::string getLocale()
 
{
 
  TCHAR szBuff1[10], szBuff2[10];
 
  
  LCID lcid = GetUserDefaultLCID();
+
=== win32 minimum, maximum screen size ===
 +
platform-win32.cpp
  
  GetLocaleInfo(lcid, LOCALE_SISO639LANGNAME, szBuff1, 10);
+
'''refs''':
  GetLocaleInfo(lcid, LOCALE_SISO3166CTRYNAME, szBuff2, 10);
+
* https://www.youtube.com/watch?v=-kg4TG7GoYI
  strcat(szBuff1,"_");
+
* https://gamedev.net/forums/topic/569148-c-windows-api-minimum-resize-dimensions/4638297/
  strcat(szBuff1,szBuff2);
+
* SO (cc-by): https://stackoverflow.com/q/19035481/870125
// std::string s=us(szBuff1)+"_"+us(szBuff2); // new 20221011 XXX
+
* SO (cc-by): https://stackoverflow.com/a/22261818/870125
 +
* https://learn.microsoft.com/en-gb/windows/win32/winmsg/wm-getminmaxinfo?redirectedfrom=MSDN
 +
* https://learn.microsoft.com/en-us/windows/win32/api/winuser/nc-winuser-wndproc
  
  return szBuff1;
+
C:\dev\gideros_hgy29\libgid\src\win32\platform-win32.cpp
//  return s; // new 20221011 XXX
+
<syntaxhighlight lang="c++">
}
+
</syntaxhighlight>
  
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(){
+
=== win32 LFS problem with separator ===
return "";
+
Recent changes to path handling (most likely [0]) caused
}
+
AssetCatalogTest.create_catalog_after_loading_file to fail on WIN32.
  
void getSafeDisplayArea(int &x,int &y,int &w,int &h)
+
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.
  
void setWindowSize(int width, int height)
+
<syntaxhighlight lang="c++">
{
+
* \note If you want a trailing slash, add `SEP_STR` as the last path argument,
  printf("setWindowSize: %d x %d. hwndcopy=%p\n",width,height,hwndcopy);
+
* 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 '/'
 +
</syntaxhighlight>
  
  Orientation app_orient=application_->orientation();
+
<syntaxhighlight lang="c++">
 +
#define SEP_CHR    '#'
 +
#define SEP_STR    "#"
  
  if (app_orient==ePortrait || app_orient==ePortraitUpsideDown){
+
#define EPS 0.001
    RECT rect;
 
    rect.left=0;
 
    rect.top=0;
 
    rect.right=width;
 
    rect.bottom=height;
 
  
    AdjustWindowRect(&rect,WS_OVERLAPPEDWINDOW,FALSE);
+
#define UN_SC_KM    1000.0f
 +
#define UN_SC_HM    100.0f
 +
      str_tmp, TEMP_STR_SIZE, "*%.9g" SEP_STR, unit->scalar / scale_pref);
  
    SetWindowPos(hwndcopy,HWND_TOP,0,0,rect.right-rect.left, rect.bottom-rect.top, SWP_NOMOVE);
+
  if (len_num > len_max) {
     printf("SetWindowPos: %d %d\n",rect.right-rect.left, rect.bottom-rect.top);
+
     len_num = len_max;
 
   }
 
   }
  else {
 
    RECT rect;
 
    rect.left=0;
 
    rect.top=0;
 
    rect.right=height;
 
    rect.bottom=width;
 
  
    AdjustWindowRect(&rect,WS_OVERLAPPEDWINDOW,FALSE);
+
  if (found_ofs + len_num + len_move > len_max) {
 +
</syntaxhighlight>
 +
 
 +
 
 +
=== openFileDialog ===
 +
platform-win32.cpp
  
    SetWindowPos(hwndcopy,HWND_TOP,0,0,rect.right-rect.left, rect.bottom-rect.top, SWP_NOMOVE);
+
'''refs''':
    printf("SetWindowPos: %d %d\n",rect.right-rect.left, rect.bottom-rect.top);
+
* '''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'''
 +
<syntaxhighlight lang="c++">
 +
#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
  
  //application_->setHardwareOrientation(app_orient);   // previously eFixed
+
                DWORD dwFlags; // new 20221028 XXX
  //application_->getApplication()->setDeviceOrientation(app_orient);
+
                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"*.*" },
 +
                        };
  
void W32SetFullScreen(bool fullScreen,HWND wnd,W32FullScreen *save)
+
                        // Create the FileOpenDialog object.
{
+
                        hr = CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_ALL,
  bool for_metro=false;
+
                                IID_IFileOpenDialog, reinterpret_cast<void**>(&pFile));
  if (fullScreen==save->isFullScreen) return;
+
                        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?
  
  // Save current window state if not already fullscreen.
+
                            // set starting folder
  if (!save->isFullScreen) {
+
                            IShellItem *pItem = NULL;
      // Save current window information.  We force the window into restored mode
+
                            hr = SHCreateItemFromParsingName(place.c_str(), NULL, IID_IShellItem, (LPVOID *)&pItem);
      // before going fullscreen because Windows doesn't seem to hide the
+
                            if (SUCCEEDED(hr))
      // taskbar if the window is in the maximized state.
+
                            {
  save->maximized = !!::IsZoomed(wnd);
+
                                pFile->SetFolder(pItem);
      if (save->maximized)
+
                                pItem->Release();
        ::SendMessage(wnd, WM_SYSCOMMAND, SC_RESTORE, 0);
+
                                pItem = NULL;
      save->style = GetWindowLong(wnd, GWL_STYLE);
+
                            }
      save->ex_style = GetWindowLong(wnd, GWL_EXSTYLE);
 
      GetWindowRect(wnd, &save->window_rect);
 
    }
 
  
    if (fullScreen) {
+
                            // Show the Open dialog box.
      // Set new window style and size.
+
                            hr = pFile->Show(NULL);
      SetWindowLong(wnd, GWL_STYLE,
+
                            // Get the file name from the dialog box.
      save->style & ~(WS_CAPTION | WS_THICKFRAME));
+
                            if (SUCCEEDED(hr))
      SetWindowLong(wnd, GWL_EXSTYLE,
+
                            {
      save->ex_style & ~(WS_EX_DLGMODALFRAME |
+
                                IShellItem *pItem;
                    WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE));
+
                                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);
  
      // On expand, if we're given a window_rect, grow to it, otherwise do
+
                                        CoTaskMemFree(pszFilePath);
      // not resize.
+
                                    }
      if (!for_metro) {
+
                                    pItem->Release();
        MONITORINFO monitor_info;
+
                                }
        monitor_info.cbSize = sizeof(monitor_info);
+
                            }
        GetMonitorInfo(MonitorFromWindow(wnd, MONITOR_DEFAULTTONEAREST),
+
                            pFile->Release();
                      &monitor_info);
+
                        }
        SetWindowPos(wnd, NULL, monitor_info.rcMonitor.left, monitor_info.rcMonitor.top,
+
                        CoUninitialize();
        monitor_info.rcMonitor.right-monitor_info.rcMonitor.left,
+
                        /*--------------------------------------------------*/
monitor_info.rcMonitor.bottom-monitor_info.rcMonitor.top,
+
                    }else if (strcmp(what, "saveFileDialog") == 0){
                    SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
+
                        /* TO DO */
      }
+
                        /*--------------------------------------------------*/
    } 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);
+
        }else if (strcmp(what, "temporaryDirectory") == 0)
      SetWindowLong(wnd, GWL_EXSTYLE, save->ex_style);
+
</syntaxhighlight>
  
      if (!for_metro) {
+
=== openFileDialog Latest ===
        // On restore, resize to the previous saved rect size.
+
platform-win32.cpp ('''updated and working piece of code''')
        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;
+
'''Added''':
}
+
* append file extension to saved files (1st extension from filters)
  
static W32FullScreen saved_window_info_;
+
<syntaxhighlight 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;
 +
                }
 +
                }
  
void setFullScreen(bool fullScreen)
+
                DWORD dwFlags;
{
+
                HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
W32SetFullScreen(fullScreen,hwndcopy,&saved_window_info_);
+
                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?
  
void vibrate(int ms)
+
// 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;
 +
}
  
void setKeepAwake(bool awake)
+
// 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);
  
bool setKeyboardVisibility(bool visible){
+
CoTaskMemFree(pszFilePath);
return false;
+
}
}
+
pItem->Release();
 +
}
 +
}
 +
pFile->Release();
 +
}
 +
                CoUninitialize();
 +
                delete[] fileTypes;
 +
                }
 +
            }
 +
            /*------------------------------------------------------------------*/
 +
        }else if (strcmp(what, "temporaryDirectory") == 0)
 +
</syntaxhighlight>
  
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) {
+
=== Locate first occurrence of character in wide string ===
return -1;
+
platform-win32.cpp
}
 
  
int getClipboard(std::string &data,std::string &mimeType, int luaFunc) {
+
'''refs''':
return -1;
+
* https://cplusplus.com/reference/cwchar/wcschr/
}
+
* https://cplusplus.com/reference/string/string/find/
 +
<syntaxhighlight 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)
 +
</syntaxhighlight>
  
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;
+
=== application:getKeyboardModifiers() ===
 +
'''refs''':
 +
* https://learn.microsoft.com/en-us/windows/win32/inputdev/about-keyboard-input#key-status
 +
* https://learn.microsoft.com/en-us/windows/win32/inputdev/about-keyboard-input#keystroke-message-flags
 +
* SO (cc-by): https://stackoverflow.com/questions/1811206/on-win32-how-to-detect-whether-a-left-shift-or-right-alt-is-pressed-using-perl
 +
<syntaxhighlight lang="c++">
 +
if(GetAsyncKeyState(VK_LSHIFT) & 0x8000)
 +
    ; // left shift is currently down
 +
</syntaxhighlight>
  
extern "C" {
+
*'''\libgid\src\win32\platform-win32.cpp'''
  int g_getFps()
+
<syntaxhighlight lang="c++">
   {
+
int getKeyboardModifiers()
    return s_fps;
+
{
 +
int m=0;
 +
if (GetKeyState(VK_CONTROL) & 0x8000) m|=GINPUT_CTRL_MODIFIER;
 +
if (GetKeyState(VK_SHIFT) & 0x8000) m|=GINPUT_SHIFT_MODIFIER;
 +
if (GetKeyState(VK_MENU) & 0x8000) m|=GINPUT_ALT_MODIFIER;
 +
return m;
 +
}
 +
</syntaxhighlight>
 +
*'''\win32_example\win32.cpp'''
 +
<syntaxhighlight lang="c++">
 +
   else if ((iMsg==WM_KEYDOWN)||(iMsg==WM_SYSKEYDOWN)) {
 +
int m=0;
 +
if (GetKeyState(VK_CONTROL) & 0x8000) m|=GINPUT_CTRL_MODIFIER;
 +
if (GetKeyState(VK_SHIFT) & 0x8000) m|=GINPUT_SHIFT_MODIFIER;
 +
if (GetKeyState(VK_MENU) & 0x8000) m|=GINPUT_ALT_MODIFIER;
 +
if (!(lParam&0x40000000)) // don't send repeated keys XXX
 +
ginputp_keyDown(wParam,m);
 +
if ((iMsg==WM_KEYDOWN)||(wParam==VK_F10))
 +
return 0;
 
   }
 
   }
   void g_setFps(int fps)
+
   else if ((iMsg==WM_KEYUP)||(iMsg==WM_SYSKEYUP)) {
  {
+
int m=0;
    s_fps = fps;
+
if (GetKeyState(VK_CONTROL) & 0x8000) m|=GINPUT_CTRL_MODIFIER;
 +
if (GetKeyState(VK_SHIFT) & 0x8000) m|=GINPUT_SHIFT_MODIFIER;
 +
if (GetKeyState(VK_MENU) & 0x8000) m|=GINPUT_ALT_MODIFIER;
 +
ginputp_keyUp(wParam,m);
 +
return 0;
 
   }
 
   }
}
+
</syntaxhighlight>
 +
 
 +
''GetKeyState'' is for messages when you need the state at the time the message was sent.
  
void g_exit()
+
''GetAsyncKeyState'' is for the state right now.
{
 
  exit(0);
 
}
 
  
bool g_checkStringProperty(bool isSet, const char* what){
+
The high bit will be set if it's down, and it returns a short, hence the 1000000000000000, or ''0x8000'' mask
    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){
+
* https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getkeystate
//   QString argGet = QString::fromUtf8(arg);
+
* https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getasynckeystate
    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!
+
'''Notes''':</br>
  {
+
''wparam'' contains the virtual key code, ''lparam'' contains the the key state vector.
//    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)
+
=== mkDir ===
{
+
platform-win32.cpp
  if (strcmp(what,"commandLine")==0)
 
    return commandLine;
 
 
 
  return 0; // new 20221011 XXX
 
}
 
</source>
 
  
=== Description ===
+
'''Tested and seems ok :-)'''
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
 
  
C:\dev\gideros_hgy29\libgid\src\win32\platform-win32.cpp
+
'''refs''':
<source lang="lua">
+
* '''https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/mkdir-wmkdir?view=msvc-170'''
#include <ShlObj.h> // new 20221013 XXX
+
<syntaxhighlight lang="c++">
...
+
         }else if (strcmp(what, "mkDir") == 0)
         }else if (strcmp(what, "directory") == 0)
 
 
         {
 
         {
/* TODO
+
            // new 20221114 XXX
             QStringList acceptedValue;
+
             std::wstring dir = ws(args[0].s.c_str());
             acceptedValue << "executable" << "document"  << "desktop" << "temporary" << "data" ;
+
             if (_wmkdir(dir.c_str()) == 0)
             acceptedValue << "music" << "movies"  << "pictures" << "cache" << "download" ;
+
                printf("mkDir OK: %S\n", dir.c_str()); // can be useful for the w32 console
             acceptedValue << "home";
+
             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)
 +
</syntaxhighlight>
 +
 
  
            if (args.size()>0)&&(acceptedValue.contains(args[0].s)){
+
=== pathfileexists ===
                QString argString=args[0].s;
+
platform-win32.cpp
                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{
+
'''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
 +
<syntaxhighlight 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::STRING;
+
                 r.type=gapplication_Variant::DOUBLE;
                 r.s=pathGet.toStdString();
+
                 r.d=retValue;
 
                 rets.push_back(r);
 
                 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;
 
            r.s=us(myPath);
 
            rets.push_back(r);
 
 
             /*------------------------------------------------------------------*/
 
             /*------------------------------------------------------------------*/
 
         }else if ((strcmp(what, "openDirectoryDialog") == 0)
 
         }else if ((strcmp(what, "openDirectoryDialog") == 0)
                || (strcmp(what, "openFileDialog") == 0)
+
</syntaxhighlight>
                || (strcmp(what, "saveFileDialog") == 0))
 
</source>
 
  
=== Convert wstring <-> string ===
+
=== pathfileexists Qt ===
* SO (cc-by): https://stackoverflow.com/a/18374698/870125
+
platform-qt.cpp
  
C:\dev\gideros_hgy29\libgid\src\win32\platform-win32.cpp
+
QFile Class seems to be "kind of" the equivalent?
<source lang="lua">
 
#include <locale> // new 20221014 XXX
 
#include <codecvt> // new 20221014 XXX
 
  
...
+
'''refs''':
 +
* https://doc.qt.io/qt-6/qfile.html
  
std::wstring s2ws(const std::string& str)
+
bool '''QFile::exists'''(const QString &fileName)
{
+
Returns true if the file specified by fileName exists; otherwise returns false.
    using convert_typeX = std::codecvt_utf8<wchar_t>;
+
Note: If fileName is a symlink that points to a non-existing file, false is returned.
    std::wstring_convert<convert_typeX, wchar_t> converterX;
 
  
    return converterX.from_bytes(str);
+
I will need to mix this and _waccess.
}
 
  
std::string ws2s(const std::wstring& wstr)
+
=== WM_GETMINMAXINFO ===
{
+
win32.cpp
    using convert_typeX = std::codecvt_utf8<wchar_t>;
 
    std::wstring_convert<convert_typeX, wchar_t> converterX;
 
  
    return converterX.to_bytes(wstr);
+
'''WIP'''
}
 
</source>
 
  
=== win32 minimum, maximum screen size ===
+
'''refs''':
https://www.youtube.com/watch?v=-kg4TG7GoYI
+
* SO (cc-by): https://stackoverflow.com/questions/22261804/how-to-set-minimum-window-size-using-winapi
* 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/a/22261818/870125
 
 
* https://learn.microsoft.com/en-gb/windows/win32/winmsg/wm-getminmaxinfo?redirectedfrom=MSDN
 
* https://learn.microsoft.com/en-gb/windows/win32/winmsg/wm-getminmaxinfo?redirectedfrom=MSDN
* https://learn.microsoft.com/en-us/windows/win32/api/winuser/nc-winuser-wndproc
+
<syntaxhighlight lang="c++">
 +
</syntaxhighlight>
 +
 
 +
 
 +
=== 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
 +
<syntaxhighlight 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)
 +
</syntaxhighlight>
 +
 
 +
=== 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
 +
<syntaxhighlight 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))
 +
{
 +
</syntaxhighlight>
 +
 
 +
== CBUMP ==
 +
 
 +
=== the TODOs ===
 +
bump.cpp
  
C:\dev\gideros_hgy29\libgid\src\win32\platform-win32.cpp
+
<syntaxhighlight lang="c++">
<source lang="lua">
+
static bool rect_getSegmentIntersectionIndices(double x, double y, double w,
</source>
+
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;
 +
...
 +
</syntaxhighlight>
  
 +
<syntaxhighlight 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;
 +
...
 +
</syntaxhighlight>
 +
It is time to do the TODOs ;-)
  
  
 
{{GIDEROS IMPORTANT LINKS}}
 
{{GIDEROS IMPORTANT LINKS}}

Latest revision as of 21:53, 28 September 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()

refs:

if(GetAsyncKeyState(VK_LSHIFT) & 0x8000)
    ; // left shift is currently down
  • \libgid\src\win32\platform-win32.cpp
int getKeyboardModifiers()
{
	int m=0;
	if (GetKeyState(VK_CONTROL) & 0x8000) m|=GINPUT_CTRL_MODIFIER;
	if (GetKeyState(VK_SHIFT) & 0x8000) m|=GINPUT_SHIFT_MODIFIER;
	if (GetKeyState(VK_MENU) & 0x8000) m|=GINPUT_ALT_MODIFIER;
	return m;
}
  • \win32_example\win32.cpp
  else if ((iMsg==WM_KEYDOWN)||(iMsg==WM_SYSKEYDOWN)) {
		int m=0;
		if (GetKeyState(VK_CONTROL) & 0x8000) m|=GINPUT_CTRL_MODIFIER;
		if (GetKeyState(VK_SHIFT) & 0x8000) m|=GINPUT_SHIFT_MODIFIER;
		if (GetKeyState(VK_MENU) & 0x8000) m|=GINPUT_ALT_MODIFIER;
		if (!(lParam&0x40000000)) // don't send repeated keys XXX
			ginputp_keyDown(wParam,m);
		if ((iMsg==WM_KEYDOWN)||(wParam==VK_F10))
			return 0;
  }
  else if ((iMsg==WM_KEYUP)||(iMsg==WM_SYSKEYUP)) {
		int m=0;
		if (GetKeyState(VK_CONTROL) & 0x8000) m|=GINPUT_CTRL_MODIFIER;
		if (GetKeyState(VK_SHIFT) & 0x8000) m|=GINPUT_SHIFT_MODIFIER;
		if (GetKeyState(VK_MENU) & 0x8000) m|=GINPUT_ALT_MODIFIER;
		ginputp_keyUp(wParam,m);
		return 0;
  }

GetKeyState is for messages when you need the state at the time the message was sent.

GetAsyncKeyState is for the state right now.

The high bit will be set if it's down, and it returns a short, hence the 1000000000000000, or 0x8000 mask


Notes:
wparam contains the virtual key code, lparam contains the the key state vector.

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 ;-)