#include "pch.h"
#include "log.h"
#include "node_panel_brush.h"
#include "asset.h"
#include "texture.h"

#ifdef __APPLE__
#include <Foundation/Foundation.h>
#endif
#include "canvas.h"
#include "app.h"
#include "abr.h"

Node* NodeButtonBrush::clone_instantiate() const
{
    return new NodeButtonBrush();
}

void NodeButtonBrush::init()
{
    init_template("tpl-brush-icon");
    color_hover = glm::vec4(.7, .7, .7, 1);
    color_normal = glm::vec4(.3, .3, .3, 1);
    m_color = color_normal;
    img = (NodeImage*)m_children[0].get();
}

void NodeButtonBrush::set_icon(const char* path)
{
    img->m_path = path;
    img->m_tex_id = const_hash(img->m_path.c_str());
    img->m_use_mipmaps = true;
    img->create();
}

void NodeButtonBrush::draw()
{
    m_color = m_mouse_inside ? color_hover : color_normal;
    m_color = m_selected ? glm::vec4(.9, 0, 0, 1) : m_color;
    NodeButtonCustom::draw();
}

Node* NodePanelBrush::clone_instantiate() const
{
    return new NodePanelBrush();
}

void NodePanelBrush::init()
{
    init_template("tpl-panel-brushes");

    m_btn_add = find<NodeButtonCustom>("btn-add");
    m_btn_add->on_click = [this](Node*) {
        App::I.pick_file({ "JPG", "PNG" }, [this](std::string path) {
            std::string name, base, ext;
            std::regex r(R"((.*)[\\/]([^\\/]+)\.(\w+)$)");
            std::smatch m;
            if (!std::regex_search(path, m, r))
                return;
            base = m[1].str();
            name = m[2].str();
            ext = m[3].str();
            Image img;
            if (!m_dir_name.empty() && img.load_file(path))
            {
                std::string path_high = App::I.data_path + "/" + m_dir_name + "/" + name + ".png";
                std::string path_thumb = App::I.data_path + "/" + m_dir_name + "/thumbs/" + name + ".png";

                img = img.resize_squared(glm::u8vec4(255));
                //img.gayscale_alpha();

                auto thumb = img.resize(64, 64);
                thumb.save(path_thumb);
                auto po2 = img.resize_power2();
                po2.save(path_high);

                async_start();
                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);
                app_redraw();
                async_end();
                save();
            }
        });
    };

    m_btn_remove = find<NodeButtonCustom>("btn-remove");
    m_btn_remove->on_click = [this](Node*) {
        if (m_current)
        {
            int idx = m_container->get_child_index(m_current);
            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)
            {
                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;
            }
            save();
        }
    };

    m_btn_up = find<NodeButtonCustom>("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<NodeButtonCustom>("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<NodeScroll>("brushes");
    restore();
    if (m_container->m_children.empty() && !m_dir_name.empty())
    {
        auto icons = Asset::list_files("data/" + m_dir_name, true, ".*\\.png$");
        for (auto& i : icons)
        {
            std::string path = "data/" + m_dir_name + "/thumbs/" + i;
            std::string path_hi = "data/" + m_dir_name + "/" + i;
            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;
            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);
        }

        auto custom_icons = Asset::list_files(App::I.data_path + "/" + m_dir_name, true, ".*\\.png$");
        for (auto& i : custom_icons)
        {
            std::string path_thumb = App::I.data_path + "/" + m_dir_name + "/thumbs/" + i;
            std::string path_high = App::I.data_path + "/" + m_dir_name + "/" + 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->m_user_brush = true;
            brush->on_click = std::bind(&NodePanelBrush::handle_click, this, std::placeholders::_1);
        }
    }
    save();
}

kEventResult NodePanelBrush::handle_event(Event* e)
{
    switch (e->m_type)
    {
    case kEventType::MouseUpL:
        if (!m_mouse_inside)
        {
            mouse_release();
            parent->remove_child(this);
            if (on_popup_close)
                on_popup_close(this);
        }
        break;
    default:
        return kEventResult::Available;
        break;
    }
    return kEventResult::Consumed;
}

