diff --git a/include/utility/fsutil.h b/include/utility/fsutil.h index 2b346ed..2c2b86a 100644 --- a/include/utility/fsutil.h +++ b/include/utility/fsutil.h @@ -53,6 +53,10 @@ struct SKIF_CommonPathsCache { { FOLDERID_Documents, L"%USERPROFILE%\\My Documents" }; + win_path_s my_pictures = + { FOLDERID_Pictures, + L"%USERPROFILE%\\My Documents\\My Pictures" + }; win_path_s app_data_local = { FOLDERID_LocalAppData, L"%USERPROFILE%\\AppData\\Local" @@ -92,7 +96,9 @@ struct SKIF_CommonPathsCache { wchar_t skiv_install [MAX_PATH + 2] = { }; // Holds the install folder for SKIV wchar_t skiv_userdata [MAX_PATH + 2] = { }; // Holds the user data folder for SKIV wchar_t specialk_userdata [MAX_PATH + 2] = { }; // Holds the user data folder for SK (often lines up with its install folder) - wchar_t skiv_temp [MAX_PATH + 2] = { }; // Holds the temp data folder for SKIV (images downloaded from the web; cleared out on every launch): %APPDATA%\TEMP\SKIV\ + wchar_t skiv_temp [MAX_PATH + 2] = { }; // Holds the temp data folder for SKIV (images downloaded from the web; cleared out on every launch): %APPDATA%\TEMP\SKIV + wchar_t skiv_screenshots [MAX_PATH + 2] = { }; // Holds the screenshot folder for SKIV + char skiv_screenshotsA [MAX_PATH + 2] = { }; // UTF-8 // Functions diff --git a/include/utility/image.h b/include/utility/image.h index 0beffdd..06f5c98 100644 --- a/include/utility/image.h +++ b/include/utility/image.h @@ -134,6 +134,17 @@ static const ParamsPQ PQ = #pragma warning( pop ) +struct SKIV_Region { + ImRect _rect; + std::wstring _title; + + SKIV_Region (ImRect r_ = ImRect(), std::wstring t_ = L"") + { + _rect = r_; + _title = t_; + } +}; + // Declarations DirectX::XMVECTOR SKIV_Image_PQToLinear (DirectX::XMVECTOR N, DirectX::XMVECTOR maxPQValue = DirectX::g_XMOne); DirectX::XMVECTOR SKIV_Image_LinearToPQ (DirectX::XMVECTOR N, DirectX::XMVECTOR maxPQValue = DirectX::g_XMOne); @@ -141,11 +152,11 @@ float SKIV_Image_LinearToPQY (float N); DirectX::XMVECTOR SKIV_Image_Rec709toICtCp (DirectX::XMVECTOR N); DirectX::XMVECTOR SKIV_Image_ICtCptoRec709 (DirectX::XMVECTOR N); -bool SKIV_Image_CopyToClipboard (const DirectX::Image* pImage, bool snipped, bool isHDR); +bool SKIV_Image_CopyToClipboard (const DirectX::Image* pImage, bool isHDR, bool isTemp, const wchar_t* wszFileName); HRESULT SKIV_Image_SaveToDisk_HDR (const DirectX::Image& image, const wchar_t* wszFileName); HRESULT SKIV_Image_SaveToDisk_SDR (const DirectX::Image& image, const wchar_t* wszFileName, bool force_sRGB); HRESULT SKIV_Image_CaptureDesktop (DirectX::ScratchImage& image, POINT pos, int flags = 0x0); -void SKIV_Image_CaptureRegion (ImRect capture_area); +void SKIV_Image_CaptureRegion (SKIV_Region capture_area); HRESULT SKIV_Image_TonemapToSDR (const DirectX::Image& image, DirectX::ScratchImage& final_sdr, float mastering_max_nits, float mastering_sdr_nits); bool SKIV_Image_IsUltraHDR (const wchar_t* wszFileName); diff --git a/include/utility/registry.h b/include/utility/registry.h index 792bf3e..00b3d7f 100644 --- a/include/utility/registry.h +++ b/include/utility/registry.h @@ -265,6 +265,10 @@ struct SKIF_RegistrySettings { SKIF_MakeRegKeyB ( LR"(SOFTWARE\Kaldaien\Special K\Viewer\)", LR"(99th Percentile MaxCLL)" ); + KeyValue regKVSaveScreenshots = + SKIF_MakeRegKeyB ( LR"(SOFTWARE\Kaldaien\Special K\Viewer\)", + LR"(Save Screenshots)" ); + // Integers (DWORDs) KeyValue regKVImageScaling = @@ -357,6 +361,10 @@ struct SKIF_RegistrySettings { SKIF_MakeRegKeyWS ( LR"(SOFTWARE\Kaldaien\Special K\Viewer\)", LR"(Path)" ); + KeyValue regKVPathScreenshots = + SKIF_MakeRegKeyWS ( LR"(SOFTWARE\Kaldaien\Special K\Viewer\)", + LR"(Screenshots)" ); + KeyValue regKVAutoUpdateVersion = SKIF_MakeRegKeyWS ( LR"(SOFTWARE\Kaldaien\Special K\Viewer\)", LR"(Auto-Update Version)" ); @@ -451,11 +459,13 @@ struct SKIF_RegistrySettings { bool bFadeCovers = true; bool bControllers = true; // Should SKIF support controller input ? bool bLoggingDeveloper = false; // This is a log level "above" verbose logging that also includes stuff like window messages. Only useable for SKIF developers + bool bSaveScreenshots = true; // Wide strings std::wstring wsUpdateChannel = L"Website"; // Default to stable channel std::wstring wsIgnoreUpdate; std::wstring wsPathViewer; + std::wstring wsPathScreenshots; std::wstring wsPathSpecialK; std::wstring wsAutoUpdateVersion; // Holds the version the auto-updater is trying to install std::wstring wsDefaultHDRExt = L".png"; diff --git a/include/utility/utility.h b/include/utility/utility.h index e32e79e..2bbea2a 100644 --- a/include/utility/utility.h +++ b/include/utility/utility.h @@ -216,6 +216,7 @@ std::wstring SKIF_Util_GetClipboardHDROP (void); DirectX::Image SKIF_Util_GetClipboardBitmapData (void); std::wstring SKIF_Util_AddEnvironmentBlock (const void* pEnvBlock, const std::wstring& varName, const std::wstring& varValue); void SKIF_Util_FileExplorer_SelectFile (PCWSTR filePath); +std::wstring SKIF_Util_FileExplorer_BrowseFolder (PCWSTR defaultPath); std::string SKIF_Util_GetWindowMessageAsStr (UINT msg); diff --git a/src/SKIV.cpp b/src/SKIV.cpp index 1227a53..1b28938 100644 --- a/src/SKIV.cpp +++ b/src/SKIV.cpp @@ -79,6 +79,8 @@ #include #include +#include "psapi.h" + const int SKIF_STEAM_APPID = 1157970; bool RecreateSwapChains = false; bool RecreateSwapChainsPending = false; @@ -986,6 +988,54 @@ void SKIF_Initialize (LPWSTR lpCmdLine) FindClose (hFind); } + + // Populate SKIV's default screenshot folder + const std::wstring screenshotsDir = + SKIF_Util_NormalizeFullPath (std::wstring (_path_cache.my_pictures.path) + LR"(\Special K\SKIV\)"); + + wcsncpy_s (_path_cache.skiv_screenshots, MAX_PATH, + screenshotsDir.c_str(), _TRUNCATE); + strncpy_s (_path_cache.skiv_screenshotsA, MAX_PATH, + SK_WideCharToUTF8 (_path_cache.skiv_screenshots).data(), _TRUNCATE); +} + +static +std::wstring +SKIV_GetBaseFilename (HWND hWnd) +{ + // Limit window title / process name to 60 characters + const size_t len = MAX_PATH + 2; + wchar_t wszFilename [len] = { }; + + // Window title, if retrievable, else process name + if (GetWindowTextW (hWnd, wszFilename, len) == 0) + { + // Process name + DWORD dwProcessId = 0; + if (GetWindowThreadProcessId (hWnd, &dwProcessId)) + { + HANDLE hProcess = OpenProcess (PROCESS_QUERY_LIMITED_INFORMATION, FALSE, dwProcessId); + + if (hProcess != NULL) + { + GetProcessImageFileNameW (hProcess, wszFilename, MAX_PATH); + PathStripPathW (wszFilename); + PathRemoveExtensionW (wszFilename); + } + } + } + + std::wstring wsFilename = std::wstring (wszFilename); + + // Strip all null terminator \0 characters from the string + wsFilename.erase (std::find(wsFilename.begin(), wsFilename.end(), '\0'), wsFilename.end()); + + if (wsFilename.size() > 60) + wsFilename = wsFilename.substr(0, 60); + else if (wsFilename.empty()) + wsFilename = L"explorer"; + + return wsFilename; } bool bKeepWindowAlive = true, @@ -1195,6 +1245,36 @@ wWinMain ( _In_ HINSTANCE hInstance, SKIF_Util_RegisterApp (true); } + // Read screenshots folder from registry if populated + if (! _registry.wsPathScreenshots.empty()) + { + if (_registry.wsPathScreenshots.back() != '\\') + _registry.wsPathScreenshots += '\\'; + + wcsncpy_s (_path_cache.skiv_screenshots, MAX_PATH, + _registry.wsPathScreenshots.c_str(), _TRUNCATE); + strncpy_s (_path_cache.skiv_screenshotsA, MAX_PATH, + SK_WideCharToUTF8 (_path_cache.skiv_screenshots).data(), _TRUNCATE); + } + + // Create the folder for our screenshots (or fall back to skiv_temp if we cannot create it) + std::error_code ec; + if (! std::filesystem::exists (_path_cache.skiv_screenshots, ec)) + { + if (! std::filesystem::create_directories (_path_cache.skiv_screenshots, ec)) + { + if (! std::filesystem::exists (_path_cache.skiv_screenshots, ec)) + { + wcsncpy_s (_path_cache.skiv_screenshots, MAX_PATH, + _path_cache.skiv_temp, _TRUNCATE); + strncpy_s (_path_cache.skiv_screenshotsA, MAX_PATH, + SK_WideCharToUTF8 (_path_cache.skiv_screenshots).data(), _TRUNCATE); + } + else + PLOG_INFO << "Created screenshot folder: " << _path_cache.skiv_screenshots; + } + } + PLOG_INFO << "Creating notification icon..."; // Create invisible notify window (for the traybar icon and notification toasts, and for doing D3D11 tests) @@ -2087,7 +2167,7 @@ wWinMain ( _In_ HINSTANCE hInstance, ImRect allowable (SKIV_DesktopImage._desktop_pos, SKIV_DesktopImage._desktop_pos + resolution); - ImRect capture_area; + SKIV_Region capture_area; bool HDR_Image = SKIV_DesktopImage._hdr_image; bool SKIV_HDR = (HDR_Image ? SKIF_ImGui_IsViewportHDR (SKIF_ImGui_hWnd) : false); @@ -2120,8 +2200,8 @@ wWinMain ( _In_ HINSTANCE hInstance, draw_list->AddRectFilled (allowable.Min, allowable.Max, ImGui::GetColorU32 (IM_COL32 (0, 0, 0, 20))); } - static ImRect selection; - static ImRect selection_auto; + static SKIV_Region selection = SKIV_Region (ImRect(), L"Desktop_Region"); + static SKIV_Region selection_auto = SKIV_Region (ImRect(), L"Desktop_Auto"); if (GetForegroundWindow () != SKIF_ImGui_hWnd) SetForegroundWindow ( SKIF_ImGui_hWnd); @@ -2162,15 +2242,18 @@ wWinMain ( _In_ HINSTANCE hInstance, return false; }; - auto _GetRectBelowCursor = [&](void) -> void + auto _GetRectBelowCursor = [&](SKIV_Region* _region, bool isAutoSelection) -> void { // This feature is unsupported on rotated displays // if (SKIV_DesktopImage._rotation == DXGI_MODE_ROTATION_ROTATE90 || SKIV_DesktopImage._rotation == DXGI_MODE_ROTATION_ROTATE270) { - selection_auto.Min = ImVec2 (0.0f, 0.0f); - selection_auto.Max = ImVec2 (0.0f, 0.0f); + if (isAutoSelection) + { + _region->_rect.Min = ImVec2 (0.0f, 0.0f); + _region->_rect.Max = ImVec2 (0.0f, 0.0f); + } return; } @@ -2232,11 +2315,16 @@ wWinMain ( _In_ HINSTANCE hInstance, break; } */ + + if (isAutoSelection) + { + _region->_rect.Min.x = static_cast (rect.left); + _region->_rect.Min.y = static_cast (rect.top); + _region->_rect.Max.x = static_cast (rect.right); + _region->_rect.Max.y = static_cast (rect.bottom); + } - selection_auto.Min.x = static_cast (rect.left); - selection_auto.Min.y = static_cast (rect.top); - selection_auto.Max.x = static_cast (rect.right); - selection_auto.Max.y = static_cast (rect.bottom); + _region->_title = SKIV_GetBaseFilename (hWnd); /* PLOG_VERBOSE << "----------------------"; @@ -2245,8 +2333,8 @@ wWinMain ( _In_ HINSTANCE hInstance, if (RealGetWindowClassW (top_most, wszRealWindowClass, 64)) PLOG_VERBOSE << "Class: " << wszRealWindowClass; PLOG_VERBOSE << "Pos: " << point.x << "," << point.y; - PLOG_VERBOSE << "Min: " << selection_auto.Min.x << "," << selection_auto.Min.y; - PLOG_VERBOSE << "Max: " << selection_auto.Max.x << "," << selection_auto.Max.y; + PLOG_VERBOSE << "Min: " << _region.Min.x << "," << _region.Min.y; + PLOG_VERBOSE << "Max: " << _region.Max.x << "," << _region.Max.y; */ breakLoop = true; @@ -2337,18 +2425,19 @@ wWinMain ( _In_ HINSTANCE hInstance, if (! bHoveringSnipToolbar) { - if (! clicked && SKIF_ImGui_SelectionRect (&selection, allowable, 0, SelectionFlag_Filled)) + if (! clicked && SKIF_ImGui_SelectionRect (&selection._rect, allowable, 0, SelectionFlag_Filled)) { _registry._SnippingModeExit = true; + _GetRectBelowCursor (&selection, false); capture_area = selection; } else if (! ImGui::IsMouseDragging (ImGuiMouseButton_Left)) { - _GetRectBelowCursor ( ); + _GetRectBelowCursor (&selection_auto, true); // Keep the selection within the allowed rectangle - selection_auto.ClipWithFull (allowable); + selection_auto._rect.ClipWithFull (allowable); if (ImGui::IsMouseClicked (ImGuiMouseButton_Left)) clicked = true; @@ -2360,20 +2449,20 @@ wWinMain ( _In_ HINSTANCE hInstance, capture_area = selection_auto; } - else if (selection_auto.Min != selection_auto.Max) + else if (selection_auto._rect.Min != selection_auto._rect.Max) { ImDrawList* draw_list = ImGui::GetForegroundDrawList (); - draw_list->AddRect (selection_auto.Min, selection_auto.Max, ImGui::GetColorU32 (IM_COL32(0,130,216,255)), 0.0f, 0, 5.0f); // Border - //draw_list->AddRectFilled (selection_auto.Min, selection_auto.Max, ImGui::GetColorU32 (IM_COL32(0,130,216,50))); // Background + draw_list->AddRect (selection_auto._rect.Min, selection_auto._rect.Max, ImGui::GetColorU32 (IM_COL32(0,130,216,255)), 0.0f, 0, 5.0f); // Border + //draw_list->AddRectFilled (selection_auto._rect.Min, selection_auto._rect.Max, ImGui::GetColorU32 (IM_COL32(0,130,216,50))); // Background } } else clicked = false; - if (capture_area.GetArea() != 0) + if (capture_area._rect.GetArea() != 0) { ignoredWindows.clear(); @@ -4034,8 +4123,9 @@ SKIF_WndProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) extern HWND hwndBeforeSnip; hwndBeforeSnip = GetForegroundWindow (); - POINT capture_point = { }; - RECT capture_rect = { }; + POINT capture_point = { }; + RECT capture_rect = { }; + std::wstring filename = L"Display"; if (mode == CaptureMode_Window) { @@ -4060,11 +4150,17 @@ SKIF_WndProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) capture_rect.right = std::min (capture_rect.right, minfo.rcMonitor.right); capture_rect.bottom = std::min (capture_rect.bottom, minfo.rcMonitor.bottom); + + filename = SKIV_GetBaseFilename (hwndBeforeSnip); } } else + { GetCursorPos (&capture_point); + HWND hWndBelowCursor = WindowFromPoint (capture_point); + filename = SKIV_GetBaseFilename (hWndBelowCursor); + } DirectX::ScratchImage captured_img; HRESULT hr = @@ -4078,14 +4174,17 @@ SKIF_WndProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) extern bool iconicBeforeSnip; extern bool trayedBeforeSnip; - extern ImRect selection_rect; + //extern ImRect selection_rect; if (mode == CaptureMode_Window) { - const ImRect area = ImRect (static_cast (capture_rect.left ), - static_cast (capture_rect.top ), - static_cast (capture_rect.right ), - static_cast (capture_rect.bottom) + const SKIV_Region region = + SKIV_Region ( + ImRect (static_cast (capture_rect.left ), + static_cast (capture_rect.top ), + static_cast (capture_rect.right ), + static_cast (capture_rect.bottom)), + filename ); //PLOG_VERBOSE << "capture_rect.left : " << capture_rect.left; @@ -4093,15 +4192,21 @@ SKIF_WndProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) //PLOG_VERBOSE << "capture_rect.right : " << capture_rect.right; //PLOG_VERBOSE << "capture_rect.bottom: " << capture_rect.bottom; - SKIV_Image_CaptureRegion (area); + SKIV_Image_CaptureRegion (region); _registry._SnippingMode = false; } else if (mode == CaptureMode_Screen) { extern skiv_image_desktop_s SKIV_DesktopImage; - const ImRect area = ImRect (ImVec2 (0, 0), SKIV_DesktopImage._resolution); - SKIV_Image_CaptureRegion (area); + const SKIV_Region region = + SKIV_Region ( + ImRect (ImVec2 (0, 0), + SKIV_DesktopImage._resolution), + filename + ); + + SKIV_Image_CaptureRegion (region); _registry._SnippingMode = false; } @@ -4130,8 +4235,8 @@ SKIF_WndProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) SKIF_ImGui_SetFullscreen (SKIF_ImGui_hWnd, true, monitor); UpdateWindow (SKIF_ImGui_hWnd); - selection_rect.Min = ImVec2 (0.0f, 0.0f); - selection_rect.Max = ImVec2 (0.0f, 0.0f); + //selection_rect.Min = ImVec2 (0.0f, 0.0f); + //selection_rect.Max = ImVec2 (0.0f, 0.0f); ImGui::GetIO ().MouseDown [0] = false; ImGui::GetIO ().MouseDownDuration [0] = -1.0f; diff --git a/src/tabs/settings.cpp b/src/tabs/settings.cpp index d4dea38..a01e419 100644 --- a/src/tabs/settings.cpp +++ b/src/tabs/settings.cpp @@ -62,9 +62,65 @@ SKIF_UI_Tab_DrawSettings (void) ImGui::Spacing (); ImGui::Spacing (); +#pragma region Section: Screenshots + + if (ImGui::CollapsingHeader ("Screenshots###SKIF_SettingsHeader-0", ImGuiTreeNodeFlags_DefaultOpen)) + { + ImGui::PushStyleColor ( + ImGuiCol_Text, ImGui::GetStyleColorVec4(ImGuiCol_SKIF_TextBase) + ); + + SKIF_ImGui_Spacing ( ); + + + if ( ImGui::Checkbox ( "Save screenshots", &_registry.bSaveScreenshots ) ) + _registry.regKVSaveScreenshots.putData ( _registry.bSaveScreenshots); + + ImGui::TreePush ("ScreenshotsFolder"); + + if (! _registry.bSaveScreenshots) + SKIF_ImGui_PushDisableState ( ); + + if (ImGui::Button ("Browse")) + { + std::wstring newPath = SKIF_Util_FileExplorer_BrowseFolder (_path_cache.skiv_screenshots); + + if (PathFileExistsW (newPath.c_str())) + { + if (newPath.back() != '\\') + newPath += '\\'; + + wcsncpy_s (_path_cache.skiv_screenshots, MAX_PATH, + newPath.c_str(), _TRUNCATE); + strncpy_s (_path_cache.skiv_screenshotsA, MAX_PATH, + SK_WideCharToUTF8 (_path_cache.skiv_screenshots).data(), _TRUNCATE); + + _registry.regKVPathScreenshots.putData (_path_cache.skiv_screenshots); + + PLOG_INFO << "Screenshots folder was changed: " << _path_cache.skiv_screenshots; + } + } + + ImGui::SameLine ( ); + ImGui::Spacing ( ); + ImGui::SameLine ( ); + + ImGui::Text ("%s", _path_cache.skiv_screenshotsA); + + if (! _registry.bSaveScreenshots) + SKIF_ImGui_PopDisableState ( ); + + ImGui::TreePop ( ); + } + + ImGui::Spacing (); + ImGui::Spacing (); + +#pragma endregion + #pragma region Section: Keybindings - if (ImGui::CollapsingHeader ("Keybindings###SKIF_SettingsHeader-0", ImGuiTreeNodeFlags_DefaultOpen)) + if (ImGui::CollapsingHeader ("Keybindings###SKIF_SettingsHeader-1", ImGuiTreeNodeFlags_DefaultOpen)) { SKIF_ImGui_Spacing ( ); @@ -123,7 +179,7 @@ SKIF_UI_Tab_DrawSettings (void) #pragma region Section: Image - if (ImGui::CollapsingHeader ("Images###SKIF_SettingsHeader-1", ImGuiTreeNodeFlags_DefaultOpen)) + if (ImGui::CollapsingHeader ("Images###SKIF_SettingsHeader-2", ImGuiTreeNodeFlags_DefaultOpen)) { ImGui::PushStyleColor ( ImGuiCol_Text, ImGui::GetStyleColorVec4(ImGuiCol_SKIF_TextBase) @@ -244,7 +300,7 @@ SKIF_UI_Tab_DrawSettings (void) #pragma region Section: Appearances - if (ImGui::CollapsingHeader ("Appearance###SKIF_SettingsHeader-2", ImGuiTreeNodeFlags_DefaultOpen)) + if (ImGui::CollapsingHeader ("Appearance###SKIF_SettingsHeader-3", ImGuiTreeNodeFlags_DefaultOpen)) { ImGui::PushStyleColor ( ImGuiCol_Text, ImGui::GetStyleColorVec4(ImGuiCol_SKIF_TextBase) @@ -629,7 +685,7 @@ SKIF_UI_Tab_DrawSettings (void) #pragma endregion #pragma region Section: Advanced - if (ImGui::CollapsingHeader ("Advanced###SKIF_SettingsHeader-3", ImGuiTreeNodeFlags_DefaultOpen)) + if (ImGui::CollapsingHeader ("Advanced###SKIF_SettingsHeader-4", ImGuiTreeNodeFlags_DefaultOpen)) { ImGui::PushStyleColor ( ImGuiCol_Text, ImGui::GetStyleColorVec4(ImGuiCol_SKIF_TextBase) diff --git a/src/tabs/viewer.cpp b/src/tabs/viewer.cpp index b4febdb..0ddb5b7 100644 --- a/src/tabs/viewer.cpp +++ b/src/tabs/viewer.cpp @@ -415,7 +415,7 @@ bool iconicBeforeSnip = false; bool trayedBeforeSnip = false; HWND hwndBeforeSnip = 0; HWND hwndTopBeforeSnip = 0; // Window above SKIV in z-order -ImRect selection_rect = { }; +//ImRect selection_rect = { }; bool coverRefresh = false; // This just triggers a refresh of the cover std::wstring coverRefreshPath = L""; @@ -2725,7 +2725,7 @@ SKIF_UI_Tab_DrawViewer (void) SUCCEEDED (DirectX::CopyRectangle (*captured_img.GetImages (), src_rect, *subrect.GetImages (), DirectX::TEX_FILTER_DEFAULT, 0, 0))) { - if (SKIV_Image_CopyToClipboard (subrect.GetImages (), true, cover.is_hdr)) + if (SKIV_Image_CopyToClipboard (subrect.GetImages (), cover.is_hdr, true, L"cp_rect")) { ImGui::InsertNotification ( { @@ -2760,7 +2760,7 @@ SKIF_UI_Tab_DrawViewer (void) else { - if (SKIV_Image_CopyToClipboard (captured_img.GetImages (), false, cover.is_hdr)) + if (SKIV_Image_CopyToClipboard (captured_img.GetImages (), cover.is_hdr, true, L"cp_full")) { ImGui::InsertNotification ( { @@ -3304,6 +3304,8 @@ SKIF_UI_Tab_DrawViewer (void) ImGui::InsertNotification (toast); } + static ImRect selection_rect = ImRect (); + if ((io.KeyCtrl && SKIF_ImGui_SelectionRect (&selection_rect, image_rect))) { // Flip an inverted rectangle @@ -3337,7 +3339,8 @@ SKIF_UI_Tab_DrawViewer (void) } ); */ - + + selection_rect = ImRect (); // Reset wantCopyToClipboard = true; copyRect = translated; } diff --git a/src/utility/fsutil.cpp b/src/utility/fsutil.cpp index 10f0f48..5f94a14 100644 --- a/src/utility/fsutil.cpp +++ b/src/utility/fsutil.cpp @@ -337,6 +337,7 @@ SKIF_CommonPathsCache::SKIF_CommonPathsCache (void) { // Cache user profile locations SKIF_GetFolderPath ( &my_documents ); + SKIF_GetFolderPath ( &my_pictures ); SKIF_GetFolderPath ( &app_data_local ); SKIF_GetFolderPath ( &app_data_local_low ); SKIF_GetFolderPath ( &app_data_roaming ); diff --git a/src/utility/image.cpp b/src/utility/image.cpp index cc3284c..088eaac 100644 --- a/src/utility/image.cpp +++ b/src/utility/image.cpp @@ -1078,7 +1078,7 @@ SKIV_PNG_CopyToClipboard (const DirectX::Image& image, const void *pData, size_t return false; } -bool SKIV_Image_CopyToClipboard (const DirectX::Image* pImage, bool snipped, bool isHDR) +bool SKIV_Image_CopyToClipboard (const DirectX::Image* pImage, bool isHDR, bool isTemp, const wchar_t* wszFileName) { using namespace DirectX; @@ -1087,10 +1087,32 @@ using namespace DirectX; static SKIF_CommonPathsCache& _path_cache = SKIF_CommonPathsCache::GetInstance ( ); - std::wstring wsPNGPath = _path_cache.skiv_temp; - wsPNGPath += snipped ? L"SKIV_Snip" - : L"SKIV_Clipboard"; - wsPNGPath += L".png"; + std::wstring wsPNGPath = (isTemp) ? _path_cache.skiv_temp : _path_cache.skiv_screenshots; + std::wstring wsFilename = std::wstring (wszFileName); + + wsFilename += L"_"; + + // DateTime + SYSTEMTIME st; + GetLocalTime(&st); + + // Buffers for formatted output + wchar_t dateBuffer[100]; + wchar_t timeBuffer[100]; + + // Get locale-aware date + if (GetDateFormatEx (LOCALE_NAME_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, dateBuffer, 100, NULL)) + wsFilename += std::wstring(dateBuffer); + + wsFilename += L"_"; + + // Get locale-aware time + if (GetTimeFormatEx (LOCALE_NAME_USER_DEFAULT, 0, &st, NULL, timeBuffer, 100)) + wsFilename += std::wstring(timeBuffer); + + wsFilename = SKIF_Util_StripInvalidFilenameChars (wsFilename); + + wsPNGPath += wsFilename + L".png"; PLOG_VERBOSE << wsPNGPath; @@ -1156,14 +1178,19 @@ using namespace DirectX; if (snipping_tonemap_mode && isHDR) { if (SUCCEEDED (SKIV_Image_TonemapToSDR (*pImage, tonemapped_sdr, SKIV_DesktopImage._max_display_nits, SKIV_DesktopImage._sdr_display_nits))) - { pImage = tonemapped_sdr.GetImage (0,0,0); - } - else PLOG_INFO << "SKIV_Image_TonemapToSDR ( ): FAILED!"; } + if (_registry.bSaveScreenshots) + { + if (SUCCEEDED (SKIV_Image_SaveToDisk_SDR (*pImage, wsPNGPath.c_str(), false))) + PLOG_VERBOSE << "SKIV_Image_SaveToDisk_SDR ( ): SUCCEEDED!"; + else + PLOG_VERBOSE << "SKIF_Image_SaveToDisk_HDR ( ): FAILED"; + } + const int _bpc = (int)(DirectX::BitsPerPixel (pImage->format)), @@ -3374,11 +3401,11 @@ SKIV_Image_CaptureDesktop (DirectX::ScratchImage& image, POINT point, int flags) } void -SKIV_Image_CaptureRegion (ImRect capture_area) +SKIV_Image_CaptureRegion (SKIV_Region capture_area) { HMONITOR hMonCaptured = - MonitorFromPoint ({ static_cast (capture_area.Min.x), - static_cast (capture_area.Min.y) }, MONITOR_DEFAULTTONEAREST); + MonitorFromPoint ({ static_cast (capture_area._rect.Min.x), + static_cast (capture_area._rect.Min.y) }, MONITOR_DEFAULTTONEAREST); MONITORINFO minfo = { .cbSize = sizeof (MONITORINFO) }; GetMonitorInfo (hMonCaptured, &minfo); @@ -3386,11 +3413,11 @@ SKIV_Image_CaptureRegion (ImRect capture_area) // Fixes snipping rectangles on non-primary (origin != 0,0) displays auto _AdjustCaptureAreaRelativeToDisplayOrigin = [&](void) { - capture_area.Min.x -= minfo.rcMonitor.left; - capture_area.Max.x -= minfo.rcMonitor.left; + capture_area._rect.Min.x -= minfo.rcMonitor.left; + capture_area._rect.Max.x -= minfo.rcMonitor.left; - capture_area.Min.y -= minfo.rcMonitor.top; - capture_area.Max.y -= minfo.rcMonitor.top; + capture_area._rect.Min.y -= minfo.rcMonitor.top; + capture_area._rect.Max.y -= minfo.rcMonitor.top; }; _AdjustCaptureAreaRelativeToDisplayOrigin (); @@ -3403,18 +3430,18 @@ SKIV_Image_CaptureRegion (ImRect capture_area) width = static_cast (minfo.rcMonitor.bottom - minfo.rcMonitor.top); - std::swap (capture_area.Min.x, capture_area.Min.y); - std::swap (capture_area.Max.x, capture_area.Max.y); + std::swap (capture_area._rect.Min.x, capture_area._rect.Min.y); + std::swap (capture_area._rect.Max.x, capture_area._rect.Max.y); const float capture_height = - static_cast (capture_area.Max.y - capture_area.Min.y), + static_cast (capture_area._rect.Max.y - capture_area._rect.Min.y), capture_width = - static_cast (capture_area.Max.x - capture_area.Min.x); + static_cast (capture_area._rect.Max.x - capture_area._rect.Min.x); if (SKIV_DesktopImage._rotation == DXGI_MODE_ROTATION_ROTATE90) { - capture_area.Min.y = height - capture_area.Max.y; - capture_area.Max.y = height - capture_area.Max.y + capture_height; + capture_area._rect.Min.y = height - capture_area._rect.Max.y; + capture_area._rect.Max.y = height - capture_area._rect.Max.y + capture_height; } else @@ -3427,10 +3454,10 @@ SKIV_Image_CaptureRegion (ImRect capture_area) } const size_t - x = static_cast (std::max (0.0f, capture_area.Min.x)), - y = static_cast (std::max (0.0f, capture_area.Min.y)), - width = static_cast (std::max (0.0f, capture_area.GetWidth ())), - height = static_cast (std::max (0.0f, capture_area.GetHeight ())); + x = static_cast (std::max (0.0f, capture_area._rect.Min.x)), + y = static_cast (std::max (0.0f, capture_area._rect.Min.y)), + width = static_cast (std::max (0.0f, capture_area._rect.GetWidth ())), + height = static_cast (std::max (0.0f, capture_area._rect.GetHeight ())); const DirectX::Rect src_rect (x,y, width,height); @@ -3489,7 +3516,7 @@ SKIV_Image_CaptureRegion (ImRect capture_area) PLOG_VERBOSE << "DirectX::FlipRotate ( ): FAILED"; } - if (SKIV_Image_CopyToClipboard (final, true, SKIV_DesktopImage._hdr_image)) + if (SKIV_Image_CopyToClipboard (final, SKIV_DesktopImage._hdr_image, false, capture_area._title.c_str())) { PLOG_VERBOSE << "SKIV_Image_CopyToClipboard ( ): SUCCEEDED"; diff --git a/src/utility/registry.cpp b/src/utility/registry.cpp index 8e5452e..7059c63 100644 --- a/src/utility/registry.cpp +++ b/src/utility/registry.cpp @@ -378,6 +378,9 @@ SKIF_RegistrySettings::SKIF_RegistrySettings (void) if (regKVPathViewer.hasData(&hKey)) wsPathViewer = regKVPathViewer .getData (&hKey); + if (regKVPathScreenshots.hasData(&hKey)) + wsPathScreenshots = regKVPathScreenshots .getData (&hKey); + if (regKVAutoUpdateVersion.hasData(&hKey)) wsAutoUpdateVersion = regKVAutoUpdateVersion .getData (&hKey); @@ -397,6 +400,9 @@ SKIF_RegistrySettings::SKIF_RegistrySettings (void) if (regKV99thPercentileMaxCLL.hasData(&hKey)) b99thPercentileMaxCLL = regKV99thPercentileMaxCLL .getData (&hKey); + if (regKVSaveScreenshots.hasData(&hKey)) + bSaveScreenshots = regKVSaveScreenshots .getData (&hKey); + // These defaults to false, so no need to check if the registry has another value // since getData ( ) defaults to false for non-existent registry values bFirstLaunch = regKVFirstLaunch .getData (&hKey); diff --git a/src/utility/skif_imgui.cpp b/src/utility/skif_imgui.cpp index 5767e32..90bd62e 100644 --- a/src/utility/skif_imgui.cpp +++ b/src/utility/skif_imgui.cpp @@ -524,7 +524,7 @@ SKIF_ImGui_SelectionRect (ImRect* selection, ImDrawList* draw_list = ImGui::GetForegroundDrawList (); - draw_list->AddRect (selection->Min-inset, selection->Max+inset, ImGui::GetColorU32 (IM_COL32(0,130,216,255)), 0.0f, 0, 5.0f); // Border + draw_list->AddRect (selection->Min-inset, selection->Max+inset, ImGui::GetColorU32 (IM_COL32(0,130,216,255)), 0.0f, 0, 5.0f); // Border if (flags & SelectionFlag_Filled) draw_list->AddRectFilled (selection->Min, selection->Max, ImGui::GetColorU32 (IM_COL32(0,130,216,50))); // Background diff --git a/src/utility/utility.cpp b/src/utility/utility.cpp index 0c25b58..d272634 100644 --- a/src/utility/utility.cpp +++ b/src/utility/utility.cpp @@ -2700,6 +2700,50 @@ SKIF_Util_FileExplorer_SelectFile (PCWSTR filePath) delete data; } +static int +CALLBACK +SKIF_Util_FileExplorer_BrowseFolder_CallbackProc (HWND hWnd,UINT uMsg, LPARAM lParam, LPARAM lpData) +{ + UNREFERENCED_PARAMETER (lParam); + + if (uMsg == BFFM_INITIALIZED) + SendMessage (hWnd, BFFM_SETSELECTION, TRUE, lpData); + + return 0; +} + +std::wstring +SKIF_Util_FileExplorer_BrowseFolder (PCWSTR defaultPath) +{ + TCHAR path[MAX_PATH]; + + BROWSEINFO + bi = { }; + bi.lpszTitle = L"Select a new screenshot folder for SKIV to use:"; + bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE; + bi.lpfn = SKIF_Util_FileExplorer_BrowseFolder_CallbackProc; + bi.lParam = (LPARAM) defaultPath; + + LPITEMIDLIST pidl = SHBrowseForFolder ( &bi ); + + if ( pidl != 0 ) + { + // Get the name of the folder and put it in path + SHGetPathFromIDList ( pidl, path ); + + // Free memory used + IMalloc * imalloc = 0; + if ( SUCCEEDED( SHGetMalloc ( &imalloc )) ) + { + imalloc->Free ( pidl ); + imalloc->Release ( ); + } + + return path; + } + + return L""; +} #if NTDDI_VERSION < NTDDI_WIN10_RS5 // Effective Power Mode (Windows 10 1809+)