From c2d526dec9b34df8fa51fe2c92c0bd9889360baf Mon Sep 17 00:00:00 2001 From: omigamedev Date: Sun, 3 Feb 2019 14:36:48 +0100 Subject: [PATCH] save brushes settings --- src/app.cpp | 11 +++ src/app_dialogs.cpp | 6 +- src/asset.cpp | 4 +- src/asset.h | 2 +- src/node.cpp | 7 +- src/node_panel_brush.cpp | 207 ++++++++++++++++++++++++++++++--------- src/node_panel_brush.h | 38 ++++--- 7 files changed, 207 insertions(+), 68 deletions(-) diff --git a/src/app.cpp b/src/app.cpp index 2fa6cc1..0c6260a 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -143,6 +143,10 @@ void App::initLog() { LOG("error creating thumbs path: %s", [[err localizedDescription] cStringUsingEncoding:NSASCIIStringEncoding]); } + if (![[NSFileManager defaultManager] createDirectoryAtPath:[docpath stringByAppendingString:@"/settings"] withIntermediateDirectories:YES attributes:nil error:&err]) + { + LOG("error creating settings path: %s", [[err localizedDescription] cStringUsingEncoding:NSASCIIStringEncoding]); + } #elif defined(__OSX__) NSArray* paths = NSSearchPathForDirectoriesInDomains(NSPicturesDirectory, NSUserDomainMask, YES); NSString* docpath = [(NSString*)[paths objectAtIndex:0] stringByAppendingString:@"/PanoPainter"]; @@ -170,6 +174,10 @@ void App::initLog() { LOG("error creating thumbs path: %s", [[err localizedDescription] cStringUsingEncoding:NSASCIIStringEncoding]); } + if (![[NSFileManager defaultManager] createDirectoryAtPath:[docpath stringByAppendingString:@"/settings"] withIntermediateDirectories:YES attributes:nil error:&err]) + { + LOG("error creating settings path: %s", [[err localizedDescription] cStringUsingEncoding:NSASCIIStringEncoding]); + } #elif defined(_WIN32) //CHAR my_documents[MAX_PATH]; //HRESULT result = SHGetFolderPathA(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, my_documents); @@ -209,6 +217,9 @@ void App::initLog() if (!PathFileExistsA((data_path + "\\brushes\\thumbs").c_str())) CreateDirectoryA((data_path + "\\brushes\\thumbs").c_str(), NULL); + + if (!PathFileExistsA((data_path + "\\settings").c_str())) + CreateDirectoryA((data_path + "\\settings").c_str(), NULL); #endif // TODO: save this path somewhere in the settings, don't overwrite every start diff --git a/src/app_dialogs.cpp b/src/app_dialogs.cpp index 0ef5c79..43bf79d 100644 --- a/src/app_dialogs.cpp +++ b/src/app_dialogs.cpp @@ -124,7 +124,7 @@ void App::dialog_newdoc() App::I.hideKeyboard(); }; - if (Asset::exist(path, false)) + if (Asset::exist(path)) { // ask confirm is file already exist auto msgbox = new NodeMessageBox(); @@ -331,7 +331,7 @@ void App::dialog_save_ver() static char tmp_name[256]; sprintf(tmp_name, "%s.%02d", base.c_str(), i); next = tmp_name; - if (Asset::exist(doc_dir + "/" + next + ".ppi", false)) + if (Asset::exist(doc_dir + "/" + next + ".ppi")) continue; break; } @@ -382,7 +382,7 @@ void App::dialog_save() App::I.hideKeyboard(); }; - if (Asset::exist(path, false)) + if (Asset::exist(path)) { // ask confirm is file already exist auto msgbox = new NodeMessageBox(); diff --git a/src/asset.cpp b/src/asset.cpp index b7ebca8..c1761e0 100644 --- a/src/asset.cpp +++ b/src/asset.cpp @@ -18,9 +18,9 @@ bool Asset::delete_file(const std::string& path) return true; } -bool Asset::exist(std::string path, bool is_asset) +bool Asset::exist(std::string path) { - if (is_asset) + if (Asset::is_asset(path)) { Asset asset; if (asset.open(path.c_str())) diff --git a/src/asset.h b/src/asset.h index 214f7a6..a129e47 100644 --- a/src/asset.h +++ b/src/asset.h @@ -8,7 +8,7 @@ public: AAsset* m_asset = nullptr; #endif static std::vector list_files(std::string folder, bool is_asset, const std::string& filter_regex); - static bool exist(std::string path, bool is_asset); + static bool exist(std::string path); static bool delete_file(const std::string& path); static std::string absolute(const std::string& path); static bool is_asset(const std::string& path); diff --git a/src/node.cpp b/src/node.cpp index 16a8bea..56a109d 100644 --- a/src/node.cpp +++ b/src/node.cpp @@ -266,7 +266,7 @@ void Node::add_child(std::shared_ptr n) void Node::add_child(std::shared_ptr n, int index) { - m_children.push_back(n); + m_children.insert(m_children.begin() + index, n); n->parent = this; n->m_manager = m_manager; YGNodeInsertChild(y_node, n->y_node, index); @@ -301,6 +301,11 @@ void Node::move_child(Node* n, int index) { YGNodeRemoveChild(y_node, n->y_node); YGNodeInsertChild(y_node, n->y_node, index); + auto it = std::find_if(m_children.begin(), m_children.end(), + [n](const std::shared_ptr& o) { return o.get() == n; }); + auto tmp = *it; // copy the ptr before removing it + m_children.erase(it); + m_children.insert(m_children.begin() + index, tmp); } void Node::move_child_offset(Node* n, int offset) diff --git a/src/node_panel_brush.cpp b/src/node_panel_brush.cpp index bb40fc6..6121116 100644 --- a/src/node_panel_brush.cpp +++ b/src/node_panel_brush.cpp @@ -47,7 +47,6 @@ Node* NodePanelBrush::clone_instantiate() const void NodePanelBrush::init() { init_template("tpl-panel-brushes"); - static auto icons = Asset::list_files("data/thumbs", true, ".*\\.png$"); m_btn_add = find("btn-add"); m_btn_add->on_click = [this](Node*) { @@ -80,10 +79,12 @@ void NodePanelBrush::init() brush->thumb_path = path_thumb; brush->high_path = path_high; brush->brush_name = name; + brush->m_user_brush = true; brush->on_click = std::bind(&NodePanelBrush::handle_click, this, std::placeholders::_1); app_redraw(); async_end(); + save(); } } }); @@ -94,8 +95,12 @@ void NodePanelBrush::init() if (m_current) { int idx = m_container->get_child_index(m_current); - Asset::delete_file(m_current->thumb_path); - Asset::delete_file(m_current->high_path); + if (m_current->m_user_brush) + { + // only delete user brushes + Asset::delete_file(m_current->thumb_path); + Asset::delete_file(m_current->high_path); + } m_container->remove_child(m_current); if (m_container->m_children.size() > 0) { @@ -109,12 +114,37 @@ void NodePanelBrush::init() { m_current = nullptr; } + save(); } }; - if ((m_container = find("brushes"))) + m_btn_up = find("btn-up"); + m_btn_up->on_click = [this](Node*) { + if (m_current) + { + int idx = m_container->get_child_index(m_current); + idx = std::max(0, std::min(idx - 1, (int)m_container->m_children.size() - 1)); + m_container->move_child(m_current, idx); + save(); + } + }; + + m_btn_down = find("btn-down"); + m_btn_down->on_click = [this](Node*) { + if (m_current) + { + int idx = m_container->get_child_index(m_current); + idx = std::max(0, std::min(idx + 1, (int)m_container->m_children.size() - 1)); + m_container->move_child(m_current, idx); + save(); + } + }; + + m_container = find("brushes"); + restore(); + if (m_container->m_children.empty()) { - int count = 0; + auto icons = Asset::list_files("data/brushes", true, ".*\\.png$"); for (auto& i : icons) { std::string path = "data/thumbs/" + i; @@ -128,6 +158,7 @@ void NodePanelBrush::init() brush->thumb_path = path; brush->high_path = path_hi; brush->brush_name = i; + brush->m_user_brush = false; // system brush, cannot be deleted from file brush->on_click = std::bind(&NodePanelBrush::handle_click, this, std::placeholders::_1); } @@ -145,9 +176,11 @@ void NodePanelBrush::init() brush->thumb_path = path_thumb; brush->high_path = path_high; brush->brush_name = i; + brush->m_user_brush = true; brush->on_click = std::bind(&NodePanelBrush::handle_click, this, std::placeholders::_1); } } + save(); } kEventResult NodePanelBrush::handle_event(Event* e) @@ -203,25 +236,94 @@ std::string NodePanelBrush::get_thumb_path(int index) const return ((NodeButtonBrush*)m_container->m_children[index].get())->thumb_path; } -// select the current brush based on the texture id -//void NodePanelBrush::select_brush(int brush_id) -//{ -// if (m_current) -// m_current->m_selected = false; -// for (auto b : m_brushes) -// { -// if (b->m_brushID == brush_id) -// { -// b->m_selected = true; -// m_current = b; -// TextureManager::load(b->high_path.c_str(), true); -// } -// } -//} +bool NodePanelBrush::save() +{ + auto path = App::I.data_path + "/settings/brushes.bin"; + if (FILE* fp = fopen(path.c_str(), "wb")) + { + header_t h; + h.brushes = m_container->m_children.size(); + fwrite(&h, sizeof(h), 1, fp); + for (const auto& child : m_container->m_children) + { + auto b = std::static_pointer_cast(child); + item_t i; + i.m_name_len = b->brush_name.size(); + i.m_high_len = b->high_path.size(); + i.m_thumb_len = b->thumb_path.size(); + fwrite(&i, sizeof(i), 1, fp); + fwrite(b->brush_name.c_str(), 1, b->brush_name.size(), fp); + fwrite(b->high_path.c_str(), 1, b->high_path.size(), fp); + fwrite(b->thumb_path.c_str(), 1, b->thumb_path.size(), fp); + } + for (const auto& d : m_deleted) + { + item_t i; + i.m_high_len = d.size(); + i.m_thumb_len = 0; + fwrite(&i, sizeof(i), 1, fp); + fwrite(d.c_str(), 1, d.size(), fp); + } + fclose(fp); + return true; + } + return false; +} + +bool NodePanelBrush::restore() +{ + auto path = App::I.data_path + "/settings/brushes.bin"; + if (FILE* fp = fopen(path.c_str(), "rb")) + { + header_t h; + fread(&h, sizeof(h), 1, fp); + if (strcmp(h.magic, "PPBR") != 0) + { + fclose(fp); + LOG("Brushes file malformed: %s", path.c_str()); + return false; + } + if (h.version < 0 || h.version > 0) + { + fclose(fp); + LOG("Brushes file version %d not supported: %s", h.version, path.c_str()); + return false; + } + + for (int k = 0; k < h.brushes; k++) + { + item_t i; + fread(&i, sizeof(i), 1, fp); + std::string name(i.m_name_len, 0); + std::string path_high(i.m_high_len, 0); + std::string path_thumb(i.m_thumb_len, 0); + fread((char*)name.c_str(), 1, name.size(), fp); + fread((char*)path_high.c_str(), 1, path_high.size(), fp); + fread((char*)path_thumb.c_str(), 1, path_thumb.size(), fp); + + if (Asset::exist(path_high)) + { + NodeButtonBrush* brush = new NodeButtonBrush; + m_container->add_child(brush); + brush->init(); + brush->create(); + brush->loaded(); + brush->set_icon(path_thumb.c_str()); + brush->thumb_path = path_thumb; + brush->high_path = path_high; + brush->brush_name = name; + brush->m_user_brush = true; + brush->on_click = std::bind(&NodePanelBrush::handle_click, this, std::placeholders::_1); + } + } + fclose(fp); + return true; + } + return false; +} // ----------------------------------------------------------------------- - Node* NodeBrushPresetItem::clone_instantiate() const { return new NodeBrushPresetItem(); @@ -244,11 +346,6 @@ void NodeBrushPresetItem::draw() NodeButtonCustom::draw(); } -NodeBrushPresetItem::~NodeBrushPresetItem() -{ - bool u = m_brush.unique(); -} - //--- Node* NodePanelBrushPreset::clone_instantiate() const @@ -361,15 +458,15 @@ void NodePanelBrushPreset::handle_click(Node* target) bool NodePanelBrushPreset::save() { - auto path = App::I.data_path + "/presets.bin"; + auto path = App::I.data_path + "/settings/presets.bin"; if (FILE* fp = fopen(path.c_str(), "wb")) { header_t h; h.count = m_container->m_children.size(); fwrite(&h, sizeof(h), 1, fp); - for (const auto& child : m_container->m_children) + for (int ci = 0; ci < m_container->m_children.size(); ci++) { - auto b = std::static_pointer_cast(child); + auto b = static_cast(m_container->get_child_at(ci)); item_t i; i.m_name_len = b->m_brush->m_name.size(); i.m_brush_path_len = b->m_brush->m_brush_path.size(); @@ -409,18 +506,31 @@ bool NodePanelBrushPreset::save() fwrite(b->m_brush->m_stencil_path.c_str(), 1, b->m_brush->m_stencil_path.size(), fp); } fclose(fp); + return true; } return false; } bool NodePanelBrushPreset::restore() { - auto path = App::I.data_path + "/presets.bin"; + auto path = App::I.data_path + "/settings/presets.bin"; if (FILE* fp = fopen(path.c_str(), "rb")) { header_t h; fread(&h, sizeof(h), 1, fp); - + if (strcmp(h.magic, "PPPR") != 0) + { + fclose(fp); + LOG("Presets file malformed: %s", path.c_str()); + return false; + } + if (h.version < 0 || h.version > 0) + { + fclose(fp); + LOG("Presets file version %d not supported: %s", h.version, path.c_str()); + return false; + } + for (int k = 0; k < h.count; k++) { item_t i; @@ -462,25 +572,28 @@ bool NodePanelBrushPreset::restore() fread((char*)b->m_brush_thumb_path.c_str(), 1, b->m_brush_thumb_path.size(), fp); fread((char*)b->m_stencil_path.c_str(), 1, b->m_stencil_path.size(), fp); - b->load_texture(b->m_brush_path, b->m_brush_thumb_path); - if (!b->m_stencil_path.empty()) - b->load_stencil(b->m_stencil_path); + if (b->load_texture(b->m_brush_path, b->m_brush_thumb_path)) + { + if (!b->m_stencil_path.empty()) + b->load_stencil(b->m_stencil_path); - NodeBrushPresetItem* brush = new NodeBrushPresetItem; - m_container->add_child(brush); - brush->init(); - brush->create(); - brush->loaded(); - brush->thumb_path = b->m_brush_thumb_path; - brush->high_path = b->m_brush_path; - brush->m_brush = b; - brush->m_brush->m_tip_size = .05f; - brush->m_preview->m_brush = b; - brush->m_preview->draw_stroke(); - brush->m_thumb->set_image(brush->m_brush->m_brush_thumb_path); - brush->on_click = std::bind(&NodePanelBrushPreset::handle_click, this, std::placeholders::_1); + NodeBrushPresetItem* brush = new NodeBrushPresetItem; + m_container->add_child(brush); + brush->init(); + brush->create(); + brush->loaded(); + brush->thumb_path = b->m_brush_thumb_path; + brush->high_path = b->m_brush_path; + brush->m_brush = b; + brush->m_brush->m_tip_size = .05f; + brush->m_preview->m_brush = b; + brush->m_preview->draw_stroke(); + brush->m_thumb->set_image(brush->m_brush->m_brush_thumb_path); + brush->on_click = std::bind(&NodePanelBrushPreset::handle_click, this, std::placeholders::_1); + } } fclose(fp); + return true; } return false; } diff --git a/src/node_panel_brush.h b/src/node_panel_brush.h index cfc43fc..d123fb1 100644 --- a/src/node_panel_brush.h +++ b/src/node_panel_brush.h @@ -9,12 +9,13 @@ class NodeButtonBrush : public NodeButtonCustom { public: - //int m_brushID; bool m_selected = false; + // whether the brush is a system default + // or user imported so it can be deleted from file + bool m_user_brush = false; std::string brush_name; std::string high_path; std::string thumb_path; - //uint16_t high_id; NodeImage* img; virtual Node* clone_instantiate() const override; virtual void init() override; @@ -24,13 +25,26 @@ public: class NodePanelBrush : public Node { - //std::vector m_brushes; + // brushes that are marked as deleted but file still exists + std::vector m_deleted; NodeButtonBrush* m_current = nullptr; NodeScroll* m_container; NodeButtonCustom* m_btn_add; NodeButtonCustom* m_btn_up; NodeButtonCustom* m_btn_down; NodeButtonCustom* m_btn_remove; + struct header_t { + char magic[5]{ 'P', 'P', 'B', 'R', 0 }; + uint16_t version = 0; + uint16_t brushes = 0; + uint16_t deleted = 0; + }; + struct item_t { + int m_name_len = 0; + int m_high_len = 0; + int m_thumb_len = 0; + bool m_deleted = false; + }; public: std::function on_brush_changed; std::function on_popup_close; @@ -41,7 +55,8 @@ public: int find_brush(const std::string& name) const; std::string get_texture_path(int index) const; std::string get_thumb_path(int index) const; - //void select_brush(int brush_id); + bool save(); + bool restore(); }; // ----------------------------------------------------------------------- @@ -58,12 +73,10 @@ public: virtual Node* clone_instantiate() const override; virtual void init() override; virtual void draw() override; - virtual ~NodeBrushPresetItem(); }; class NodePanelBrushPreset : public Node { - //std::vector m_brushes; NodeBrushPresetItem* m_current = nullptr; Node* m_container; NodeButtonCustom* m_btn_add; @@ -72,17 +85,15 @@ class NodePanelBrushPreset : public Node NodeButtonCustom* m_btn_delete; NodeButtonCustom* m_btn_save; struct header_t { - char magic[4]{ 'P', 'P', 'P', 'R' }; + char magic[5]{ 'P', 'P', 'P', 'R', 0 }; uint16_t version = 0; uint16_t count = 0; }; struct item_t { - int m_name_len; - int m_brush_path_len; - int m_brush_thumb_path_len; - int m_stencil_path_len; - //std::shared_ptr m_tip_texture; - //std::shared_ptr m_stencil_texture; + int m_name_len = 0; + int m_brush_path_len = 0; + int m_brush_thumb_path_len = 0; + int m_stencil_path_len = 0; glm::vec4 m_tip_color{ 0, 0, 0, 1 }; float m_tip_size = 0; float m_tip_spacing = 0; @@ -118,7 +129,6 @@ public: virtual void init() override; virtual kEventResult handle_event(Event* e) override; void handle_click(Node* target); - std::shared_ptr get_brush(int index) const; bool save(); bool restore(); };