void NodePanelBrush::handle_click(Node* target)
{
    if (target == m_current)
        return;
    if (m_current)
        m_current->m_selected = false;
    m_current = (NodeButtonBrush*)target;
    m_current->m_selected = true;
    if (on_brush_changed)
        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_container->m_children.size(); i++)
    {
        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
{
    if (index < 0 || index >= m_container->m_children.size())
        return "";
    return ((NodeButtonBrush*)m_container->m_children[index].get())->high_path;
}

std::string NodePanelBrush::get_thumb_path(int index) const
{
    if (index < 0 || index >= m_container->m_children.size())
        return "";
    return ((NodeButtonBrush*)m_container->m_children[index].get())->thumb_path;
}

bool NodePanelBrush::save()
{
    auto path = App::I.data_path + "/settings/" + m_dir_name + ".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<NodeButtonBrush>(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/" + m_dir_name + ".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 = i.m_user_brush;
                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();
}

void NodeBrushPresetItem::init()
{
    init_template("tpl-brush-preset");
    color_hover = glm::vec4(.7, .7, .7, 1);
    color_normal = glm::vec4(.3, .3, .3, 1);
    m_color = color_normal;
    m_thumb = find<NodeImage>("thumb");
    m_caption_size = find<NodeText>("caption-size");
    m_preview = find<NodeStrokePreview>("canvas");
    m_preview->m_min_flow = 1.f;
}

void NodeBrushPresetItem::draw()
{
    m_color = m_mouse_inside ? color_hover : color_normal;
    m_color = m_selected ? glm::vec4(.9, 0, 0, 1) : m_color;
    NodeButtonCustom::draw();
}

//---

Node* NodePanelBrushPreset::clone_instantiate() const
{
    return new NodePanelBrushPreset();
}

void NodePanelBrushPreset::init()
{
    init_template("tpl-panel-brush-preset");
    m_container = find<Node>("brushes");
    m_btn_add = find<NodeButtonCustom>("btn-add");
    m_btn_add->on_click = [this] (Node*) {
        add_brush(std::make_shared<Brush>(*Canvas::I->m_current_brush));
        save();
    };
    m_btn_up = find<NodeButtonCustom>("btn-up");
    m_btn_up->on_click = [this](Node*) {
        if (m_current)
        {
            m_container->move_child(m_current, std::max(m_container->get_child_index(m_current) - 1, 0));
            save();
        }
    };
    m_btn_down = find<NodeButtonCustom>("btn-down");
    m_btn_down->on_click = [this](Node*) {
        if (m_current)
        {
            m_container->move_child(m_current,
                std::min(m_container->get_child_index(m_current) + 1, (int)m_container->m_children.size() - 1));
            save();
        }
    };
    m_btn_save = find<NodeButtonCustom>("btn-save");
    m_btn_save->on_click = [this](Node*) {
        if (m_current)
        {
            *m_current->m_brush = *Canvas::I->m_current_brush;
            m_current->m_preview->draw_stroke();
            m_current->m_thumb->set_image(m_current->m_brush->m_brush_thumb_path);
            save();
        }
    };
    m_btn_delete = find<NodeButtonCustom>("btn-remove");
    m_btn_delete->on_click = [this](Node*) {
        if (!m_current)
            return;
        int index = m_container->get_child_index(m_current);
        m_current->destroy_immediate();
        m_container->remove_child(m_current);
        if (m_container->m_children.empty())
        {
            m_current = nullptr;
        }
        else
        {
            int next = std::min<int>(m_container->m_children.size() - 1, index);
            m_current = (NodeBrushPresetItem*)m_container->m_children[next].get();
            m_current->m_selected = true;
        }
        save();
    };

    restore();
}

kEventResult NodePanelBrushPreset::handle_event(Event* e)
{
    switch (e->m_type)
    {
    case kEventType::MouseUpL:
        if (!m_mouse_inside)
        {
            mouse_release();
            parent->remove_child(this);
            if (on_popup_close)
                on_popup_close(this);
        }
        break;
    default:
        return kEventResult::Available;
        break;
    }
    return kEventResult::Consumed;
}

void NodePanelBrushPreset::handle_click(Node* target)
{
    if (target == m_current)
        return;
    if (m_current)
        m_current->m_selected = false;
    m_current = (NodeBrushPresetItem*)target;
    m_current->m_selected = true;
    if (on_brush_changed)
        on_brush_changed(this, m_current->m_brush);
}

bool NodePanelBrushPreset::save()
{
    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 (int ci = 0; ci < m_container->m_children.size(); ci++)
        {
            auto bpi = static_cast<NodeBrushPresetItem*>(m_container->get_child_at(ci));
            auto& b = bpi->m_brush;
            item_t i;
            i.m_name_len = b->m_name.size();
            i.m_brush_path_len = b->m_brush_path.size();
            i.m_brush_thumb_path_len = b->m_brush_thumb_path.size();
            i.m_dual_path_len = b->m_dual_path.size();
            i.m_dual_thumb_path_len = b->m_dual_thumb_path.size();
            i.m_pattern_path_len = b->m_pattern_path.size();
            i.m_pattern_thumb_path_len = b->m_pattern_thumb_path.size();
            i.m_tip_color           = b->m_tip_color;
            i.m_tip_scale           = b->m_tip_scale;
            i.m_tip_size            = b->m_tip_size;
            i.m_tip_spacing         = b->m_tip_spacing;
            i.m_tip_flow            = b->m_tip_flow;
            i.m_tip_opacity         = b->m_tip_opacity;
            i.m_tip_angle           = b->m_tip_angle;
            i.m_tip_angle_smooth    = b->m_tip_angle_smooth;
            i.m_tip_mix             = b->m_tip_mix;
            i.m_tip_wet             = b->m_tip_wet;
            i.m_tip_noise           = b->m_tip_noise;
            i.m_tip_hue             = b->m_tip_hue;
            i.m_tip_sat             = b->m_tip_sat;
            i.m_tip_val             = b->m_tip_val;
            i.m_tip_angle_init      = b->m_tip_angle_init;
            i.m_tip_angle_follow    = b->m_tip_angle_follow;
            i.m_tip_flow_pressure   = b->m_tip_flow_pressure;
            i.m_tip_opacity_pressure= b->m_tip_opacity_pressure;
            i.m_tip_size_pressure   = b->m_tip_size_pressure;
            i.m_jitter_scale        = b->m_jitter_scale;
            i.m_jitter_angle        = b->m_jitter_angle;
            i.m_jitter_scatter      = b->m_jitter_scatter;
            i.m_jitter_scatter_bothaxis = b->m_jitter_scatter_bothaxis;
            i.m_jitter_flow         = b->m_jitter_flow;
            i.m_jitter_opacity      = b->m_jitter_opacity;
            i.m_jitter_hue          = b->m_jitter_hue;
            i.m_jitter_sat          = b->m_jitter_sat;
            i.m_jitter_val          = b->m_jitter_val;
            i.m_jitter_aspect       = b->m_jitter_aspect;
            i.m_jitter_aspect_bothaxis = b->m_jitter_aspect_bothaxis;
            i.m_blend_mode          = b->m_blend_mode;

            i.m_tip_invert          = b->m_tip_invert;
            i.m_tip_flipx           = b->m_tip_flipx;
            i.m_tip_flipy           = b->m_tip_flipy;
            i.m_pattern_enabled     = b->m_pattern_enabled;
            i.m_dual_enabled        = b->m_dual_enabled;
            i.m_dual_blend_mode     = b->m_dual_blend_mode;
            i.m_dual_randflip       = b->m_dual_randflip;
            i.m_dual_size           = b->m_dual_size;
            i.m_dual_spacing        = b->m_dual_spacing;
            i.m_dual_scatter        = b->m_dual_scatter;
            i.m_dual_scatter_bothaxis = b->m_dual_scatter_bothaxis;
            i.m_dual_invert         = b->m_dual_invert;
            i.m_dual_flipx          = b->m_dual_flipx;
            i.m_dual_flipy          = b->m_dual_flipy;
            i.m_tip_randflipx       = b->m_tip_randflipx;
            i.m_tip_randflipy       = b->m_tip_randflipy;
            i.m_tip_aspect          = b->m_tip_aspect;
            i.m_dual_flow           = b->m_dual_flow;
            i.m_dual_opacity        = b->m_dual_opacity;
            i.m_dual_rotate         = b->m_dual_rotate;
            i.m_dual_angle          = b->m_dual_angle;
            i.m_dual_count          = b->m_dual_count;
            i.m_dual_aspect         = b->m_dual_aspect;
            i.m_dual_scale          = b->m_dual_scale;

            i.m_pattern_eachsample  = b->m_pattern_eachsample;
            i.m_pattern_invert      = b->m_pattern_invert;
            i.m_pattern_flipx       = b->m_pattern_flipx;
            i.m_pattern_flipy       = b->m_pattern_flipy;
            i.m_pattern_scale       = b->m_pattern_scale;
            i.m_pattern_brightness  = b->m_pattern_brightness;
            i.m_pattern_contrast    = b->m_pattern_contrast;
            i.m_pattern_rand_offset = b->m_pattern_rand_offset;
            i.m_pattern_depth       = b->m_pattern_depth;

            fwrite(&i, sizeof(i), 1, fp);
            fwrite(b->m_name.c_str(), 1, b->m_name.size(), fp);
            fwrite(b->m_brush_path.c_str(), 1, b->m_brush_path.size(), fp);
            fwrite(b->m_brush_thumb_path.c_str(), 1, b->m_brush_thumb_path.size(), fp);
            fwrite(b->m_dual_path.c_str(), 1, b->m_dual_path.size(), fp);
            fwrite(b->m_dual_thumb_path.c_str(), 1, b->m_dual_thumb_path.size(), fp);
            fwrite(b->m_pattern_path.c_str(), 1, b->m_pattern_path.size(), fp);
            fwrite(b->m_pattern_thumb_path.c_str(), 1, b->m_pattern_thumb_path.size(), fp);
        }
        fclose(fp);
        return true;
    }
    return false;
}

