inline lstring directory::folders(const string &pathname, const string &pattern) { lstring list; string path = pathname; path.transform("/", "\\"); if(!strend(path, "\\")) path.append("\\"); path.append("*"); HANDLE handle; WIN32_FIND_DATA data; handle = FindFirstFile(utf16_t(path), &data); if(handle != INVALID_HANDLE_VALUE) { if(wcscmp(data.cFileName, L".") && wcscmp(data.cFileName, L"..")) { if(data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { string name = (const char*)utf8_t(data.cFileName); if(wildcard(name, pattern)) list.append(name); } } while(FindNextFile(handle, &data) != false) { if(wcscmp(data.cFileName, L".") && wcscmp(data.cFileName, L"..")) { if(data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { string name = (const char*)utf8_t(data.cFileName); if(wildcard(name, pattern)) list.append(name); } } } FindClose(handle); } if(list.size() > 0) list.sort(); for(auto &name : list) name.append("/"); //must append after sorting return list; }
inline lstring directory::files(const string &pathname, const string &pattern) { lstring list; string path = pathname; path.transform("/", "\\"); if(!strend(path, "\\")) path.append("\\"); path.append("*"); HANDLE handle; WIN32_FIND_DATA data; handle = FindFirstFile(utf16_t(path), &data); if(handle != INVALID_HANDLE_VALUE) { if((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) { string name = utf8_t(data.cFileName); if(wildcard(name, pattern)) list.append(name); } while(FindNextFile(handle, &data) != false) { if((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) { string name = utf8_t(data.cFileName); if(wildcard(name, pattern)) list.append(name); } } FindClose(handle); } if(list.size() > 0) sort(&list[0], list.size()); return list; }
string pBrowserWindow::directory(BrowserWindow::State& state) { wchar_t wname[PATH_MAX + 1] = L""; BROWSEINFO bi; bi.hwndOwner = state.parent ? state.parent->p.hwnd : 0; bi.pidlRoot = NULL; bi.pszDisplayName = wname; bi.lpszTitle = L"\nChoose a directory:"; bi.ulFlags = BIF_NEWDIALOGSTYLE | BIF_RETURNONLYFSDIRS; bi.lpfn = BrowserWindowCallbackProc; bi.lParam = (LPARAM)&state; bi.iImage = 0; bool result = false; LPITEMIDLIST pidl = SHBrowseForFolder(&bi); if(pidl) { if(SHGetPathFromIDList(pidl, wname)) { result = true; IMalloc *imalloc = 0; if(SUCCEEDED(SHGetMalloc(&imalloc))) { imalloc->Free(pidl); imalloc->Release(); } } } if(result == false) return ""; string name = (const char*)utf8_t(wname); if(!name) return ""; name.transform("\\", "/"); if(name.endsWith("/") == false) name.append("/"); return name; }
string pDialogWindow::folderSelect(Window &parent, const string &path) { wchar_t wfilename[PATH_MAX + 1] = L""; BROWSEINFO bi; bi.hwndOwner = &parent != &Window::None ? parent.p.hwnd : 0; bi.pidlRoot = NULL; bi.pszDisplayName = wfilename; bi.lpszTitle = L""; bi.ulFlags = BIF_NEWDIALOGSTYLE | BIF_RETURNONLYFSDIRS; bi.lpfn = NULL; bi.lParam = 0; bi.iImage = 0; bool result = false; LPITEMIDLIST pidl = SHBrowseForFolder(&bi); if(pidl) { if(SHGetPathFromIDList(pidl, wfilename)) { result = true; IMalloc *imalloc = 0; if(SUCCEEDED(SHGetMalloc(&imalloc))) { imalloc->Free(pidl); imalloc->Release(); } } } if(result == false) return ""; string name = (const char*)utf8_t(wfilename); if(name == "") return ""; name.transform("\\", "/"); if(name.endswith("/") == false) name.append("/"); return name; }
string pLineEdit::text() { unsigned length = GetWindowTextLength(hwnd); wchar_t text[length + 1]; GetWindowText(hwnd, text, length + 1); text[length] = 0; return (const char*)utf8_t(text); }
string pTextEdit::text() { unsigned length = GetWindowTextLength(hwnd); wchar_t buffer[length + 1]; GetWindowText(hwnd, buffer, length + 1); buffer[length] = 0; string text = (const char*)utf8_t(buffer); text.replace("\r", ""); return text; }
string temppath() { #ifdef _WIN32 wchar_t path[PATH_MAX] = L""; GetTempPathW(PATH_MAX, path); //path.transform("\\", "/"); return (const char*)utf8_t(path); #else return "/tmp/"; #endif }
string temppath() { #if defined(PLATFORM_WINDOWS) wchar_t path[PATH_MAX] = L""; GetTempPathW(PATH_MAX, path); string result = (const char*)utf8_t(path); result.transform("\\", "/"); return result; #else return "/tmp/"; #endif }
string realpath(const string &name) { string result; #ifdef _WIN32 wchar_t path[PATH_MAX] = L""; if(_wfullpath(path, utf16_t(name), PATH_MAX)) result = (const char*)utf8_t(path); result.transform("\\", "/"); #else char path[PATH_MAX] = ""; if(::realpath(name, path)) result = path; #endif return result; }
string realpath(const string& name) { string result; #if defined(PLATFORM_WINDOWS) wchar_t path[PATH_MAX] = L""; if(_wfullpath(path, utf16_t(name), PATH_MAX)) result = (const char*)utf8_t(path); result.transform("\\", "/"); #else char path[PATH_MAX] = ""; if(::realpath(name, path)) result = path; #endif if(result.empty()) result = {activepath(), name}; return result; }
static string read(const string& name) { lstring part = name.split("/"); HKEY handle, rootKey = root(part.take(0)); string node = part.take(); string path = part.merge("\\"); if(RegOpenKeyExW(rootKey, utf16_t(path), 0, NWR_FLAGS | KEY_READ, &handle) == ERROR_SUCCESS) { wchar_t data[NWR_SIZE] = L""; DWORD size = NWR_SIZE * sizeof(wchar_t); LONG result = RegQueryValueExW(handle, utf16_t(node), nullptr, nullptr, (LPBYTE)&data, (LPDWORD)&size); RegCloseKey(handle); if(result == ERROR_SUCCESS) return (const char*)utf8_t(data); } return ""; }
static string FileDialog(bool save, Window &parent, const string &path, const lstring &filter) { string dir = path; dir.replace("/", "\\"); string filterList; for(auto &filterItem : filter) { lstring part; part.split("(", filterItem); if(part.size() != 2) continue; part[1].rtrim<1>(")"); part[1].replace(" ", ""); part[1].transform(",", ";"); filterList.append(string(filterItem, "\t", part[1], "\t")); } utf16_t wfilter(filterList); utf16_t wdir(dir); wchar_t wfilename[PATH_MAX + 1] = L""; wchar_t *p = wfilter; while(*p != L'\0') { if(*p == L'\t') *p = L'\0'; p++; } if(path.empty() == false) { //clear COMDLG32 MRU (most recently used) file list //this is required in order for lpstrInitialDir to be honored in Windows 7 and above registry::remove("HKCU/Software/Microsoft/Windows/CurrentVersion/Explorer/ComDlg32/LastVisitedPidlMRU/"); registry::remove("HKCU/Software/Microsoft/Windows/CurrentVersion/Explorer/ComDlg32/OpenSavePidlMRU/"); } OPENFILENAME ofn; memset(&ofn, 0, sizeof(OPENFILENAME)); ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = &parent != &Window::None ? parent.p.hwnd : 0; ofn.lpstrFilter = wfilter; ofn.lpstrInitialDir = wdir; ofn.lpstrFile = wfilename; ofn.nMaxFile = PATH_MAX; ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; ofn.lpstrDefExt = L""; bool result = (save == false ? GetOpenFileName(&ofn) : GetSaveFileName(&ofn)); if(result == false) return ""; string name = (const char*)utf8_t(wfilename); name.transform("\\", "/"); return name; }
static string BrowserWindow_fileDialog(bool save, BrowserWindow::State& state) { string path = string{state.path}.replace("/", "\\"); string filters; for(auto& filter : state.filters) { lstring part = filter.split("("); if(part.size() != 2) continue; part[1].rtrim<1>(")"); part[1].replace(" ", ""); part[1].transform(",", ";"); filters.append(filter, "\t", part[1], "\t"); } utf16_t wfilters(filters); wchar_t wname[PATH_MAX + 1] = L""; utf16_t wpath(path); utf16_t wtitle(state.title); wchar_t* p = wfilters; while(*p != L'\0') { if(*p == L'\t') *p = L'\0'; p++; } if(path.empty() == false) { //clear COMDLG32 MRU (most recently used) file list //this is required in order for lpstrInitialDir to be honored in Windows 7 and above registry::remove("HKCU/Software/Microsoft/Windows/CurrentVersion/Explorer/ComDlg32/LastVisitedPidlMRU/"); registry::remove("HKCU/Software/Microsoft/Windows/CurrentVersion/Explorer/ComDlg32/OpenSavePidlMRU/"); } OPENFILENAME ofn; memset(&ofn, 0, sizeof(OPENFILENAME)); ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = state.parent ? state.parent->p.hwnd : 0; ofn.lpstrFilter = wfilters; ofn.lpstrInitialDir = wpath; ofn.lpstrFile = wname; ofn.lpstrTitle = wtitle; ofn.nMaxFile = PATH_MAX; ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; ofn.lpstrDefExt = L""; bool result = (save == false ? GetOpenFileName(&ofn) : GetSaveFileName(&ofn)); if(result == false) return ""; string name = (const char*)utf8_t(wname); name.transform("\\", "/"); return name; }
static lstring contents(const string& name) { lstring part = name.split("/"), result; HKEY handle, rootKey = root(part.take(0)); part.remove(); string path = part.merge("\\"); if(RegOpenKeyExW(rootKey, utf16_t(path), 0, NWR_FLAGS | KEY_READ, &handle) == ERROR_SUCCESS) { DWORD folders, nodes; RegQueryInfoKey(handle, nullptr, nullptr, nullptr, &folders, nullptr, nullptr, &nodes, nullptr, nullptr, nullptr, nullptr); for(unsigned n = 0; n < folders; n++) { wchar_t name[NWR_SIZE] = L""; DWORD size = NWR_SIZE * sizeof(wchar_t); RegEnumKeyEx(handle, n, (wchar_t*)&name, &size, nullptr, nullptr, nullptr, nullptr); result.append({(const char*)utf8_t(name), "/"}); } for(unsigned n = 0; n < nodes; n++) { wchar_t name[NWR_SIZE] = L""; DWORD size = NWR_SIZE * sizeof(wchar_t); RegEnumValueW(handle, n, (wchar_t*)&name, &size, nullptr, nullptr, nullptr, nullptr); result.append((const char*)utf8_t(name)); } RegCloseKey(handle); } return result; }
// /home/username/ // c:/users/username/ string userpath() { string result; #if defined(PLATFORM_WINDOWS) wchar_t path[PATH_MAX] = L""; SHGetFolderPathW(nullptr, CSIDL_PROFILE | CSIDL_FLAG_CREATE, nullptr, 0, path); result = (const char*)utf8_t(path); result.transform("\\", "/"); #else struct passwd *userinfo = getpwuid(getuid()); result = userinfo->pw_dir; #endif if(result.empty()) result = "."; if(result.endswith("/") == false) result.append("/"); return result; }
static BOOL CALLBACK MonitorEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) { MonitorInfo& info = *(MonitorInfo*)dwData; MONITORINFOEX mi; memset(&mi, 0, sizeof(MONITORINFOEX)); mi.cbSize = sizeof(MONITORINFOEX); GetMonitorInfo(hMonitor, &mi); string displayName = (const char*)utf8_t(mi.szDevice); if(displayName.beginsWith(R"(\\.\DISPLAYV)")) return TRUE; //ignore pseudo-monitors if(mi.dwFlags & MONITORINFOF_PRIMARY) info.primary = info.index; if(info.monitor == info.index) { info.geometry = {lprcMonitor->left, lprcMonitor->top, lprcMonitor->right - lprcMonitor->left, lprcMonitor->bottom - lprcMonitor->top}; } info.index++; return TRUE; }
string activepath() { string result; #ifdef _WIN32 wchar_t path[PATH_MAX] = L""; auto unused = _wgetcwd(path, PATH_MAX); result = (const char*)utf8_t(path); result.transform("\\", "/"); #else char path[PATH_MAX] = ""; auto unused = getcwd(path, PATH_MAX); result = path; #endif if(result.empty()) result = "."; if(result.endswith("/") == false) result.append("/"); return result; }
string sharedpath() { string result; #if defined(PLATFORM_WINDOWS) wchar_t path[PATH_MAX] = L""; SHGetFolderPathW(nullptr, CSIDL_COMMON_APPDATA | CSIDL_FLAG_CREATE, nullptr, 0, path); result = (const char*)utf8_t(path); result.transform("\\", "/"); #elif defined(PLATFORM_OSX) result = "/Library/Application Support/"; #else result = "/usr/share/"; #endif if(result.empty()) result = "."; if(result.endswith("/") == false) result.append("/"); return result; }
string userpath() { string result; #ifdef _WIN32 wchar_t path[PATH_MAX] = L""; SHGetFolderPathW(0, CSIDL_APPDATA | CSIDL_FLAG_CREATE, 0, 0, path); result = (const char*)utf8_t(path); result.transform("\\", "/"); #else char path[PATH_MAX] = ""; struct passwd *userinfo = getpwuid(getuid()); if(userinfo) strcpy(path, userinfo->pw_dir); result = path; #endif if(result.empty()) result = "."; if(result.endswith("/") == false) result.append("/"); return result; }
static lstring DropPaths(WPARAM wparam) { auto dropList = HDROP(wparam); auto fileCount = DragQueryFile(dropList, ~0u, nullptr, 0); lstring paths; for(unsigned n = 0; n < fileCount; n++) { auto length = DragQueryFile(dropList, n, nullptr, 0); auto buffer = new wchar_t[length + 1]; if(DragQueryFile(dropList, n, buffer, length + 1)) { string path = (const char*)utf8_t(buffer); path.transform("\\", "/"); if(directory::exists(path) && !path.endsWith("/")) path.append("/"); paths.append(path); } delete[] buffer; } return paths; }
static bool OS_keyboardProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { if(msg != WM_KEYDOWN && msg != WM_SYSKEYDOWN && msg != WM_KEYUP && msg != WM_SYSKEYUP) return false; GUITHREADINFO info; memset(&info, 0, sizeof(GUITHREADINFO)); info.cbSize = sizeof(GUITHREADINFO); GetGUIThreadInfo(GetCurrentThreadId(), &info); Object *object = (Object*)GetWindowLongPtr(info.hwndFocus, GWLP_USERDATA); if(object == nullptr) return false; if(dynamic_cast<Window*>(object)) { Window &window = (Window&)*object; if(pWindow::modal.size() > 0 && !pWindow::modal.find(&window.p)) return false; Keyboard::Keycode keysym = Keysym(wparam, lparam); if(keysym != Keyboard::Keycode::None) { if((msg == WM_KEYDOWN || msg == WM_SYSKEYDOWN) && window.onKeyPress) window.onKeyPress(keysym); if((msg == WM_KEYUP || msg == WM_SYSKEYUP) && window.onKeyRelease) window.onKeyRelease(keysym); } return false; } if(msg == WM_KEYDOWN) { if(dynamic_cast<ListView*>(object)) { ListView &listView = (ListView&)*object; if(wparam == VK_RETURN) { if(listView.onActivate) listView.onActivate(); } } else if(dynamic_cast<LineEdit*>(object)) { LineEdit &lineEdit = (LineEdit&)*object; if(wparam == VK_RETURN) { if(lineEdit.onActivate) lineEdit.onActivate(); } } else if(dynamic_cast<TextEdit*>(object)) { TextEdit &textEdit = (TextEdit&)*object; if(wparam == 'A' && GetKeyState(VK_CONTROL) < 0) { //Ctrl+A = select all text //note: this is not a standard accelerator on Windows Edit_SetSel(textEdit.p.hwnd, 0, ~0); return true; } else if(wparam == 'V' && GetKeyState(VK_CONTROL) < 0) { //Ctrl+V = paste text //note: this formats Unix (LF) and OS9 (CR) line-endings to Windows (CR+LF) line-endings //this is necessary as the EDIT control only supports Windows line-endings OpenClipboard(hwnd); HANDLE handle = GetClipboardData(CF_UNICODETEXT); if(handle) { wchar_t *text = (wchar_t*)GlobalLock(handle); if(text) { string data = (const char*)utf8_t(text); data.replace("\r\n", "\n"); data.replace("\r", "\n"); data.replace("\n", "\r\n"); GlobalUnlock(handle); utf16_t output(data); HGLOBAL resource = GlobalAlloc(GMEM_MOVEABLE, (wcslen(output) + 1) * sizeof(wchar_t)); if(resource) { wchar_t *write = (wchar_t*)GlobalLock(resource); if(write) { wcscpy(write, output); GlobalUnlock(write); if(SetClipboardData(CF_UNICODETEXT, resource) == FALSE) { GlobalFree(resource); } } } } } CloseClipboard(); return false; } } } return false; }
static LRESULT CALLBACK Viewport_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { Object* object = (Object*)GetWindowLongPtr(hwnd, GWLP_USERDATA); if(object == nullptr) return DefWindowProc(hwnd, msg, wparam, lparam); if(!dynamic_cast<Viewport*>(object)) return DefWindowProc(hwnd, msg, wparam, lparam); Viewport& viewport = (Viewport&)*object; if(msg == WM_DROPFILES) { auto dropList = HDROP(wparam); auto fileCount = DragQueryFile(dropList, ~0u, nullptr, 0); lstring result; for(unsigned n = 0; n < fileCount; n++) { auto length = DragQueryFile(dropList, n, nullptr, 0); auto buffer = new wchar_t[length + 1]; if(DragQueryFile(dropList, n, buffer, length + 1)) { string path = (const char*)utf8_t(buffer); path.transform("\\", "/"); if(directory::exists(path) && !path.endswith("/")) path.append("/"); result.append(path); } delete[] buffer; } if(viewport.onDrop) viewport.onDrop(result); return FALSE; } if(msg == WM_GETDLGCODE) { return DLGC_STATIC | DLGC_WANTCHARS; } if(msg == WM_MOUSEMOVE) { TRACKMOUSEEVENT tracker = {sizeof(TRACKMOUSEEVENT), TME_LEAVE, hwnd}; TrackMouseEvent(&tracker); if(viewport.onMouseMove) viewport.onMouseMove({(int16_t)LOWORD(lparam), (int16_t)HIWORD(lparam)}); } if(msg == WM_MOUSELEAVE) { if(viewport.onMouseLeave) viewport.onMouseLeave(); } if(msg == WM_LBUTTONDOWN || msg == WM_MBUTTONDOWN || msg == WM_RBUTTONDOWN) { if(viewport.onMousePress) switch(msg) { case WM_LBUTTONDOWN: viewport.onMousePress(Mouse::Button::Left); break; case WM_MBUTTONDOWN: viewport.onMousePress(Mouse::Button::Middle); break; case WM_RBUTTONDOWN: viewport.onMousePress(Mouse::Button::Right); break; } } if(msg == WM_LBUTTONUP || msg == WM_MBUTTONUP || msg == WM_RBUTTONUP) { if(viewport.onMouseRelease) switch(msg) { case WM_LBUTTONUP: viewport.onMouseRelease(Mouse::Button::Left); break; case WM_MBUTTONUP: viewport.onMouseRelease(Mouse::Button::Middle); break; case WM_RBUTTONUP: viewport.onMouseRelease(Mouse::Button::Right); break; } } return DefWindowProc(hwnd, msg, wparam, lparam); }