CPlusPlus for Gideros Studio Help
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:
- 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
Convert wstring <-> string
platform-win32.cpp
refs:
- SO (cc-by): https://stackoverflow.com/a/18374698/870125
C:\dev\gideros_hgy29\libgid\src\win32\platform-win32.cpp <syntaxhighlight lang="c++">
- 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);
} </source>
win32 minimum, maximum screen size
platform-win32.cpp
refs:
- https://www.youtube.com/watch?v=-kg4TG7GoYI
- 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-us/windows/win32/api/winuser/nc-winuser-wndproc
C:\dev\gideros_hgy29\libgid\src\win32\platform-win32.cpp <syntaxhighlight lang="c++"> </source>
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.
<syntaxhighlight lang="c++">
* \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 '/'
</source>
<syntaxhighlight lang="c++">
- 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) {
</source>
openFileDialog
platform-win32.cpp
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
<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
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)
</source>
openFileDialog Latest
platform-win32.cpp (updated and working piece of code)
Added:
- append file extension to saved files (1st extension from filters)
<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; } }
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:
<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) </source>
application:getKeyboardModifiers()
platform-win32.cpp
refs:
<syntaxhighlight lang="c++"> if(GetAsyncKeyState(VK_LSHIFT) & 0x8000)
; // left shift is currently down
</source>
mkDir
platform-win32.cpp
Tested and seems ok :-)
refs:
<syntaxhighlight 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
<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::DOUBLE; r.d=retValue; rets.push_back(r); } /*------------------------------------------------------------------*/ }else if ((strcmp(what, "openDirectoryDialog") == 0)
</source>
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:
- 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
<syntaxhighlight 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
<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)
</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 <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)) { </source>
CBUMP
the TODOs
bump.cpp
<syntaxhighlight 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>
<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; ... </source> It is time to do the TODOs ;-)