bool NodePanelBrushPreset::restore()
{
    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;
            fread(&i, sizeof(i), 1, fp);
            auto b = std::make_shared<Brush>();
            b->m_tip_color          = i.m_tip_color;
            b->m_tip_scale          = i.m_tip_scale;
            b->m_tip_size           = i.m_tip_size;
            b->m_tip_spacing        = i.m_tip_spacing;
            b->m_tip_flow           = i.m_tip_flow;
            b->m_tip_opacity        = i.m_tip_opacity;
            b->m_tip_angle          = i.m_tip_angle;
            b->m_tip_angle_smooth   = i.m_tip_angle_smooth;
            b->m_tip_mix            = i.m_tip_mix;
            b->m_tip_wet            = i.m_tip_wet;
            b->m_tip_noise          = i.m_tip_noise;
            b->m_tip_hue            = i.m_tip_hue;
            b->m_tip_sat            = i.m_tip_sat;
            b->m_tip_val            = i.m_tip_val;
            b->m_tip_angle_init     = i.m_tip_angle_init;
            b->m_tip_angle_follow   = i.m_tip_angle_follow;
            b->m_tip_flow_pressure  = i.m_tip_flow_pressure;
            b->m_tip_opacity_pressure = i.m_tip_opacity_pressure;
            b->m_tip_size_pressure  = i.m_tip_size_pressure;
            b->m_jitter_scale       = i.m_jitter_scale;
            b->m_jitter_angle       = i.m_jitter_angle;
            b->m_jitter_scatter     = i.m_jitter_scatter;
            b->m_jitter_scatter_bothaxis = i.m_jitter_scatter_bothaxis;
            b->m_jitter_flow = i.m_jitter_flow;
            b->m_jitter_opacity     = i.m_jitter_opacity;
            b->m_jitter_hue         = i.m_jitter_hue;
            b->m_jitter_sat         = i.m_jitter_sat;
            b->m_jitter_val         = i.m_jitter_val;
            b->m_jitter_aspect      = i.m_jitter_aspect;
            b->m_jitter_aspect_bothaxis = i.m_jitter_aspect_bothaxis;
            b->m_blend_mode = i.m_blend_mode;

            b->m_tip_invert         = i.m_tip_invert;
            b->m_tip_flipx          = i.m_tip_flipx;
            b->m_tip_flipy          = i.m_tip_flipy;
            b->m_pattern_enabled    = i.m_pattern_enabled;
            b->m_dual_enabled       = i.m_dual_enabled;
            b->m_dual_blend_mode    = i.m_dual_blend_mode;
            b->m_dual_randflip      = i.m_dual_randflip;
            b->m_dual_size          = i.m_dual_size;
            b->m_dual_spacing       = i.m_dual_spacing;
            b->m_dual_scatter       = i.m_dual_scatter;
            b->m_dual_scatter_bothaxis = i.m_dual_scatter_bothaxis;
            b->m_dual_invert        = i.m_dual_invert;
            b->m_dual_flipx         = i.m_dual_flipx;
            b->m_dual_flipy         = i.m_dual_flipy;
            b->m_tip_randflipx      = i.m_tip_randflipx;
            b->m_tip_randflipy      = i.m_tip_randflipy;
            b->m_tip_aspect         = i.m_tip_aspect;
            b->m_dual_flow          = i.m_dual_flow;
            b->m_dual_opacity       = i.m_dual_opacity;
            b->m_dual_rotate        = i.m_dual_rotate;
            b->m_dual_angle         = i.m_dual_angle;
            b->m_dual_count         = i.m_dual_count;
            b->m_dual_aspect        = i.m_dual_aspect;
            b->m_dual_scale         = i.m_dual_scale;

            b->m_pattern_eachsample = i.m_pattern_eachsample;
            b->m_pattern_invert     = i.m_pattern_invert;
            b->m_pattern_flipx      = i.m_pattern_flipx;
            b->m_pattern_flipy      = i.m_pattern_flipy;
            b->m_pattern_scale      = i.m_pattern_scale;
            b->m_pattern_brightness = i.m_pattern_brightness;
            b->m_pattern_contrast   = i.m_pattern_contrast;
            b->m_pattern_rand_offset = i.m_pattern_rand_offset;
            b->m_pattern_depth      = i.m_pattern_depth;

            b->m_name.resize(i.m_name_len);
            b->m_brush_path.resize(i.m_brush_path_len);
            b->m_brush_thumb_path.resize(i.m_brush_thumb_path_len);
            b->m_dual_path.resize(i.m_dual_path_len);
            b->m_dual_thumb_path.resize(i.m_dual_thumb_path_len);
            b->m_pattern_path.resize(i.m_pattern_path_len);
            b->m_pattern_thumb_path.resize(i.m_pattern_thumb_path_len);
            fread((char*)b->m_name.c_str(), 1, b->m_name.size(), fp);
            fread((char*)b->m_brush_path.c_str(), 1, b->m_brush_path.size(), fp);
            fread((char*)b->m_brush_thumb_path.c_str(), 1, b->m_brush_thumb_path.size(), fp);
            fread((char*)b->m_dual_path.c_str(), 1, b->m_dual_path.size(), fp);
            fread((char*)b->m_dual_thumb_path.c_str(), 1, b->m_dual_thumb_path.size(), fp);
            fread((char*)b->m_pattern_path.c_str(), 1, b->m_pattern_path.size(), fp);
            fread((char*)b->m_pattern_thumb_path.c_str(), 1, b->m_pattern_thumb_path.size(), fp);

            if (b->load_tip(b->m_brush_path, b->m_brush_thumb_path))
            {
                if (!b->m_pattern_path.empty())
                    b->load_pattern(b->m_pattern_path, b->m_pattern_thumb_path);
                if (!b->m_dual_path.empty())
                    b->load_dual(b->m_dual_path, b->m_dual_thumb_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_preview->m_brush = b;
                brush->m_preview->draw_stroke();
                brush->m_caption_size->set_text_format("%d", (int)b->m_tip_size);
                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;
}

void NodePanelBrushPreset::add_brush(std::shared_ptr<Brush> brush)
{
    NodeBrushPresetItem* b = new NodeBrushPresetItem;
    m_container->add_child(b);
    b->init();
    b->create();
    b->loaded();
    b->thumb_path = brush->m_brush_thumb_path;
    b->high_path = brush->m_brush_path;
    b->m_brush = brush;
    //brush->m_brush->m_tip_size = .05f;
    b->m_preview->m_brush = brush;
    b->m_preview->draw_stroke();
    b->m_thumb->m_use_mipmaps = true;
    b->m_thumb->set_image(brush->m_brush_thumb_path);
    b->m_caption_size->set_text_format("%d", (int)brush->m_tip_size);
    b->on_click = std::bind(&NodePanelBrushPreset::handle_click, this, std::placeholders::_1);
}
