#include "pch.h" #include "app.h" #include "node_icon.h" #include "node_dialog_open.h" #include "node_text.h" #include "node_progress_bar.h" using namespace ui; static glm::vec4 color_button_normal{ .1, .1, .1, 1 }; static glm::vec4 color_button_hlight{ 1, .0, .0, 1 }; void App::init_toolbar_main() { if (auto* button = layout[main_id]->find("btn-export")) { button->on_click = [this, button](Node*) { if (canvas) { canvas->m_canvas->export_equirectangular(data_path); } }; } if (auto* button = layout[main_id]->find("btn-anim")) { button->on_click = [this, button](Node*) { if (canvas) { canvas->m_canvas->export_anim(data_path); } }; } if (auto* button = layout[main_id]->find("btn-open")) { button->on_click = [this, button](Node*) { dialog_open(); }; } if (auto* button = layout[main_id]->find("btn-save")) { button->on_click = [this, button](Node*) { dialog_save(); }; } if (auto* button = layout[main_id]->find("btn-undo")) { button->on_click = [this, button](Node*) { if (!ActionManager::empty()) ActionManager::undo(); }; } if (auto* button = layout[main_id]->find("btn-clean-memory")) { button->on_click = [this](Node*) { ActionManager::clear(); }; } if (auto* button = layout[main_id]->find("btn-clear")) { button->on_click = [this](Node*) { //exit(0); if (canvas) canvas->m_canvas->clear({ 0, 0, 0, 0 }); }; } if (auto* button = layout[main_id]->find("btn-popup")) { button->on_click = [this](Node*) { msgbox = new NodeMessageBox(); msgbox->m_manager = &layout; msgbox->init(); layout[main_id]->add_child(msgbox); layout[main_id]->update(); }; } if (auto* button = layout[main_id]->find("btn-settings")) { button->on_click = [this](Node*) { settings = new NodeSettings(); settings->m_manager = &layout; settings->init(); layout[main_id]->add_child(settings); layout[main_id]->update(); }; } } void App::init_sidebar() { sidebar = layout[main_id]->find("sidebar"); panels = layout[main_id]->find("panels"); canvas = layout[main_id]->find("paint-canvas"); canvas->data_path = data_path; //brushes = layout[main_id]->find("panel-brush"); //layers = layout[main_id]->find("panel-layer"); //color = layout[main_id]->find("panel-color"); //stroke = layout[main_id]->find("panel-stroke"); brushes = std::make_shared(); brushes->m_manager = &layout; brushes->init(); brushes->create(); brushes->loaded(); layers = std::make_shared(); layers->m_manager = &layout; layers->init(); layers->create(); layers->loaded(); color = std::make_shared(); color->m_manager = &layout; color->init(); color->create(); color->loaded(); stroke = std::make_shared(); stroke->m_manager = &layout; stroke->init(); stroke->create(); stroke->loaded(); presets = std::make_shared(); presets->m_manager = &layout; presets->init(); presets->create(); presets->loaded(); if (canvas) { stroke->m_canvas->m_brush.m_tip_color = color->m_color; stroke->m_canvas->draw_stroke(); canvas->m_brush = stroke->m_canvas->m_brush; } brushes->on_brush_changed = [this](Node* target, int index) { stroke->m_canvas->m_brush.m_tex_id = brushes->get_texture_id(index); stroke->m_canvas->m_brush.id = brushes->get_brush_id(index); stroke->m_canvas->draw_stroke(); canvas->m_brush = stroke->m_canvas->m_brush; if (on_brush_select) on_brush_select(index); }; presets->on_brush_changed = [this](Node* target, int index) { auto b = presets->get_brush(index); // don't change some params b.m_tip_size = stroke->m_canvas->m_brush.m_tip_size; b.m_tip_color = stroke->m_canvas->m_brush.m_tip_color; stroke->set_params(b); canvas->m_brush = stroke->m_canvas->m_brush; if (on_brush_select) on_brush_select(index); }; color->on_color_changed = [this](Node* target, glm::vec4 color) { stroke->m_canvas->m_brush.m_tip_color = color; // stroke->m_canvas->draw_stroke(); if (canvas) canvas->m_brush = stroke->m_canvas->m_brush; if (on_color_change) on_color_change(color); }; stroke->on_stroke_change = [this](Node*target) { if (canvas) canvas->m_brush = stroke->m_canvas->m_brush; if (on_stroke_change) on_stroke_change(); }; layers->on_layer_add = [this](Node*) { canvas->m_canvas->layer_add(layers->m_layers.back()->m_label_text.c_str()); }; layers->on_layer_change = [this](Node*, int old_idx, int new_idx) { canvas->m_canvas->m_current_layer_idx = canvas->m_canvas->m_order[new_idx]; }; layers->on_layer_order = [this](Node*, int old_idx, int new_idx) { canvas->m_canvas->layer_order(old_idx, new_idx); }; layers->on_layer_delete = [this](Node*, int idx) { canvas->m_canvas->layer_remove(canvas->m_canvas->m_order[idx]); }; layers->on_layer_opacity_changed = [this](Node*, int idx, float value) { canvas->m_canvas->m_layers[canvas->m_canvas->m_order[idx]].m_opacity = value; }; layers->on_layer_visibility_changed = [this](Node*, int idx, bool visible) { canvas->m_canvas->m_layers[canvas->m_canvas->m_order[idx]].m_alpha_locked = visible; }; layers->on_layer_highlight_changed = [this](Node*, int idx, bool highlight) { canvas->m_canvas->m_layers[canvas->m_canvas->m_order[idx]].m_hightlight = highlight; }; if (auto* button = layout[main_id]->find("btn-stroke")) { button->on_click = [this, button](Node*) { panels->get_child_index(stroke.get()) == -1 ? panels->add_child(stroke) : panels->remove_child(stroke.get()); panels->fix_scroll(); button->set_color(panels->get_child_index(stroke.get()) == -1 ? color_button_normal : color_button_hlight); }; } if (auto* button = layout[main_id]->find("btn-brush")) { button->on_click = [this, button](Node*) { panels->get_child_index(brushes.get()) == -1 ? panels->add_child(brushes) : panels->remove_child(brushes.get()); panels->fix_scroll(); button->set_color(panels->get_child_index(brushes.get()) == -1 ? color_button_normal : color_button_hlight); }; } if (auto* button = layout[main_id]->find("btn-brush-preset")) { button->on_click = [this, button](Node*) { panels->get_child_index(presets.get()) == -1 ? panels->add_child(presets) : panels->remove_child(presets.get()); panels->fix_scroll(); button->set_color(panels->get_child_index(presets.get()) == -1 ? color_button_normal : color_button_hlight); }; } if (auto* button = layout[main_id]->find("btn-color")) { button->on_click = [this, button](Node*) { panels->get_child_index(color.get()) == -1 ? panels->add_child(color) : panels->remove_child(color.get()); panels->fix_scroll(); button->set_color(panels->get_child_index(color.get()) == -1 ? color_button_normal : color_button_hlight); }; } if (auto* button = layout[main_id]->find("btn-layer")) { button->on_click = [this, button](Node*) { panels->get_child_index(layers.get()) == -1 ? panels->add_child(layers) : panels->remove_child(layers.get()); panels->fix_scroll(); button->set_color(panels->get_child_index(layers.get()) == -1 ? color_button_normal : color_button_hlight); }; } } void App::init_toolbar_draw() { static auto select_button = [] (Node* main, NodeButton* button) { main->find("btn-pen")->set_color(color_button_normal); main->find("btn-erase")->set_color(color_button_normal); main->find("btn-line")->set_color(color_button_normal); main->find("btn-cam")->set_color(color_button_normal); main->find("btn-grid")->set_color(color_button_normal); //main->find("btn-fill")->set_color(color_button_normal); main->find("btn-mask-free")->set_color(color_button_normal); main->find("btn-mask-line")->set_color(color_button_normal); button->set_color(color_button_hlight); }; if (auto* button = layout[main_id]->find("btn-pen")) { button->on_click = [this, button](Node*) { select_button(layout[main_id], button); Canvas::set_mode(Canvas::kCanvasMode::Draw); }; layout[main_id]->find("btn-pen")->set_color(color_button_hlight); Canvas::set_mode(Canvas::kCanvasMode::Draw); } if (auto* button = layout[main_id]->find("btn-pick")) { button->on_click = [this](Node*) { CanvasModePen* mode = (CanvasModePen*)canvas->m_canvas->modes[(int)Canvas::kCanvasMode::Draw][0]; if (mode && canvas->m_canvas->m_current_mode == Canvas::kCanvasMode::Draw) { mode->m_picking = !mode->m_picking; } }; } if (auto* button = layout[main_id]->find("btn-touchlock")) { button->on_click = [this](Node*) { canvas->m_canvas->m_touch_lock = !canvas->m_canvas->m_touch_lock; }; } if (auto* button = layout[main_id]->find("btn-erase")) { button->on_click = [this, button](Node*) { select_button(layout[main_id], button); Canvas::set_mode(Canvas::kCanvasMode::Erase); }; } if (auto* button = layout[main_id]->find("btn-line")) { button->on_click = [this, button](Node*) { select_button(layout[main_id], button); Canvas::set_mode(Canvas::kCanvasMode::Line); }; } if (auto* button = layout[main_id]->find("btn-cam")) { button->on_click = [this, button](Node*) { select_button(layout[main_id], button); Canvas::set_mode(Canvas::kCanvasMode::Camera); }; } if (auto* button = layout[main_id]->find("btn-grid")) { button->on_click = [this, button](Node*) { select_button(layout[main_id], button); Canvas::set_mode(Canvas::kCanvasMode::Grid); }; } if (auto* button = layout[main_id]->find("btn-fill")) { button->on_click = [this, button](Node*) { select_button(layout[main_id], button); Canvas::set_mode(Canvas::kCanvasMode::Fill); }; } if (auto* button = layout[main_id]->find("btn-mask-free")) { button->on_click = [this, button](Node*) { select_button(layout[main_id], button); Canvas::set_mode(Canvas::kCanvasMode::MaskFree); }; } if (auto* button = layout[main_id]->find("btn-mask-line")) { button->on_click = [this, button](Node*) { select_button(layout[main_id], button); Canvas::set_mode(Canvas::kCanvasMode::MaskLine); }; } if (auto* button = layout[main_id]->find("btn-bucket")) { button->on_click = [this](Node*) { canvas->m_canvas->clear(canvas->m_brush.m_tip_color); }; } } void App::init_menu_file() { if (auto* menu_file = layout[main_id]->find("menu-file")) { menu_file->on_click = [=](Node*) { glm::vec2 pos = menu_file->m_pos + glm::vec2(0, menu_file->m_size.y); popup = (NodePopupMenu*)layout[const_hash("file-menu")]->m_children[0]->clone(); popup->SetPositioning(YGPositionTypeAbsolute); popup->SetPosition(pos.x, pos.y); layout[main_id]->add_child(popup); layout[main_id]->update(); popup->mouse_capture(); popup->m_mouse_ignore = false; popup->m_flood_events = true; popup->m_capture_children = false; popup->find("file-newdoc")->on_click = [this](Node*) { dialog_newdoc(); popup->mouse_release(); popup->destroy(); }; popup->find("file-open")->on_click = [this](Node*) { dialog_open(); popup->mouse_release(); popup->destroy(); }; popup->find("file-browse")->on_click = [this](Node*) { dialog_browse(); popup->mouse_release(); popup->destroy(); }; popup->find("file-save")->on_click = [this](Node*) { if (doc_name.empty()) { dialog_save(); } else { canvas->m_canvas->project_save(data_path + "/" + doc_name + ".pano"); } popup->mouse_release(); popup->destroy(); }; popup->find("file-save-as")->on_click = [this](Node*) { dialog_save(); popup->mouse_release(); popup->destroy(); }; popup->find("file-save-ver")->on_click = [this](Node*) { if (doc_name.empty()) { dialog_save(); } else { int current = 0; std::string next = doc_name + ".01"; std::string base = doc_name; std::regex r(R"((.*)\.(\w{2})$)"); std::smatch m; if (std::regex_search(doc_name, m, r)) { std::string base = m[1].str(); current = atoi(m[2].str().c_str()); } for (int i = current + 1; i < 99; i++) { static char tmp_name[256]; sprintf(tmp_name, "%s.%02d", base.c_str(), i); next = tmp_name; if (Asset::exist(data_path + "/" + next + ".pano", false)) continue; break; } doc_name = next; if (auto docname = layout[main_id]->find("txt-docname")) docname->set_text(("Panodoc: " + doc_name).c_str()); canvas->m_canvas->project_save(data_path + "/" + next + ".pano"); } popup->mouse_release(); popup->destroy(); }; popup->find("file-export")->on_click = [this](Node*) { dialog_export(); popup->mouse_release(); popup->destroy(); }; popup->find("file-cloud-upload")->on_click = [this](Node*) { cloud_upload_all(); popup->mouse_release(); popup->destroy(); }; popup->find("file-cloud-browse")->on_click = [this](Node*) { cloud_browse(); popup->mouse_release(); popup->destroy(); }; }; } } void App::init_menu_edit() { if (auto* menu_file = layout[main_id]->find("menu-edit")) { menu_file->on_click = [=](Node*) { glm::vec2 pos = menu_file->m_pos + glm::vec2(0, menu_file->m_size.y); popup = (NodePopupMenu*)layout[const_hash("edit-menu")]->m_children[0]->clone(); popup->SetPositioning(YGPositionTypeAbsolute); popup->SetPosition(pos.x, pos.y); layout[main_id]->add_child(popup); layout[main_id]->update(); popup->mouse_capture(); popup->m_mouse_ignore = false; popup->m_flood_events = true; popup->m_capture_children = false; }; } } void App::brush_update() { brushes->select_brush(canvas->m_brush.id); stroke->set_params(canvas->m_brush); } void App::init_menu_layer() { if (auto* menu_file = layout[main_id]->find("menu-layers")) { menu_file->on_click = [=](Node*) { glm::vec2 pos = menu_file->m_pos + glm::vec2(0, menu_file->m_size.y); popup = (NodePopupMenu*)layout[const_hash("layers-menu")]->m_children[0]->clone(); popup->SetPositioning(YGPositionTypeAbsolute); popup->SetPosition(pos.x, pos.y); layout[main_id]->add_child(popup); layout[main_id]->update(); popup->mouse_capture(); popup->m_mouse_ignore = false; popup->m_flood_events = true; popup->m_capture_children = false; popup->find("clear-grids")->on_click = [this](Node*) { CanvasModeGrid* mode = (CanvasModeGrid*)ui::Canvas::modes[(int)ui::Canvas::kCanvasMode::Grid][0]; mode->clear(); popup->mouse_release(); popup->destroy(); }; popup->find("layer-clear")->on_click = [this](Node*) { canvas->m_canvas->clear(); }; if (layers->m_current_layer) popup->find("layer-clear")-> find("menu-label")-> set_text(("Clear Layer " + layers->m_current_layer->m_label_text).c_str()); popup->find("layer-rename")->on_click = [this](Node*) { dialog_layer_rename(); }; if (layers->m_current_layer) popup->find("layer-rename")-> find("menu-label")-> set_text(("Rename Layer " + layers->m_current_layer->m_label_text).c_str()); else popup->find("layer-rename")-> find("menu-label")-> set_text("Rename Layer (Select a layer)"); popup->find("layer-merge")->on_click = [this](Node*) { const auto& order = canvas->m_canvas->m_order; //layers->get_child_index(layers->) int current_idx_order = std::distance(order.begin(), std::find(order.begin(), order.end(), canvas->m_canvas->m_current_layer_idx)); if (current_idx_order > 0) { int dest_layer_idx = order[current_idx_order - 1]; canvas->m_canvas->layer_merge(canvas->m_canvas->m_current_layer_idx, dest_layer_idx); canvas->m_canvas->layer_remove(current_idx_order); layers->clear(); for (auto& i : canvas->m_canvas->m_order) layers->add_layer(canvas->m_canvas->m_layers[i].m_name.c_str()); layers->m_current_layer->m_selected = false; layers->m_current_layer = layers->m_layers[current_idx_order - 1]; layers->m_current_layer->m_selected = true; layers->m_current_layer->on_selected(layers->m_current_layer); } popup->mouse_release(); popup->destroy(); }; if (layers->m_current_layer) { const auto& order = canvas->m_canvas->m_order; int current_idx_order = std::distance(order.begin(), std::find(order.begin(), order.end(), canvas->m_canvas->m_current_layer_idx)); if (current_idx_order > 0) { int down_layer_idx = order[current_idx_order - 1]; popup->find("layer-merge")-> find("menu-label")-> set_text(("Merge with " + canvas->m_canvas->m_layers[down_layer_idx].m_name).c_str()); } else { popup->find("layer-merge")-> find("menu-label")-> set_text("Merge Layer (Select upper layers)"); } } else popup->find("layer-merge")-> find("menu-label")-> set_text("Merge Layer (Select a layer)"); }; } } void App::initLayout() { LOG("initializing layout statics"); NodeBorder::static_init(); NodeImage::static_init(); NodeIcon::static_init(); NodeStrokePreview::static_init(); layout.on_loaded = [&] { LOG("initializing layout updating after load"); layout[main_id]->update(width, height, zoom); LOG("initializing layout components"); init_sidebar(); canvas->m_canvas->layer_add("Default"); layers->add_layer("Default"); init_toolbar_draw(); init_toolbar_main(); init_menu_file(); init_menu_edit(); init_menu_layer(); Brush b; b.m_tex_id = brushes->get_texture_id(0); b.id = brushes->get_brush_id(0); b.m_tip_size = .1f; b.m_tip_flow = .5f; b.m_tip_spacing = .1f; b.m_tip_opacity = 1.f; stroke->m_canvas->m_brush = b; canvas->m_brush = b; brush_update(); TextureManager::load("data/paper.jpg"); // hacky thing to make the toolbar buttons not steal events when moving cursor fast if (auto* toolbar = layout[main_id]->find("toolbar")) toolbar->m_flood_events = true; /* if (auto* slider = layout[main_id]->find("frames-slider")) { slider->on_value_changed = [this](Node*, float value) { auto& c = *ui::Canvas::I; for (int i = 0; i < c.m_layers.size(); i++) { auto l = layers->get_layer_at(i); layers->handle_layer_opacity(l, .0f); } int current_layer = (int)floor(value * c.m_layers.size()); auto l = layers->get_layer_at(current_layer); layers->handle_layer_selected(l); layers->handle_layer_opacity(l, 1.f); if (current_layer > 0) { auto l = layers->get_layer_at(current_layer - 1); layers->handle_layer_opacity(l, .25f); } }; } */ }; LOG("initializing layout xml"); if (layout.m_loaded) { LOG("restore layout"); layout.restore_context(); if (panels->get_child_index(brushes.get()) == -1) brushes->restore_context(); if (panels->get_child_index(layers.get()) == -1) layers->restore_context(); if (panels->get_child_index(color.get()) == -1) color->restore_context(); if (panels->get_child_index(stroke.get()) == -1) stroke->restore_context(); } else layout.load("data/layout.xml"); LOG("initializing layout completed"); }