From 5feb3acb1da4802358daba5166bdedfb622c9732 Mon Sep 17 00:00:00 2001 From: omigamedev Date: Thu, 4 Jan 2018 00:02:28 +0000 Subject: [PATCH] add download progress, improbable cloud browser, lock touch when pencil is down on iOS --- PanoPainter/GameViewController.m | 13 ++++- engine/app.cpp | 18 ++++++- engine/app.h | 3 +- engine/app_cloud.cpp | 15 ++++-- engine/canvas.cpp | 7 ++- engine/node.cpp | 9 ++++ engine/node.h | 1 + engine/node_dialog_cloud.cpp | 84 ++++++++++++++++++++++---------- engine/node_dialog_cloud.h | 2 + engine/node_slider.cpp | 5 +- 10 files changed, 120 insertions(+), 37 deletions(-) diff --git a/PanoPainter/GameViewController.m b/PanoPainter/GameViewController.m index 28a6bd2..db717cd 100644 --- a/PanoPainter/GameViewController.m +++ b/PanoPainter/GameViewController.m @@ -30,6 +30,7 @@ @end //std::map< +bool pen_down = false; int t_count = 0; glm::vec2 t_pos; int lock_count = 0; @@ -194,6 +195,8 @@ NSThread* lock_thread; float scale = self.view.contentScaleFactor; kEventSource source = touch.type == UITouchType::UITouchTypeStylus ? kEventSource::Stylus : kEventSource::Touch; + if (source == kEventSource::Stylus) + pen_down = true; [self async_lock]; App::I.mouse_down(0, touchLocation.x * scale, touchLocation.y * scale, touch.force, source); [self async_unlock]; @@ -220,7 +223,14 @@ NSThread* lock_thread; } [self async_lock]; - if (n == 2) + if (pen_down) + { + if (t0.type == UITouchType::UITouchTypeStylus) + App::I.mouse_move(p0.x, p0.y, t0.force, kEventSource::Stylus); + if (t1.type == UITouchType::UITouchTypeStylus) + App::I.mouse_move(p1.x, p1.y, t1.force, kEventSource::Stylus); + } + else if (n == 2) { if (t_count == 1) { @@ -258,6 +268,7 @@ NSThread* lock_thread; float scale = self.view.contentScaleFactor; kEventSource source = touch.type == UITouchType::UITouchTypeStylus ? kEventSource::Stylus : kEventSource::Touch; + pen_down = false; [self async_lock]; if (t_count == 2) diff --git a/engine/app.cpp b/engine/app.cpp index f708483..ea1bd7b 100644 --- a/engine/app.cpp +++ b/engine/app.cpp @@ -63,7 +63,15 @@ void App::initLog() LogRemote::I.file_init(); } -void App::download(std::string filename) +int progress_callback(void *clientp, curl_off_t dltotal, + curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow) +{ + std::function progress = *(std::function*)clientp; + progress((float)dlnow / (float)dltotal); + return 0; +} + +void App::download(std::string filename, std::function progress) { CURL *curl = curl_easy_init(); if (curl) @@ -74,6 +82,9 @@ void App::download(std::string filename) curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_data_write); + curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, progress_callback); + curl_easy_setopt(curl, CURLOPT_XFERINFODATA, &progress); + curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0); auto err = curl_easy_perform(curl); curl_easy_cleanup(curl); fclose(fp); @@ -213,6 +224,11 @@ void App::async_update() #endif } +void App::async_redraw() +{ + redraw = true; +} + void App::async_end() { #if __OSX__ diff --git a/engine/app.h b/engine/app.h index 8cfe018..eebe0d2 100644 --- a/engine/app.h +++ b/engine/app.h @@ -97,6 +97,7 @@ public: void update(float dt); void async_start(); void async_update(); + void async_redraw(); void async_end(); void resize(float w, float h); bool mouse_down(int button, float x, float y, float pressure, kEventSource source); @@ -129,7 +130,7 @@ public: void cloud_upload_all(); void cloud_browse(); void upload(std::string filename, std::string name = ""); - void download(std::string filename); + void download(std::string filename, std::function progress); void brush_update(); void title_update(std::string name, int resolution); diff --git a/engine/app_cloud.cpp b/engine/app_cloud.cpp index c944cb5..b0933a2 100644 --- a/engine/app_cloud.cpp +++ b/engine/app_cloud.cpp @@ -117,11 +117,18 @@ void App::cloud_browse() async_start(); auto* m = layout[main_id]->add_child(); m->m_title->set_text("Downloading"); - m->m_message->set_text("Download in progress, please wait..."); - async_update(); + m->m_message->set_text("Download in progress"); + async_redraw(); async_end(); - download(dialog->selected_file); + download(dialog->selected_file, [this,m](float p){ + static char progress[256]; + sprintf(progress, "Download in progress %.2f%%", p * 100.f); + async_start(); + m->m_message->set_text(progress); + async_redraw(); + async_end(); + }); async_start(); canvas->reset_camera(); @@ -137,7 +144,7 @@ void App::cloud_browse() layers->add_layer(canvas->m_canvas->m_layers[i].m_name.c_str()); ActionManager::clear(); m->destroy(); - async_update(); + async_redraw(); async_end(); }).detach(); }; diff --git a/engine/canvas.cpp b/engine/canvas.cpp index d9ea426..86c05f0 100644 --- a/engine/canvas.cpp +++ b/engine/canvas.cpp @@ -1399,8 +1399,11 @@ void ui::Canvas::project_open_thread(std::string file_path) fread(compressed.data(), 1, data_size, fp); int imgw, imgh, imgc; uint8_t* rgba = stbi_load_from_memory(compressed.data(), data_size, &imgw, &imgh, &imgc, 4); - std::copy(rgba, rgba + (imgw*imgh * 4), snap.image[plane_index].get()); - delete rgba; + if (rgba) + { + std::copy(rgba, rgba + (imgw*imgh * 4), snap.image[plane_index].get()); + delete rgba; + } } progress++; diff --git a/engine/node.cpp b/engine/node.cpp index 5636986..391cedc 100644 --- a/engine/node.cpp +++ b/engine/node.cpp @@ -191,6 +191,11 @@ void Node::added(Node* parent) } +void Node::removed(Node* parent) +{ + +} + const Node* Node::init_template(const char* id) { const auto& m_template = static_cast((*m_manager)[const_hash(id)]->m_children[0].get()); @@ -247,6 +252,7 @@ void Node::remove_child(Node* n) auto i = std::find_if(m_children.begin(), m_children.end(), [=](auto& ptr) { return ptr.get() == n; }); if (i != m_children.end()) { + n->removed(this); YGNodeRemoveChild(y_node, n->y_node); m_children.erase(i); } @@ -255,7 +261,10 @@ void Node::remove_child(Node* n) void Node::remove_all_children() { for (auto& n : m_children) + { + n->removed(this); YGNodeRemoveChild(y_node, n->y_node); + } m_children.clear(); } diff --git a/engine/node.h b/engine/node.h index b9b0819..a38234e 100644 --- a/engine/node.h +++ b/engine/node.h @@ -194,6 +194,7 @@ public: virtual void init(); virtual void loaded(); virtual void added(Node* parent); + virtual void removed(Node* parent); const Node* init_template(const char* id); void async_start(); void async_update(); diff --git a/engine/node_dialog_cloud.cpp b/engine/node_dialog_cloud.cpp index 3587526..0ed6137 100644 --- a/engine/node_dialog_cloud.cpp +++ b/engine/node_dialog_cloud.cpp @@ -43,40 +43,90 @@ void NodeDialogCloud::loaded() { } +void NodeDialogCloud::removed(Node* parent) +{ + closed = true; +} + void NodeDialogCloud::load_thumbs_thread() { CURL *curl = curl_easy_init(); std::string res; if (curl) { + async_start(); + auto* align = container->add_child(); + align->SetWidthP(100.f); + align->SetHeightP(100.f); + align->SetAlign(YGAlignCenter); + align->SetJustify(YGJustifyCenter); + auto* text = align->add_child(); + text->set_font(kFont::Arial_30); + text->set_text("Connecting to the server..."); + async_update(); + async_end(); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &res); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_data_handler); curl_easy_setopt(curl, CURLOPT_URL, "http://omigamedev.com/panopainter/cloud/cloud-list.php"); auto err = curl_easy_perform(curl); + if (err != CURLE_OK) { async_start(); - auto* align = container->add_child(); - align->SetWidthP(100.f); - align->SetHeightP(100.f); - align->SetAlign(YGAlignCenter); - align->SetJustify(YGJustifyCenter); - auto* t = align->add_child(); - t->set_font(kFont::Arial_30); - t->set_text("Could not connect to the server"); + text->set_text("Could not connect to the server"); async_update(); async_end(); return; } + async_start(); + align->destroy(); + async_end(); + LOG("CLOUD LIST: %s", res.c_str()); auto names = split(res, ','); + std::vector nodes; + + // create slots with name + App::I.async_start(); for (const auto& n : names) { + auto node = new NodeDialogCloudItem; + node->m_manager = m_manager; + node->init(); + node->m_text->set_text(n.c_str()); + node->m_path = data_path + "/" + n; + node->m_file_name = n; + container->add_child(node); + node->on_selected = [&](NodeDialogCloudItem* target) { + if (target == current) + return; + selected_path = target->m_path; + selected_file = target->m_file_name; + selected_name = selected_file.substr(0, selected_file.length() - 5); + if (current) + current->m_selected = false; + current = target; + }; + nodes.push_back(node); + } + App::I.async_update(); + App::I.async_end(); + + // load the icons + for (int i = 0; i < names.size(); i++) + { + const auto& n = names[i]; + auto* node = nodes[i]; + if (closed) + break; + res.clear(); std::string url = "http://omigamedev.com/panopainter/cloud/cloud-info.php?file=" + n; curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); + LOG("%s", url.c_str()); auto err = curl_easy_perform(curl); if (err != CURLE_OK) break; // TODO: handle this error with a message or something @@ -93,29 +143,11 @@ void NodeDialogCloud::load_thumbs_thread() thumb.copy_from((uint8_t*)rgb.data()); App::I.async_start(); - auto node = new NodeDialogCloudItem; - node->m_manager = m_manager; - node->init(); - node->m_text->set_text(n.c_str()); - node->m_path = data_path + "/" + n; - node->m_file_name = n; auto image_tex = node->find("thumb-tex"); image_tex->tex.destroy(); image_tex->tex.create(thumb); - container->add_child(node); App::I.async_update(); App::I.async_end(); - - node->on_selected = [&](NodeDialogCloudItem* target) { - if (target == current) - return; - selected_path = target->m_path; - selected_file = target->m_file_name; - selected_name = selected_file.substr(0, selected_file.length() - 5); - if (current) - current->m_selected = false; - current = target; - }; } curl_easy_cleanup(curl); } diff --git a/engine/node_dialog_cloud.h b/engine/node_dialog_cloud.h index 46d9357..61b93e3 100644 --- a/engine/node_dialog_cloud.h +++ b/engine/node_dialog_cloud.h @@ -29,6 +29,7 @@ public: class NodeDialogCloud : public NodeBorder { public: + bool closed = false; NodeButton* btn_cancel; NodeButton* btn_ok; NodeButton* btn_delete; @@ -43,5 +44,6 @@ public: virtual void init() override; void init_controls(); virtual void loaded() override; + virtual void removed(Node* parent) override; void load_thumbs_thread(); }; diff --git a/engine/node_slider.cpp b/engine/node_slider.cpp index 58938b4..bd9a7a8 100644 --- a/engine/node_slider.cpp +++ b/engine/node_slider.cpp @@ -93,7 +93,7 @@ kEventResult NodeSliderH::handle_event(Event* e) auto pos = glm::clamp(((MouseEvent*)e)->m_pos - m_pos, { 0, 0 }, sz) * m_mask; m_value = pos / glm::max({ 1, 1 }, sz); if (on_value_changed) - on_value_changed(this, glm::length(m_value)); + on_value_changed(this, glm::length(m_value * m_mask)); } break; case kEventType::MouseCancel: @@ -103,7 +103,7 @@ kEventResult NodeSliderH::handle_event(Event* e) m_value = m_old_value; set_value(glm::length(m_value)); if (on_value_changed) - on_value_changed(this, glm::length(m_value)); + on_value_changed(this, glm::length(m_value * m_mask)); } dragging = false; break; @@ -143,6 +143,7 @@ void NodeSliderHue::init_controls() glm::vec4 NodeSliderHue::get_hue() { + m_color = glm::vec4(convert_hsv2rgb({ glm::length(m_value * m_mask), 1, 1 }), 1); return m_color; }