499 lines
14 KiB
C++
499 lines
14 KiB
C++
#include "pch.h"
|
|
#include "log.h"
|
|
#include "node_panel_brush.h"
|
|
#include "legacy_brush_preset_panel_ui.h"
|
|
#include "legacy_brush_panel_services.h"
|
|
#include "app_core/brush_ui.h"
|
|
#include "legacy_brush_ui_services.h"
|
|
#include "legacy_brush_preset_services.h"
|
|
#include "legacy_ui_overlay_services.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_file("data/dialogs/panel-brushes.xml", "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();
|
|
}
|
|
|
|
bool NodeButtonBrush::read(BinaryStreamReader& r)
|
|
{
|
|
Serializer::Descriptor d;
|
|
r >> d;
|
|
d.value<Serializer::CString>("brush_name", brush_name);
|
|
d.value<Serializer::CString>("high_path", high_path);
|
|
d.value<Serializer::CString>("thumb_path", thumb_path);
|
|
d.value<Serializer::Boolean>("m_user_brush", m_user_brush);
|
|
high_path = str_replace(high_path, "{data_path}", App::I->data_path);
|
|
thumb_path = str_replace(thumb_path, "{data_path}", App::I->data_path);
|
|
return true;
|
|
}
|
|
|
|
void NodeButtonBrush::write(BinaryStreamWriter& w) const
|
|
{
|
|
Serializer::Descriptor d;
|
|
d.class_id = "brush";
|
|
d.name = L"Brush class";
|
|
d.props["brush_name"] = std::make_shared<Serializer::CString>(brush_name);
|
|
d.props["high_path"] = std::make_shared<Serializer::CString>(
|
|
str_replace(high_path, App::I->data_path, "{data_path}"));
|
|
d.props["thumb_path"] = std::make_shared<Serializer::CString>(
|
|
str_replace(thumb_path, App::I->data_path, "{data_path}"));
|
|
d.props["m_user_brush"] = std::make_shared<Serializer::Boolean>(m_user_brush);
|
|
w << d;
|
|
}
|
|
|
|
Node* NodePanelBrush::clone_instantiate() const
|
|
{
|
|
return new NodePanelBrush();
|
|
}
|
|
|
|
void NodePanelBrush::execute_texture_list_plan(const pp::app::BrushTextureListPlan& plan)
|
|
{
|
|
const auto status = pp::panopainter::execute_legacy_brush_texture_list_plan(*this, plan);
|
|
if (!status.ok()) {
|
|
LOG("Brush texture list action failed: %s", status.message);
|
|
}
|
|
}
|
|
|
|
void NodePanelBrush::init()
|
|
{
|
|
init_template_file("data/dialogs/panel-brushes.xml", "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) {
|
|
const auto plan = pp::app::plan_brush_texture_list_add(m_dir_name, App::I->data_path, path);
|
|
if (plan) {
|
|
execute_texture_list_plan(plan.value());
|
|
}
|
|
});
|
|
};
|
|
|
|
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);
|
|
const auto plan = pp::app::plan_brush_texture_list_remove(
|
|
static_cast<int>(m_container->m_children.size()),
|
|
idx,
|
|
m_current->m_user_brush);
|
|
if (plan) {
|
|
execute_texture_list_plan(plan.value());
|
|
}
|
|
}
|
|
};
|
|
|
|
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);
|
|
const auto plan = pp::app::plan_brush_texture_list_move(
|
|
static_cast<int>(m_container->m_children.size()),
|
|
idx,
|
|
-1);
|
|
if (plan) {
|
|
execute_texture_list_plan(plan.value());
|
|
}
|
|
}
|
|
};
|
|
|
|
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);
|
|
const auto plan = pp::app::plan_brush_texture_list_move(
|
|
static_cast<int>(m_container->m_children.size()),
|
|
idx,
|
|
1);
|
|
if (plan) {
|
|
execute_texture_list_plan(plan.value());
|
|
}
|
|
}
|
|
};
|
|
|
|
m_container = find<NodeScroll>("brushes");
|
|
|
|
if (Asset::exist(App::I->data_path + "/settings/" + m_dir_name + ".bin") && !restore())
|
|
{
|
|
auto mb = App::I->message_box("Brushes", "Could not read brush textures file, it will be deleted.", true);
|
|
mb->btn_ok->on_click = [this, mb](Node*) {
|
|
Asset::delete_file(App::I->data_path + "/settings/" + m_dir_name + ".bin");
|
|
pp::panopainter::close_legacy_dialog_node(*mb);
|
|
};
|
|
mb->btn_cancel->on_click = [mb](Node*) {
|
|
pp::panopainter::close_legacy_dialog_node(*mb);
|
|
};
|
|
}
|
|
|
|
if (m_container->m_children.empty() && !m_dir_name.empty())
|
|
scan();
|
|
save();
|
|
}
|
|
|
|
kEventResult NodePanelBrush::handle_event(Event* e)
|
|
{
|
|
switch (e->m_type)
|
|
{
|
|
case kEventType::MouseLeave:
|
|
if (!m_interacted)
|
|
break;
|
|
// else fall through
|
|
case kEventType::MouseUpL:
|
|
if (!m_mouse_inside)
|
|
{
|
|
pp::panopainter::release_legacy_mouse_capture(*this);
|
|
if (m_parent)
|
|
{
|
|
pp::panopainter::detach_legacy_node_from_parent(*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));
|
|
m_interacted = true;
|
|
}
|
|
|
|
int NodePanelBrush::find_brush(const std::string & name) const
|
|
{
|
|
return pp::panopainter::LegacyBrushPanelServices(const_cast<NodePanelBrush&>(*this)).find_brush(name);
|
|
}
|
|
|
|
std::string NodePanelBrush::get_texture_path(int index) const
|
|
{
|
|
return pp::panopainter::LegacyBrushPanelServices(const_cast<NodePanelBrush&>(*this)).get_texture_path(index);
|
|
}
|
|
|
|
std::string NodePanelBrush::get_thumb_path(int index) const
|
|
{
|
|
return pp::panopainter::LegacyBrushPanelServices(const_cast<NodePanelBrush&>(*this)).get_thumb_path(index);
|
|
}
|
|
|
|
bool NodePanelBrush::save()
|
|
{
|
|
return pp::panopainter::LegacyBrushPanelServices(*this).save();
|
|
}
|
|
|
|
bool NodePanelBrush::restore()
|
|
{
|
|
return pp::panopainter::LegacyBrushPanelServices(*this).restore();
|
|
}
|
|
|
|
void NodePanelBrush::clear()
|
|
{
|
|
pp::panopainter::LegacyBrushPanelServices(*this).clear();
|
|
}
|
|
|
|
void NodePanelBrush::scan()
|
|
{
|
|
pp::panopainter::LegacyBrushPanelServices(*this).scan();
|
|
}
|
|
|
|
void NodePanelBrush::reload()
|
|
{
|
|
pp::panopainter::LegacyBrushPanelServices(*this).reload();
|
|
}
|
|
|
|
void NodePanelBrush::added(Node* parent)
|
|
{
|
|
m_interacted = false;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
std::vector<NodePanelBrushPreset*> NodePanelBrushPreset::s_panels;
|
|
|
|
Node* NodeBrushPresetItem::clone_instantiate() const
|
|
{
|
|
return new NodeBrushPresetItem();
|
|
}
|
|
|
|
void NodeBrushPresetItem::init()
|
|
{
|
|
init_template_file("data/dialogs/panel-brushes.xml", "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();
|
|
}
|
|
|
|
NodePanelBrushPreset::NodePanelBrushPreset()
|
|
{
|
|
s_panels.push_back(this);
|
|
}
|
|
|
|
NodePanelBrushPreset::~NodePanelBrushPreset()
|
|
{
|
|
s_panels.erase(std::remove(s_panels.begin(), s_panels.end(), this));
|
|
}
|
|
|
|
//---
|
|
|
|
Node* NodePanelBrushPreset::clone_instantiate() const
|
|
{
|
|
return new NodePanelBrushPreset();
|
|
}
|
|
|
|
namespace pp::panopainter {
|
|
|
|
class LegacyBrushPresetListServices final : public pp::app::BrushPresetListServices {
|
|
public:
|
|
explicit LegacyBrushPresetListServices(NodePanelBrushPreset& owner)
|
|
: owner_(owner)
|
|
{
|
|
}
|
|
|
|
pp::foundation::Status add_current_brush_preset(int target_index) override
|
|
{
|
|
if (target_index < 0) {
|
|
return pp::foundation::Status::out_of_range("brush preset add target is invalid");
|
|
}
|
|
if (!Canvas::I || !Canvas::I->m_current_brush) {
|
|
return pp::foundation::Status::invalid_argument("current brush must be available to add a preset");
|
|
}
|
|
|
|
for (auto p : NodePanelBrushPreset::s_panels) {
|
|
p->add_brush(std::make_shared<Brush>(*Canvas::I->m_current_brush));
|
|
}
|
|
return pp::foundation::Status::success();
|
|
}
|
|
|
|
void remove_brush_preset(
|
|
int current_index,
|
|
int target_index,
|
|
bool selects_target,
|
|
bool clears_selection) override
|
|
{
|
|
for (auto p : NodePanelBrushPreset::s_panels) {
|
|
if (current_index < 0 || current_index >= static_cast<int>(p->m_container->m_children.size())) {
|
|
continue;
|
|
}
|
|
|
|
const bool new_current = !p->m_current || p->m_container->get_child_index(p->m_current) == current_index;
|
|
pp::panopainter::destroy_legacy_node(*p->m_container->m_children[current_index]);
|
|
if (clears_selection) {
|
|
p->m_current = nullptr;
|
|
} else if (new_current && selects_target) {
|
|
p->m_current = static_cast<NodeBrushPresetItem*>(p->m_container->m_children[target_index].get());
|
|
p->m_current->m_selected = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
void move_brush_preset(int from_index, int to_index) override
|
|
{
|
|
for (auto p : NodePanelBrushPreset::s_panels) {
|
|
if (from_index >= 0 && from_index < static_cast<int>(p->m_container->m_children.size())) {
|
|
p->m_container->move_child(p->m_container->m_children[from_index].get(), to_index);
|
|
}
|
|
}
|
|
}
|
|
|
|
void select_brush_preset(int index, bool notify_brush_changed) override
|
|
{
|
|
for (auto p : NodePanelBrushPreset::s_panels) {
|
|
if (p->m_current) {
|
|
p->m_current->m_selected = false;
|
|
}
|
|
p->m_current = static_cast<NodeBrushPresetItem*>(p->m_container->get_child_at(index));
|
|
p->m_current->m_selected = true;
|
|
p->m_interacted = true;
|
|
}
|
|
if (notify_brush_changed && owner_.on_brush_changed) {
|
|
owner_.on_brush_changed(&owner_, owner_.m_current->m_brush);
|
|
}
|
|
}
|
|
|
|
void clear_brush_presets(bool clears_selection) override
|
|
{
|
|
for (auto p : NodePanelBrushPreset::s_panels) {
|
|
p->m_container->remove_all_children();
|
|
if (clears_selection) {
|
|
p->m_current = nullptr;
|
|
}
|
|
}
|
|
}
|
|
|
|
void update_preset_empty_notification() override
|
|
{
|
|
for (auto p : NodePanelBrushPreset::s_panels) {
|
|
p->m_notification->SetVisibility(p->m_container->m_children.size() == 0);
|
|
}
|
|
}
|
|
|
|
void save_preset_list() override
|
|
{
|
|
owner_.save();
|
|
}
|
|
|
|
private:
|
|
NodePanelBrushPreset& owner_;
|
|
};
|
|
|
|
} // namespace pp::panopainter
|
|
|
|
void NodePanelBrushPreset::execute_preset_list_plan(const pp::app::BrushPresetListPlan& plan)
|
|
{
|
|
pp::panopainter::LegacyBrushPresetListServices services(*this);
|
|
const auto status = pp::app::execute_brush_preset_list_plan(plan, services);
|
|
if (!status.ok()) {
|
|
LOG("Brush preset list action failed: %s", status.message);
|
|
}
|
|
}
|
|
|
|
void NodePanelBrushPreset::init()
|
|
{
|
|
pp::panopainter::LegacyBrushPresetPanelUi::init(*this);
|
|
}
|
|
|
|
kEventResult NodePanelBrushPreset::handle_event(Event* e)
|
|
{
|
|
switch (e->m_type)
|
|
{
|
|
case kEventType::MouseLeave:
|
|
if (!m_interacted)
|
|
break;
|
|
// else fall through
|
|
case kEventType::MouseUpL:
|
|
if (!m_mouse_inside)
|
|
{
|
|
pp::panopainter::release_legacy_mouse_capture(*this);
|
|
if (m_parent)
|
|
{
|
|
pp::panopainter::detach_legacy_node_from_parent(*this);
|
|
}
|
|
if (on_popup_close)
|
|
{
|
|
on_popup_close(this);
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
return kEventResult::Available;
|
|
break;
|
|
}
|
|
return kEventResult::Consumed;
|
|
}
|
|
|
|
void NodePanelBrushPreset::handle_click(Node* target)
|
|
{
|
|
pp::panopainter::LegacyBrushPresetPanelUi::handle_click(*this, target);
|
|
}
|
|
|
|
bool NodePanelBrushPreset::save()
|
|
{
|
|
return pp::panopainter::LegacyBrushPresetServices(*this).save();
|
|
}
|
|
|
|
bool NodePanelBrushPreset::restore()
|
|
{
|
|
const auto ok = pp::panopainter::LegacyBrushPresetServices(*this).restore();
|
|
if (ok) {
|
|
m_notification->SetVisibility(m_container->m_children.size() == 0);
|
|
}
|
|
return ok;
|
|
}
|
|
|
|
void NodePanelBrushPreset::add_brush(std::shared_ptr<Brush> brush)
|
|
{
|
|
pp::panopainter::LegacyBrushPresetPanelUi::add_brush(*this, std::move(brush));
|
|
}
|
|
|
|
bool NodePanelBrushPreset::export_ppbr(const std::string& path_in, const PPBRInfo& info_data)
|
|
{
|
|
return pp::panopainter::LegacyBrushPresetServices(*this).export_ppbr(path_in, info_data);
|
|
}
|
|
|
|
bool NodePanelBrushPreset::import_ppbr(const std::string& path)
|
|
{
|
|
return pp::panopainter::LegacyBrushPresetServices(*this).import_ppbr(path);
|
|
}
|
|
|
|
bool NodePanelBrushPreset::import_abr(const std::string& path)
|
|
{
|
|
return pp::panopainter::LegacyBrushPresetServices(*this).import_abr(path);
|
|
}
|
|
|
|
bool NodePanelBrushPreset::import_brush(const std::string& path)
|
|
{
|
|
return pp::panopainter::LegacyBrushPresetServices(*this).import_brush(path);
|
|
}
|
|
|
|
void NodePanelBrushPreset::clear_brushes()
|
|
{
|
|
const auto plan = pp::app::plan_brush_preset_list_clear(
|
|
static_cast<int>(m_container->m_children.size()));
|
|
if (plan) {
|
|
execute_preset_list_plan(plan.value());
|
|
}
|
|
}
|
|
|
|
void NodePanelBrushPreset::added(Node* parent)
|
|
{
|
|
(void)parent;
|
|
pp::panopainter::LegacyBrushPresetPanelUi::added(*this);
|
|
}
|