add download progress, improbable cloud browser, lock touch when pencil is down on iOS
This commit is contained in:
@@ -30,6 +30,7 @@
|
|||||||
@end
|
@end
|
||||||
|
|
||||||
//std::map<
|
//std::map<
|
||||||
|
bool pen_down = false;
|
||||||
int t_count = 0;
|
int t_count = 0;
|
||||||
glm::vec2 t_pos;
|
glm::vec2 t_pos;
|
||||||
int lock_count = 0;
|
int lock_count = 0;
|
||||||
@@ -194,6 +195,8 @@ NSThread* lock_thread;
|
|||||||
float scale = self.view.contentScaleFactor;
|
float scale = self.view.contentScaleFactor;
|
||||||
|
|
||||||
kEventSource source = touch.type == UITouchType::UITouchTypeStylus ? kEventSource::Stylus : kEventSource::Touch;
|
kEventSource source = touch.type == UITouchType::UITouchTypeStylus ? kEventSource::Stylus : kEventSource::Touch;
|
||||||
|
if (source == kEventSource::Stylus)
|
||||||
|
pen_down = true;
|
||||||
[self async_lock];
|
[self async_lock];
|
||||||
App::I.mouse_down(0, touchLocation.x * scale, touchLocation.y * scale, touch.force, source);
|
App::I.mouse_down(0, touchLocation.x * scale, touchLocation.y * scale, touch.force, source);
|
||||||
[self async_unlock];
|
[self async_unlock];
|
||||||
@@ -220,7 +223,14 @@ NSThread* lock_thread;
|
|||||||
}
|
}
|
||||||
|
|
||||||
[self async_lock];
|
[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)
|
if (t_count == 1)
|
||||||
{
|
{
|
||||||
@@ -258,6 +268,7 @@ NSThread* lock_thread;
|
|||||||
float scale = self.view.contentScaleFactor;
|
float scale = self.view.contentScaleFactor;
|
||||||
|
|
||||||
kEventSource source = touch.type == UITouchType::UITouchTypeStylus ? kEventSource::Stylus : kEventSource::Touch;
|
kEventSource source = touch.type == UITouchType::UITouchTypeStylus ? kEventSource::Stylus : kEventSource::Touch;
|
||||||
|
pen_down = false;
|
||||||
|
|
||||||
[self async_lock];
|
[self async_lock];
|
||||||
if (t_count == 2)
|
if (t_count == 2)
|
||||||
|
|||||||
@@ -63,7 +63,15 @@ void App::initLog()
|
|||||||
LogRemote::I.file_init();
|
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<void(float)> progress = *(std::function<void(float)>*)clientp;
|
||||||
|
progress((float)dlnow / (float)dltotal);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void App::download(std::string filename, std::function<void(float)> progress)
|
||||||
{
|
{
|
||||||
CURL *curl = curl_easy_init();
|
CURL *curl = curl_easy_init();
|
||||||
if (curl)
|
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_URL, url.c_str());
|
||||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
|
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
|
||||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_data_write);
|
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);
|
auto err = curl_easy_perform(curl);
|
||||||
curl_easy_cleanup(curl);
|
curl_easy_cleanup(curl);
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
@@ -213,6 +224,11 @@ void App::async_update()
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void App::async_redraw()
|
||||||
|
{
|
||||||
|
redraw = true;
|
||||||
|
}
|
||||||
|
|
||||||
void App::async_end()
|
void App::async_end()
|
||||||
{
|
{
|
||||||
#if __OSX__
|
#if __OSX__
|
||||||
|
|||||||
@@ -97,6 +97,7 @@ public:
|
|||||||
void update(float dt);
|
void update(float dt);
|
||||||
void async_start();
|
void async_start();
|
||||||
void async_update();
|
void async_update();
|
||||||
|
void async_redraw();
|
||||||
void async_end();
|
void async_end();
|
||||||
void resize(float w, float h);
|
void resize(float w, float h);
|
||||||
bool mouse_down(int button, float x, float y, float pressure, kEventSource source);
|
bool mouse_down(int button, float x, float y, float pressure, kEventSource source);
|
||||||
@@ -129,7 +130,7 @@ public:
|
|||||||
void cloud_upload_all();
|
void cloud_upload_all();
|
||||||
void cloud_browse();
|
void cloud_browse();
|
||||||
void upload(std::string filename, std::string name = "");
|
void upload(std::string filename, std::string name = "");
|
||||||
void download(std::string filename);
|
void download(std::string filename, std::function<void(float)> progress);
|
||||||
|
|
||||||
void brush_update();
|
void brush_update();
|
||||||
void title_update(std::string name, int resolution);
|
void title_update(std::string name, int resolution);
|
||||||
|
|||||||
@@ -117,11 +117,18 @@ void App::cloud_browse()
|
|||||||
async_start();
|
async_start();
|
||||||
auto* m = layout[main_id]->add_child<NodeMessageBox>();
|
auto* m = layout[main_id]->add_child<NodeMessageBox>();
|
||||||
m->m_title->set_text("Downloading");
|
m->m_title->set_text("Downloading");
|
||||||
m->m_message->set_text("Download in progress, please wait...");
|
m->m_message->set_text("Download in progress");
|
||||||
async_update();
|
async_redraw();
|
||||||
async_end();
|
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();
|
async_start();
|
||||||
canvas->reset_camera();
|
canvas->reset_camera();
|
||||||
@@ -137,7 +144,7 @@ void App::cloud_browse()
|
|||||||
layers->add_layer(canvas->m_canvas->m_layers[i].m_name.c_str());
|
layers->add_layer(canvas->m_canvas->m_layers[i].m_name.c_str());
|
||||||
ActionManager::clear();
|
ActionManager::clear();
|
||||||
m->destroy();
|
m->destroy();
|
||||||
async_update();
|
async_redraw();
|
||||||
async_end();
|
async_end();
|
||||||
}).detach();
|
}).detach();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1399,9 +1399,12 @@ void ui::Canvas::project_open_thread(std::string file_path)
|
|||||||
fread(compressed.data(), 1, data_size, fp);
|
fread(compressed.data(), 1, data_size, fp);
|
||||||
int imgw, imgh, imgc;
|
int imgw, imgh, imgc;
|
||||||
uint8_t* rgba = stbi_load_from_memory(compressed.data(), data_size, &imgw, &imgh, &imgc, 4);
|
uint8_t* rgba = stbi_load_from_memory(compressed.data(), data_size, &imgw, &imgh, &imgc, 4);
|
||||||
|
if (rgba)
|
||||||
|
{
|
||||||
std::copy(rgba, rgba + (imgw*imgh * 4), snap.image[plane_index].get());
|
std::copy(rgba, rgba + (imgw*imgh * 4), snap.image[plane_index].get());
|
||||||
delete rgba;
|
delete rgba;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
progress++;
|
progress++;
|
||||||
float p = (float)progress / total * 100.f;
|
float p = (float)progress / total * 100.f;
|
||||||
|
|||||||
@@ -191,6 +191,11 @@ void Node::added(Node* parent)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Node::removed(Node* parent)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
const Node* Node::init_template(const char* id)
|
const Node* Node::init_template(const char* id)
|
||||||
{
|
{
|
||||||
const auto& m_template = static_cast<Node*>((*m_manager)[const_hash(id)]->m_children[0].get());
|
const auto& m_template = static_cast<Node*>((*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; });
|
auto i = std::find_if(m_children.begin(), m_children.end(), [=](auto& ptr) { return ptr.get() == n; });
|
||||||
if (i != m_children.end())
|
if (i != m_children.end())
|
||||||
{
|
{
|
||||||
|
n->removed(this);
|
||||||
YGNodeRemoveChild(y_node, n->y_node);
|
YGNodeRemoveChild(y_node, n->y_node);
|
||||||
m_children.erase(i);
|
m_children.erase(i);
|
||||||
}
|
}
|
||||||
@@ -255,7 +261,10 @@ void Node::remove_child(Node* n)
|
|||||||
void Node::remove_all_children()
|
void Node::remove_all_children()
|
||||||
{
|
{
|
||||||
for (auto& n : m_children)
|
for (auto& n : m_children)
|
||||||
|
{
|
||||||
|
n->removed(this);
|
||||||
YGNodeRemoveChild(y_node, n->y_node);
|
YGNodeRemoveChild(y_node, n->y_node);
|
||||||
|
}
|
||||||
m_children.clear();
|
m_children.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -194,6 +194,7 @@ public:
|
|||||||
virtual void init();
|
virtual void init();
|
||||||
virtual void loaded();
|
virtual void loaded();
|
||||||
virtual void added(Node* parent);
|
virtual void added(Node* parent);
|
||||||
|
virtual void removed(Node* parent);
|
||||||
const Node* init_template(const char* id);
|
const Node* init_template(const char* id);
|
||||||
void async_start();
|
void async_start();
|
||||||
void async_update();
|
void async_update();
|
||||||
|
|||||||
@@ -43,17 +43,16 @@ void NodeDialogCloud::loaded()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NodeDialogCloud::removed(Node* parent)
|
||||||
|
{
|
||||||
|
closed = true;
|
||||||
|
}
|
||||||
|
|
||||||
void NodeDialogCloud::load_thumbs_thread()
|
void NodeDialogCloud::load_thumbs_thread()
|
||||||
{
|
{
|
||||||
CURL *curl = curl_easy_init();
|
CURL *curl = curl_easy_init();
|
||||||
std::string res;
|
std::string res;
|
||||||
if (curl)
|
if (curl)
|
||||||
{
|
|
||||||
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();
|
async_start();
|
||||||
auto* align = container->add_child<Node>();
|
auto* align = container->add_child<Node>();
|
||||||
@@ -61,22 +60,73 @@ void NodeDialogCloud::load_thumbs_thread()
|
|||||||
align->SetHeightP(100.f);
|
align->SetHeightP(100.f);
|
||||||
align->SetAlign(YGAlignCenter);
|
align->SetAlign(YGAlignCenter);
|
||||||
align->SetJustify(YGJustifyCenter);
|
align->SetJustify(YGJustifyCenter);
|
||||||
auto* t = align->add_child<NodeText>();
|
auto* text = align->add_child<NodeText>();
|
||||||
t->set_font(kFont::Arial_30);
|
text->set_font(kFont::Arial_30);
|
||||||
t->set_text("Could not connect to the server");
|
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();
|
||||||
|
text->set_text("Could not connect to the server");
|
||||||
async_update();
|
async_update();
|
||||||
async_end();
|
async_end();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async_start();
|
||||||
|
align->destroy();
|
||||||
|
async_end();
|
||||||
|
|
||||||
LOG("CLOUD LIST: %s", res.c_str());
|
LOG("CLOUD LIST: %s", res.c_str());
|
||||||
|
|
||||||
auto names = split(res, ',');
|
auto names = split(res, ',');
|
||||||
|
std::vector<NodeDialogCloudItem*> nodes;
|
||||||
|
|
||||||
|
// create slots with name
|
||||||
|
App::I.async_start();
|
||||||
for (const auto& n : names)
|
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();
|
res.clear();
|
||||||
std::string url = "http://omigamedev.com/panopainter/cloud/cloud-info.php?file=" + n;
|
std::string url = "http://omigamedev.com/panopainter/cloud/cloud-info.php?file=" + n;
|
||||||
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
|
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
|
||||||
|
LOG("%s", url.c_str());
|
||||||
auto err = curl_easy_perform(curl);
|
auto err = curl_easy_perform(curl);
|
||||||
if (err != CURLE_OK)
|
if (err != CURLE_OK)
|
||||||
break; // TODO: handle this error with a message or something
|
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());
|
thumb.copy_from((uint8_t*)rgb.data());
|
||||||
|
|
||||||
App::I.async_start();
|
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<NodeImageTexture>("thumb-tex");
|
auto image_tex = node->find<NodeImageTexture>("thumb-tex");
|
||||||
image_tex->tex.destroy();
|
image_tex->tex.destroy();
|
||||||
image_tex->tex.create(thumb);
|
image_tex->tex.create(thumb);
|
||||||
container->add_child(node);
|
|
||||||
App::I.async_update();
|
App::I.async_update();
|
||||||
App::I.async_end();
|
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);
|
curl_easy_cleanup(curl);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ public:
|
|||||||
class NodeDialogCloud : public NodeBorder
|
class NodeDialogCloud : public NodeBorder
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
bool closed = false;
|
||||||
NodeButton* btn_cancel;
|
NodeButton* btn_cancel;
|
||||||
NodeButton* btn_ok;
|
NodeButton* btn_ok;
|
||||||
NodeButton* btn_delete;
|
NodeButton* btn_delete;
|
||||||
@@ -43,5 +44,6 @@ public:
|
|||||||
virtual void init() override;
|
virtual void init() override;
|
||||||
void init_controls();
|
void init_controls();
|
||||||
virtual void loaded() override;
|
virtual void loaded() override;
|
||||||
|
virtual void removed(Node* parent) override;
|
||||||
void load_thumbs_thread();
|
void load_thumbs_thread();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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;
|
auto pos = glm::clamp(((MouseEvent*)e)->m_pos - m_pos, { 0, 0 }, sz) * m_mask;
|
||||||
m_value = pos / glm::max({ 1, 1 }, sz);
|
m_value = pos / glm::max({ 1, 1 }, sz);
|
||||||
if (on_value_changed)
|
if (on_value_changed)
|
||||||
on_value_changed(this, glm::length(m_value));
|
on_value_changed(this, glm::length(m_value * m_mask));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case kEventType::MouseCancel:
|
case kEventType::MouseCancel:
|
||||||
@@ -103,7 +103,7 @@ kEventResult NodeSliderH::handle_event(Event* e)
|
|||||||
m_value = m_old_value;
|
m_value = m_old_value;
|
||||||
set_value(glm::length(m_value));
|
set_value(glm::length(m_value));
|
||||||
if (on_value_changed)
|
if (on_value_changed)
|
||||||
on_value_changed(this, glm::length(m_value));
|
on_value_changed(this, glm::length(m_value * m_mask));
|
||||||
}
|
}
|
||||||
dragging = false;
|
dragging = false;
|
||||||
break;
|
break;
|
||||||
@@ -143,6 +143,7 @@ void NodeSliderHue::init_controls()
|
|||||||
|
|
||||||
glm::vec4 NodeSliderHue::get_hue()
|
glm::vec4 NodeSliderHue::get_hue()
|
||||||
{
|
{
|
||||||
|
m_color = glm::vec4(convert_hsv2rgb({ glm::length(m_value * m_mask), 1, 1 }), 1);
|
||||||
return m_color;
|
return m_color;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user