git repos / sago_multi_scrambler_puzzle2

commit 84af5c25

Poul Sander · 2025-11-20 17:12
84af5c2509e0fce03ff0a4f04cbe85d20315f29e patch · browse files
parent 4d672c236baf517e251e898b3f08b64b0a85cb50

Add favorite functionality.

Changed files

M src/ImageSelectState.cpp before
M src/ImageSelectState.hpp before
M src/config.cpp before
M src/config.hpp before
diff --git a/src/ImageSelectState.cpp b/src/ImageSelectState.cpp index b837709..fe5da74 100644 --- a/src/ImageSelectState.cpp +++ b/src/ImageSelectState.cpp
@@ -28,6 +28,7 @@ https://github.com/sago007/saland
#include "PuzzleSingleImageState.hpp"
#include "sago_common.hpp"
#include "SagoImGui.hpp"
+#include "config.hpp"
static void DrawRect(SDL_Renderer* target, int topx, int topy, int height, int width, const std::string& name) {
const int size = 32;
@@ -144,6 +145,39 @@ void ImageSelectState::Draw(SDL_Renderer* target) {
imageNameFields[image_number].Draw(target, text_x_physical, text_y_physical,
sago::SagoTextField::Alignment::center, sago::SagoTextField::VerticalAlignment::bottom);
}
+
+ // Draw favorite indicator as ImGui button overlay
+ if (image_number < imageList.size()) {
+ bool isFavorite = IsFavorite(imageList[image_number]);
+ int star_x_physical, star_y_physical;
+ logicalResize.LogicalToPhysical(
+ frame_logical.x + frame_size - 40,
+ frame_logical.y + 10,
+ star_x_physical, star_y_physical);
+
+ ImGui::SetNextWindowPos(ImVec2(star_x_physical, star_y_physical));
+ ImGui::SetNextWindowSize(ImVec2(0, 0));
+ ImGui::Begin(("##favorite" + std::to_string(image_number)).c_str(),
+ nullptr,
+ ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize |
+ ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar |
+ ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_AlwaysAutoResize |
+ ImGuiWindowFlags_NoBackground);
+
+ const char* starText = isFavorite ? "★" : "☆";
+ if (ImGui::Button(starText)) {
+ if (isFavorite) {
+ RemoveFavorite(imageList[image_number]);
+ } else {
+ AddFavorite(imageList[image_number]);
+ }
+ }
+ if (ImGui::IsItemHovered()) {
+ ImGui::SetTooltip(isFavorite ? "Remove from favorites" : "Add to favorites");
+ }
+
+ ImGui::End();
+ }
}
ImGui::BeginMainMenuBar();
@@ -153,6 +187,18 @@ void ImageSelectState::Draw(SDL_Renderer* target) {
}
ImGui::EndMenu();
}
+ if (ImGui::BeginMenu("View")) {
+ if (ImGui::MenuItem("Show Only Favorites", nullptr, showOnlyFavorites)) {
+ showOnlyFavorites = !showOnlyFavorites;
+ // Reload the image list with the new filter
+ imageList.clear();
+ imageNameFields.clear();
+ imageHolders.clear();
+ firstImage = 0;
+ Init();
+ }
+ ImGui::EndMenu();
+ }
ImGui::EndMainMenuBar();
ImGui::Begin("Page control");
if (ImGui::Button("Next page")) {
@@ -179,6 +225,11 @@ void ImageSelectState::Update() {
if (SDL_GetMouseState(nullptr,nullptr)&SDL_BUTTON(1) && globalData.mouseUp) {
globalData.mouseUp = false;
+ // Don't process clicks if ImGui wants to capture the mouse (e.g., clicking on buttons)
+ if (ImGui::GetIO().WantCaptureMouse) {
+ return;
+ }
+
// Convert physical mouse coordinates to logical coordinates
int mouse_x_logical, mouse_y_logical;
logicalResize.PhysicalToLogical(globalData.mousex, globalData.mousey, mouse_x_logical, mouse_y_logical);
@@ -263,13 +314,20 @@ void ImageSelectState::Init() {
if (!folder.empty()) {
for (const auto& entry : std::filesystem::directory_iterator(folder)) {
if (entry.is_regular_file() && (HasExtension(entry.path().string(), ".jpg") || HasExtension(entry.path().string(), ".jpeg") || HasExtension(entry.path().string(), ".png") ) ) {
+ std::string imagePath = entry.path().string();
+
+ // If showOnlyFavorites is enabled, skip non-favorite images
+ if (showOnlyFavorites && !IsFavorite(imagePath)) {
+ continue;
+ }
+
std::cout << entry.path() << std::endl;
- imageList.push_back(entry.path().string());
+ imageList.push_back(imagePath);
sago::SagoTextField field;
setFontText(globalData.dataHolder, field, entry.path().filename().string().c_str());
imageNameFields.push_back(std::move(field));
imageHolders.emplace_back();
- imageHolders.back().LoadPictureFromFileLazy(entry.path().string());
+ imageHolders.back().LoadPictureFromFileLazy(imagePath);
}
}
}
diff --git a/src/ImageSelectState.hpp b/src/ImageSelectState.hpp index 7e5f8b8..70b11ed 100644 --- a/src/ImageSelectState.hpp +++ b/src/ImageSelectState.hpp
@@ -53,6 +53,7 @@ public:
private:
bool isActive = true;
+ bool showOnlyFavorites = false;
sago::SagoLogicalResize logicalResize;
};
diff --git a/src/config.cpp b/src/config.cpp index 490016f..2067fb9 100644 --- a/src/config.cpp +++ b/src/config.cpp
@@ -25,6 +25,7 @@ SOFTWARE.
#include "config.hpp"
#include "os.hpp"
#include <fstream>
+#include <vector>
std::map<std::string, std::string> LoadConfigMap() {
std::map<std::string, std::string> config;
@@ -107,3 +108,73 @@ std::string GetConfigString(const std::map<std::string, std::string>& config, co
void SetConfigString(std::map<std::string, std::string>& config, const std::string& key, const std::string& value) {
config[key] = value;
}
+
+std::vector<std::string> LoadFavorites() {
+ std::vector<std::string> favorites;
+ std::string favoritesPath = getPathToSaveFiles() + "/favorites.txt";
+ std::ifstream favoritesFile(favoritesPath);
+
+ if (favoritesFile.is_open()) {
+ std::string line;
+ while (std::getline(favoritesFile, line)) {
+ if (!line.empty() && line[0] != '#') {
+ favorites.push_back(line);
+ }
+ }
+ favoritesFile.close();
+ }
+
+ return favorites;
+}
+
+void SaveFavorites(const std::vector<std::string>& favorites) {
+ std::string favoritesPath = getPathToSaveFiles() + "/favorites.txt";
+ std::ofstream favoritesFile(favoritesPath);
+
+ if (favoritesFile.is_open()) {
+ favoritesFile << "# Favorite images - one absolute path per line" << std::endl;
+ for (const auto& favorite : favorites) {
+ favoritesFile << favorite << std::endl;
+ }
+ favoritesFile.close();
+ }
+}
+
+void AddFavorite(const std::string& imagePath) {
+ std::vector<std::string> favorites = LoadFavorites();
+
+ // Check if already in favorites
+ for (const auto& fav : favorites) {
+ if (fav == imagePath) {
+ return;
+ }
+ }
+
+ favorites.push_back(imagePath);
+ SaveFavorites(favorites);
+}
+
+void RemoveFavorite(const std::string& imagePath) {
+ std::vector<std::string> favorites = LoadFavorites();
+ std::vector<std::string> newFavorites;
+
+ for (const auto& fav : favorites) {
+ if (fav != imagePath) {
+ newFavorites.push_back(fav);
+ }
+ }
+
+ SaveFavorites(newFavorites);
+}
+
+bool IsFavorite(const std::string& imagePath) {
+ std::vector<std::string> favorites = LoadFavorites();
+
+ for (const auto& fav : favorites) {
+ if (fav == imagePath) {
+ return true;
+ }
+ }
+
+ return false;
+}
diff --git a/src/config.hpp b/src/config.hpp index 11a41ea..0100d37 100644 --- a/src/config.hpp +++ b/src/config.hpp
@@ -27,6 +27,7 @@ SOFTWARE.
#include <string>
#include <map>
+#include <vector>
/**
* @brief Loads configuration from file into a map
@@ -91,4 +92,35 @@ std::string GetConfigString(const std::map<std::string, std::string>& config, co
*/
void SetConfigString(std::map<std::string, std::string>& config, const std::string& key, const std::string& value);
+/**
+ * @brief Loads the list of favorite image paths
+ * @return Vector of absolute paths to favorite images
+ */
+std::vector<std::string> LoadFavorites();
+
+/**
+ * @brief Saves the list of favorite image paths
+ * @param favorites Vector of absolute paths to favorite images
+ */
+void SaveFavorites(const std::vector<std::string>& favorites);
+
+/**
+ * @brief Adds an image path to favorites
+ * @param imagePath Absolute path to the image
+ */
+void AddFavorite(const std::string& imagePath);
+
+/**
+ * @brief Removes an image path from favorites
+ * @param imagePath Absolute path to the image
+ */
+void RemoveFavorite(const std::string& imagePath);
+
+/**
+ * @brief Checks if an image path is in favorites
+ * @param imagePath Absolute path to the image
+ * @return true if the image is a favorite, false otherwise
+ */
+bool IsFavorite(const std::string& imagePath);
+
#endif // CONFIG_HPP