diff --git a/src/app.cpp b/src/app.cpp index 9d44cc5..2fa6cc1 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -125,31 +125,50 @@ void App::initLog() NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString* docpath = (NSString*)[paths objectAtIndex:0]; data_path = [docpath cStringUsingEncoding:NSASCIIStringEncoding]; - + + NSError* err = nil; + NSString* recpath = [docpath stringByAppendingString:@"/rec"]; rec_path = [recpath cStringUsingEncoding:NSASCIIStringEncoding]; - NSError* recerr = nil; - if (![[NSFileManager defaultManager] createDirectoryAtPath:recpath withIntermediateDirectories:YES attributes:nil error:&recerr]) + if (![[NSFileManager defaultManager] createDirectoryAtPath:recpath withIntermediateDirectories:YES attributes:nil error:&err]) { - LOG("error creating rec path: %s", [[recerr localizedDescription] cStringUsingEncoding:NSASCIIStringEncoding]); + LOG("error creating rec path: %s", [[err localizedDescription] cStringUsingEncoding:NSASCIIStringEncoding]); + } + + if (![[NSFileManager defaultManager] createDirectoryAtPath:[docpath stringByAppendingString:@"/brushes"] withIntermediateDirectories:YES attributes:nil error:&err]) + { + LOG("error creating brushes path: %s", [[err localizedDescription] cStringUsingEncoding:NSASCIIStringEncoding]); + } + if (![[NSFileManager defaultManager] createDirectoryAtPath:[docpath stringByAppendingString:@"/brushes/thumbs"] withIntermediateDirectories:YES attributes:nil error:&err]) + { + LOG("error creating thumbs path: %s", [[err localizedDescription] cStringUsingEncoding:NSASCIIStringEncoding]); } #elif defined(__OSX__) NSArray* paths = NSSearchPathForDirectoriesInDomains(NSPicturesDirectory, NSUserDomainMask, YES); NSString* docpath = [(NSString*)[paths objectAtIndex:0] stringByAppendingString:@"/PanoPainter"]; - NSError* docerr = nil; - if (![[NSFileManager defaultManager] createDirectoryAtPath:docpath withIntermediateDirectories:YES attributes:nil error:&docerr]) + NSError* err = nil; + + if (![[NSFileManager defaultManager] createDirectoryAtPath:docpath withIntermediateDirectories:YES attributes:nil error:&err]) { - LOG("error creating rec path: %s", [[docerr localizedDescription] cStringUsingEncoding:NSASCIIStringEncoding]); + LOG("error creating rec path: %s", [[err localizedDescription] cStringUsingEncoding:NSASCIIStringEncoding]); } data_path = [docpath cStringUsingEncoding:NSASCIIStringEncoding]; NSString* recpath = [docpath stringByAppendingString:@"/rec"]; rec_path = [recpath cStringUsingEncoding:NSASCIIStringEncoding]; - NSError* recerr = nil; - if (![[NSFileManager defaultManager] createDirectoryAtPath:recpath withIntermediateDirectories:YES attributes:nil error:&recerr]) + if (![[NSFileManager defaultManager] createDirectoryAtPath:recpath withIntermediateDirectories:YES attributes:nil error:&err]) { - LOG("error creating rec path: %s", [[recerr localizedDescription] cStringUsingEncoding:NSASCIIStringEncoding]); + LOG("error creating rec path: %s", [[err localizedDescription] cStringUsingEncoding:NSASCIIStringEncoding]); + } + + if (![[NSFileManager defaultManager] createDirectoryAtPath:[docpath stringByAppendingString:@"/brushes"] withIntermediateDirectories:YES attributes:nil error:&err]) + { + LOG("error creating brushes path: %s", [[err localizedDescription] cStringUsingEncoding:NSASCIIStringEncoding]); + } + if (![[NSFileManager defaultManager] createDirectoryAtPath:[docpath stringByAppendingString:@"/brushes/thumbs"] withIntermediateDirectories:YES attributes:nil error:&err]) + { + LOG("error creating thumbs path: %s", [[err localizedDescription] cStringUsingEncoding:NSASCIIStringEncoding]); } #elif defined(_WIN32) //CHAR my_documents[MAX_PATH]; @@ -184,6 +203,12 @@ void App::initLog() rec_path = data_path + "\\frames"; if (!PathFileExistsA(rec_path.c_str())) CreateDirectoryA(rec_path.c_str(), NULL); + + if (!PathFileExistsA((data_path + "\\brushes").c_str())) + CreateDirectoryA((data_path + "\\brushes").c_str(), NULL); + + if (!PathFileExistsA((data_path + "\\brushes\\thumbs").c_str())) + CreateDirectoryA((data_path + "\\brushes\\thumbs").c_str(), NULL); #endif // TODO: save this path somewhere in the settings, don't overwrite every start diff --git a/src/image.cpp b/src/image.cpp index 6bf22ac..c917edc 100644 --- a/src/image.cpp +++ b/src/image.cpp @@ -39,6 +39,11 @@ bool Image::load_file(std::string filename) return true; } +bool Image::save(const std::string& path) +{ + return stbi_write_png(path.c_str(), width, height, comp, data(), 0); +} + void Image::flip() { auto flipped = std::make_unique(width*height*4); diff --git a/src/image.h b/src/image.h index 6e355bd..263d3db 100644 --- a/src/image.h +++ b/src/image.h @@ -11,6 +11,7 @@ public: bool load_file(std::string filename); const uint8_t* data() const { return m_data.get(); } int size() const { return width * height * comp; } + bool save(const std::string& path); void create(int w, int h) { width = w; diff --git a/src/node_panel_brush.cpp b/src/node_panel_brush.cpp index 4b7f8a6..bb40fc6 100644 --- a/src/node_panel_brush.cpp +++ b/src/node_panel_brush.cpp @@ -47,10 +47,72 @@ Node* NodePanelBrush::clone_instantiate() const void NodePanelBrush::init() { init_template("tpl-panel-brushes"); - //m_layers_container = find("layers-container"); static auto icons = Asset::list_files("data/thumbs", true, ".*\\.png$"); - if ((m_container = find("brushes"))) + m_btn_add = find("btn-add"); + m_btn_add->on_click = [this](Node*) { + App::I.pick_image([this](std::string path) { + Image img; + if (img.load_file(path)) + { + std::string name, base, ext; + std::regex r(R"((.*)[\\/]([^\\/]+)\.(\w+)$)"); + std::smatch m; + if (std::regex_search(path, m, r)) + { + base = m[1].str(); + name = m[2].str(); + ext = m[3].str(); + + std::string path_high = App::I.data_path + "/brushes/" + name + ".png"; + std::string path_thumb = App::I.data_path + "/brushes/thumbs/" + name + ".png"; + auto thumb = img.resize(64, 64); + thumb.save(path_thumb); + img.save(path_high); + + async_start(); + NodeButtonBrush* brush = new NodeButtonBrush; + m_container->add_child(brush); + brush->init(); + brush->create(); + brush->loaded(); + brush->set_icon(path.c_str()); + brush->thumb_path = path_thumb; + brush->high_path = path_high; + brush->brush_name = name; + brush->on_click = std::bind(&NodePanelBrush::handle_click, this, std::placeholders::_1); + + app_redraw(); + async_end(); + } + } + }); + }; + + m_btn_remove = find("btn-remove"); + m_btn_remove->on_click = [this](Node*) { + 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); + m_container->remove_child(m_current); + if (m_container->m_children.size() > 0) + { + idx = std::max(0, std::min(idx, (int)m_container->m_children.size() - 1)); + m_current = (NodeButtonBrush*)m_container->m_children[idx].get(); + m_current->m_selected = true; + if (on_brush_changed) + on_brush_changed(this, idx); + } + else + { + m_current = nullptr; + } + } + }; + + if ((m_container = find("brushes"))) { int count = 0; for (auto& i : icons) @@ -63,12 +125,26 @@ void NodePanelBrush::init() brush->create(); brush->loaded(); brush->set_icon(path.c_str()); - brush->m_brushID = count++; brush->thumb_path = path; brush->high_path = path_hi; brush->brush_name = i; - brush->high_id = const_hash(path_hi.c_str()); - m_brushes.push_back(brush); + brush->on_click = std::bind(&NodePanelBrush::handle_click, this, std::placeholders::_1); + } + + auto custom_icons = Asset::list_files(App::I.data_path + "/brushes", true, ".*\\.png$"); + for (auto& i : custom_icons) + { + std::string path_thumb = App::I.data_path + "/brushes/thumbs/" + i; + std::string path_high = App::I.data_path + "/brushes/" + i; + 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 = i; brush->on_click = std::bind(&NodePanelBrush::handle_click, this, std::placeholders::_1); } } @@ -103,46 +179,45 @@ void NodePanelBrush::handle_click(Node* target) m_current = (NodeButtonBrush*)target; m_current->m_selected = true; if (on_brush_changed) - on_brush_changed(this, m_current->m_brushID); + on_brush_changed(this, m_container->get_child_index(target)); } int NodePanelBrush::find_brush(const std::string & name) const { - for (int i = 0; i < m_brushes.size(); i++) + for (int i = 0; i < m_container->m_children.size(); i++) { - if (m_brushes[i]->brush_name.find(name) != std::string::npos) - { + NodeButtonBrush* b = (NodeButtonBrush*)m_container->m_children[i].get(); + if (b->brush_name.find(name) != std::string::npos) return i; - } } return -1; } std::string NodePanelBrush::get_texture_path(int index) const { - return m_brushes[index]->high_path; + return ((NodeButtonBrush*)m_container->m_children[index].get())->high_path; } std::string NodePanelBrush::get_thumb_path(int index) const { - return m_brushes[index]->thumb_path; + 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); - } - } -} +//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); +// } +// } +//} // ----------------------------------------------------------------------- diff --git a/src/node_panel_brush.h b/src/node_panel_brush.h index 62c3a90..cfc43fc 100644 --- a/src/node_panel_brush.h +++ b/src/node_panel_brush.h @@ -4,16 +4,17 @@ #include "node_image.h" #include "node_stroke_preview.h" #include "brush.h" +#include "node_scroll.h" class NodeButtonBrush : public NodeButtonCustom { public: - int m_brushID; + //int m_brushID; bool m_selected = false; std::string brush_name; std::string high_path; std::string thumb_path; - uint16_t high_id; + //uint16_t high_id; NodeImage* img; virtual Node* clone_instantiate() const override; virtual void init() override; @@ -23,11 +24,15 @@ public: class NodePanelBrush : public Node { - std::vector m_brushes; + //std::vector m_brushes; NodeButtonBrush* m_current = nullptr; - Node* m_container; + NodeScroll* m_container; + NodeButtonCustom* m_btn_add; + NodeButtonCustom* m_btn_up; + NodeButtonCustom* m_btn_down; + NodeButtonCustom* m_btn_remove; public: - std::function on_brush_changed; + std::function on_brush_changed; std::function on_popup_close; virtual Node* clone_instantiate() const override; virtual void init() override; @@ -36,7 +41,7 @@ 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); + //void select_brush(int brush_id); }; // -----------------------------------------------------------------------