diff --git a/data/layout.xml b/data/layout.xml index ce8949f..3ea0189 100644 --- a/data/layout.xml +++ b/data/layout.xml @@ -248,10 +248,10 @@ - - - - + + + + @@ -342,23 +342,23 @@ --> - + - + - + - + - + @@ -368,15 +368,15 @@ - + - + - + @@ -386,15 +386,15 @@ - + - + - + @@ -410,7 +410,8 @@ - - + + --> + diff --git a/engine.xcodeproj/project.pbxproj b/engine.xcodeproj/project.pbxproj index e63d960..fad4c1f 100644 --- a/engine.xcodeproj/project.pbxproj +++ b/engine.xcodeproj/project.pbxproj @@ -161,6 +161,9 @@ ADC6F4621F3AFF2C004177FA /* node_dialog_layer_rename.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ADC6F4611F3AFA2B004177FA /* node_dialog_layer_rename.cpp */; }; ADC6F4631F3AFF2D004177FA /* node_dialog_layer_rename.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ADC6F4611F3AFA2B004177FA /* node_dialog_layer_rename.cpp */; }; ADC6F4641F3AFF2E004177FA /* node_dialog_layer_rename.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ADC6F4611F3AFA2B004177FA /* node_dialog_layer_rename.cpp */; }; + ADC6F4661F3E66FB004177FA /* app_dialogs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ADC6F4651F3E66FA004177FA /* app_dialogs.cpp */; }; + ADC6F4671F3E66FB004177FA /* app_dialogs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ADC6F4651F3E66FA004177FA /* app_dialogs.cpp */; }; + ADC6F4681F3E66FB004177FA /* app_dialogs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ADC6F4651F3E66FA004177FA /* app_dialogs.cpp */; }; ADD7D26F1EBF9AE300D5A897 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = ADD7D26E1EBF9AE300D5A897 /* main.m */; }; ADD7D2721EBF9AE300D5A897 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = ADD7D2711EBF9AE300D5A897 /* AppDelegate.m */; }; ADD7D2791EBF9AE300D5A897 /* GameViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = ADD7D2781EBF9AE300D5A897 /* GameViewController.m */; }; @@ -324,6 +327,7 @@ ADB61C811E3D38450093280F /* util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = util.h; sourceTree = ""; }; ADC6F4601F3AFA2A004177FA /* node_dialog_layer_rename.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = node_dialog_layer_rename.h; sourceTree = ""; }; ADC6F4611F3AFA2B004177FA /* node_dialog_layer_rename.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = node_dialog_layer_rename.cpp; sourceTree = ""; }; + ADC6F4651F3E66FA004177FA /* app_dialogs.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = app_dialogs.cpp; sourceTree = ""; }; ADD7D26B1EBF9AE300D5A897 /* PanoPainter.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PanoPainter.app; sourceTree = BUILT_PRODUCTS_DIR; }; ADD7D26E1EBF9AE300D5A897 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; ADD7D2701EBF9AE300D5A897 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; @@ -507,6 +511,7 @@ AD29CC601EA2B214008C8BFA /* action.cpp */, AD29CC611EA2B214008C8BFA /* action.h */, AD58E0701E2A90EF006ACC15 /* app.cpp */, + ADC6F4651F3E66FA004177FA /* app_dialogs.cpp */, AD0E11921ECA20F200CDA6BB /* app_events.cpp */, AD0E11931ECA20F200CDA6BB /* app_layout.cpp */, AD0E11941ECA20F200CDA6BB /* app_shaders.cpp */, @@ -727,6 +732,7 @@ AD0E5CD81ECC72AD00C35669 /* canvas_modes.cpp in Sources */, AD0E5CA31ECC6F2B00C35669 /* main.cpp in Sources */, AD0E5CB21ECC72AD00C35669 /* jpge.cpp in Sources */, + ADC6F4681F3E66FB004177FA /* app_dialogs.cpp in Sources */, AD0E5CD21ECC72AD00C35669 /* app_events.cpp in Sources */, AD0E5CD11ECC72AD00C35669 /* app.cpp in Sources */, AD0E5CC21ECC72AD00C35669 /* node_image.cpp in Sources */, @@ -787,6 +793,7 @@ AD1063891EC7ADFA002A525F /* node_message_box.cpp in Sources */, AD10638A1EC7ADFA002A525F /* node_panel_brush.cpp in Sources */, AD1063801EC7ADFA002A525F /* node_button_custom.cpp in Sources */, + ADC6F4661F3E66FB004177FA /* app_dialogs.cpp in Sources */, AD58E06F1E2A80BC006ACC15 /* shape.cpp in Sources */, AD58E0651E2A76FD006ACC15 /* shader.cpp in Sources */, AD4C08DA1E89BD0F0051D85F /* bezier.cpp in Sources */, @@ -892,6 +899,7 @@ AD02F0C31EDC457C00B2E692 /* sequencer.cpp in Sources */, AD1063A51EC7AE92002A525F /* node_panel_stroke.cpp in Sources */, ADD7D2911EBF9E1C00D5A897 /* event.cpp in Sources */, + ADC6F4671F3E66FB004177FA /* app_dialogs.cpp in Sources */, ADD7D2A41EBFA06F00D5A897 /* YGNodeList.c in Sources */, AD1063AB1EC7AE92002A525F /* node_text.cpp in Sources */, AD1063A11EC7AE92002A525F /* node_message_box.cpp in Sources */, diff --git a/engine/app.h b/engine/app.h index 168f359..88356b5 100644 --- a/engine/app.h +++ b/engine/app.h @@ -47,6 +47,7 @@ public: std::function on_color_change; std::function on_stroke_change; const uint16_t main_id = const_hash("main"); + std::string doc_name; float width; float height; bool keys[256]; diff --git a/engine/app_dialogs.cpp b/engine/app_dialogs.cpp index be61723..3ea8e19 100644 --- a/engine/app_dialogs.cpp +++ b/engine/app_dialogs.cpp @@ -11,15 +11,20 @@ void App::dialog_newdoc() dialog->init(); dialog->create(); dialog->loaded(); + dialog->input->set_text(""); layout[main_id]->add_child(dialog); layout[main_id]->update(); dialog->btn_ok->on_click = [this, dialog](Node*) { + doc_name = dialog->input->m_string; + if (auto docname = layout[main_id]->find("txt-docname")) + docname->set_text(("Panodoc: " + doc_name).c_str()); layers->clear(); canvas->m_canvas->m_layers.clear(); canvas->m_canvas->m_order.clear(); + canvas->reset_camera(); ActionManager::clear(); dialog->destroy(); }; @@ -43,10 +48,12 @@ void App::dialog_open() dialog->btn_ok->on_click = [this, dialog](Node*) { + canvas->reset_camera(); layers->clear(); canvas->m_canvas->project_open(dialog->selected_path); + doc_name = dialog->selected_name; if (auto docname = layout[main_id]->find("txt-docname")) - docname->set_text(("Document: " + dialog->selected_file).c_str()); + docname->set_text(("Panodoc: " + doc_name).c_str()); for (auto& i : canvas->m_canvas->m_order) layers->add_layer(canvas->m_canvas->m_layers[i].m_name.c_str()); dialog->destroy(); @@ -64,13 +71,17 @@ void App::dialog_save() dialog->init(); dialog->create(); dialog->loaded(); + dialog->input->set_text(doc_name); layout[main_id]->add_child(dialog); layout[main_id]->update(); dialog->btn_ok->on_click = [this, dialog](Node*) { - canvas->m_canvas->project_save(data_path + "/" + dialog->input->m_string + ".pano"); + doc_name = dialog->input->m_string; + if (auto docname = layout[main_id]->find("txt-docname")) + docname->set_text(("Panodoc: " + doc_name).c_str()); + canvas->m_canvas->project_save(data_path + "/" + doc_name + ".pano"); dialog->destroy(); }; } diff --git a/engine/app_events.cpp b/engine/app_events.cpp index 5019996..af13567 100644 --- a/engine/app_events.cpp +++ b/engine/app_events.cpp @@ -87,7 +87,7 @@ bool App::gesture_start(const glm::vec2& p0, const glm::vec2& p1) GestureEvent e; glm::vec2 p = glm::lerp(p0, p1, 0.5f); e.m_type = kEventType::GestureStart; - e.m_pos = p; + e.m_pos = p / glm::vec2(zoom); e.m_distance = glm::distance(p0, p1); gesture_p0 = p0; gesture_p1 = p1; @@ -101,7 +101,7 @@ bool App::gesture_move(const glm::vec2& p0, const glm::vec2& p1) GestureEvent e; glm::vec2 p = glm::lerp(p0, p1, 0.5f); e.m_type = kEventType::GestureMove; - e.m_pos = p; + e.m_pos = p / glm::vec2(zoom); e.m_distance = glm::distance(p0, p1); e.m_distance_delta = e.m_distance - glm::distance(gesture_p0, gesture_p1); e.m_pos_delta = p - glm::lerp(gesture_p0, gesture_p1, 0.5f); diff --git a/engine/canvas.cpp b/engine/canvas.cpp index 9696485..ff0f245 100644 --- a/engine/canvas.cpp +++ b/engine/canvas.cpp @@ -1011,7 +1011,8 @@ void ui::Canvas::project_save(std::string data_path) } // load thumbnail - Image thumb = thumbnail_generate(64, 64); + Image thumb = thumbnail_generate(128, 128); + thumb.flip(); fwrite(&thumb.width, sizeof(int), 1, fp); fwrite(&thumb.height, sizeof(int), 1, fp); fwrite(&thumb.comp, sizeof(int), 1, fp); @@ -1028,7 +1029,7 @@ void ui::Canvas::project_save(std::string data_path) int n_order = m_order[i]; fwrite(&n_order, sizeof(int), 1, fp); - int name_len = m_layers[i].m_name.size(); + int name_len = (int)m_layers[i].m_name.size(); fwrite(&name_len, sizeof(int), 1, fp); fwrite(m_layers[i].m_name.data(), name_len, 1, fp); diff --git a/engine/image.cpp b/engine/image.cpp index bd89d1a..9f5cd36 100644 --- a/engine/image.cpp +++ b/engine/image.cpp @@ -22,3 +22,18 @@ bool Image::load(std::string filename) m_data = std::unique_ptr(buffer); return true; } + +void Image::flip() +{ + auto flipped = std::make_unique(width*height*4); + int line_size = width * 4; + const uint8_t* src = m_data.get(); + uint8_t* dst = flipped.get() + line_size * (height - 1); + for (int y = 0; y < height; y++) + { + std::copy(src, src+line_size, dst); + src += line_size; + dst -= line_size; + } + std::swap(m_data, flipped); +} diff --git a/engine/image.h b/engine/image.h index e6da6fa..7781500 100644 --- a/engine/image.h +++ b/engine/image.h @@ -19,6 +19,7 @@ public: comp = 4; m_data = std::make_unique(size()); } + void flip(); void create() { m_data = std::make_unique(size()); } }; diff --git a/engine/node.cpp b/engine/node.cpp index 657c8b1..f311df4 100644 --- a/engine/node.cpp +++ b/engine/node.cpp @@ -54,7 +54,7 @@ kEventResult Node::on_event(Event* e) return current_mouse_capture->on_event(e); bool skip_children = false; - skip_children |= (e->m_cat == kEventCategory::MouseEvent) && + skip_children |= (e->m_cat == kEventCategory::MouseEvent || e->m_cat == kEventCategory::GestureEvent) && (m_mouse_captured) && (root()->current_mouse_capture == this) && m_capture_children; if (!skip_children) @@ -120,6 +120,18 @@ kEventResult Node::on_event(Event* e) } break; } + case kEventCategory::GestureEvent: + { + if (m_mouse_ignore) + break; + GestureEvent* ge = static_cast(e); + bool inside = point_in_rect(ge->m_pos, m_clip); + bool inside_old = m_mouse_inside; + m_mouse_inside = inside; + if ((inside || m_mouse_captured) && handle_event(e) == kEventResult::Consumed) + return kEventResult::Consumed; + break; + } default: if (handle_event(e) == kEventResult::Consumed) return kEventResult::Consumed; @@ -274,6 +286,12 @@ glm::vec4 Node::get_children_rect() const void Node::mouse_capture() { + if (auto n = root()->current_mouse_capture) + { + MouseEvent e; + e.m_type = kEventType::MouseCancel; + n->handle_event(&e); + } root()->current_mouse_capture = this; m_mouse_captured = true; } diff --git a/engine/node_canvas.cpp b/engine/node_canvas.cpp index e150711..a251fe2 100644 --- a/engine/node_canvas.cpp +++ b/engine/node_canvas.cpp @@ -257,13 +257,29 @@ kEventResult NodeCanvas::handle_event(Event* e) // m_canvas->m_alpha_lock = false; break; case kEventType::GestureStart: + mouse_capture(); + for (auto& mode : *m_canvas->m_mode) + mode->on_GestureEvent(ge); + break; case kEventType::GestureMove: for (auto& mode : *m_canvas->m_mode) mode->on_GestureEvent(ge); break; + case kEventType::GestureEnd: + mouse_release(); + for (auto& mode : *m_canvas->m_mode) + mode->on_GestureEvent(ge); + break; default: return kEventResult::Available; break; } return kEventResult::Consumed; } + +void NodeCanvas::reset_camera() +{ + m_canvas->m_cam_rot = {0, 0}; + m_canvas->m_cam_pos = {0, 0, 0}; + m_canvas->m_cam_fov = 85; +} diff --git a/engine/node_canvas.h b/engine/node_canvas.h index 0e9ab0f..004bef0 100644 --- a/engine/node_canvas.h +++ b/engine/node_canvas.h @@ -18,4 +18,5 @@ public: virtual void draw() override; virtual void handle_resize(glm::vec2 old_size, glm::vec2 new_size) override; virtual kEventResult handle_event(Event* e) override; + void reset_camera(); }; diff --git a/engine/node_color_quad.cpp b/engine/node_color_quad.cpp index b343a9c..9e7f131 100644 --- a/engine/node_color_quad.cpp +++ b/engine/node_color_quad.cpp @@ -42,6 +42,7 @@ kEventResult NodeColorQuad::handle_event(Event* e) { case kEventType::MouseDownL: { + m_old_value = m_value; dragging = true; mouse_capture(); auto sz = GetSize(); @@ -67,6 +68,14 @@ kEventResult NodeColorQuad::handle_event(Event* e) on_value_changed(this, m_value); } break; + case kEventType::MouseCancel: + mouse_release(); + dragging = false; + m_value = m_old_value; + set_value(m_value.x, m_value.y); + if (on_value_changed) + on_value_changed(this, m_value); + break; default: return kEventResult::Available; break; diff --git a/engine/node_color_quad.h b/engine/node_color_quad.h index e19e7fe..b178073 100644 --- a/engine/node_color_quad.h +++ b/engine/node_color_quad.h @@ -7,6 +7,7 @@ class NodeColorQuad : public NodeBorder bool dragging = false; public: glm::vec2 m_value; + glm::vec2 m_old_value; std::function on_value_changed; virtual Node* clone_instantiate() const override; virtual void clone_finalize(Node* dest) const override; diff --git a/engine/node_dialog_open.cpp b/engine/node_dialog_open.cpp index acabb30..d6c3a12 100644 --- a/engine/node_dialog_open.cpp +++ b/engine/node_dialog_open.cpp @@ -52,6 +52,7 @@ void NodeDialogOpen::init_controls() image_tex->tex.create(thumb); 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; @@ -191,4 +192,4 @@ void NodeDialogNewDoc::init_controls() void NodeDialogNewDoc::loaded() { -} \ No newline at end of file +} diff --git a/engine/node_dialog_open.h b/engine/node_dialog_open.h index 97abe1d..40b2e4c 100644 --- a/engine/node_dialog_open.h +++ b/engine/node_dialog_open.h @@ -34,6 +34,7 @@ public: Node* container; std::string selected_path; std::string selected_file; + std::string selected_name; std::string data_path; virtual Node* clone_instantiate() const override; virtual void clone_finalize(Node* dest) const override; diff --git a/engine/node_scroll.cpp b/engine/node_scroll.cpp index bb41c06..c37a344 100644 --- a/engine/node_scroll.cpp +++ b/engine/node_scroll.cpp @@ -12,6 +12,7 @@ kEventResult NodeScroll::handle_event(Event* e) { NodeBorder::handle_event(e); auto me = static_cast(e); + auto ge = static_cast(e); auto loc = (me->m_pos - m_pos) * root()->m_zoom; switch (e->m_type) { @@ -36,8 +37,33 @@ kEventResult NodeScroll::handle_event(Event* e) mouse_release(); m_dragging = false; break; -// case kEventType::MouseScroll: -// break; + case kEventType::MouseScroll: + { + auto pad = GetPadding(); + glm::vec2 padoff = { pad.y + pad.w, pad.x + pad.z }; + auto rect = get_children_rect(); + m_offset += me->m_scroll_delta * 50; + m_offset = glm::clamp(m_offset, -rect.zw() + m_clip_uncut.zw() - padoff, { 0, 0 }); + m_pos_offset_childred = m_offset; + } + break; + case kEventType::GestureStart: + m_offset_start = m_offset; + mouse_capture(); + break; + case kEventType::GestureMove: + { + auto pad = GetPadding(); + glm::vec2 padoff = { pad.y + pad.w, pad.x + pad.z }; + auto rect = get_children_rect(); + m_offset = m_offset_start + ge->m_pos_delta * m_mask; + m_offset = glm::clamp(m_offset, -rect.zw() + m_clip_uncut.zw() - padoff, { 0, 0 }); + m_pos_offset_childred = m_offset; + } + break; + case kEventType::GestureEnd: + mouse_release(); + break; case kEventType::MouseCancel: mouse_release(); m_dragging = false; diff --git a/engine/node_slider.cpp b/engine/node_slider.cpp index f9cba97..49c1c5b 100644 --- a/engine/node_slider.cpp +++ b/engine/node_slider.cpp @@ -74,6 +74,7 @@ kEventResult NodeSliderH::handle_event(Event* e) dragging = true; mouse_capture(); { + m_old_value = m_value; auto sz = GetSize(); auto pos = glm::clamp(((MouseEvent*)e)->m_pos - m_pos, { 0, 0 }, sz) * m_mask; m_value = pos / glm::max({ 1, 1 }, sz); @@ -95,6 +96,14 @@ kEventResult NodeSliderH::handle_event(Event* e) on_value_changed(this, glm::length(m_value)); } break; + case kEventType::MouseCancel: + mouse_release(); + dragging = false; + m_value = m_old_value; + set_value(glm::length(m_value)); + if (on_value_changed) + on_value_changed(this, glm::length(m_value)); + break; default: return kEventResult::Available; break; diff --git a/engine/node_slider.h b/engine/node_slider.h index 4597efe..57d72b3 100644 --- a/engine/node_slider.h +++ b/engine/node_slider.h @@ -7,6 +7,7 @@ class NodeSliderH : public NodeBorder public: glm::vec2 m_mask{ 1, 0 }; glm::vec2 m_value; + glm::vec2 m_old_value; std::function on_value_changed; virtual Node* clone_instantiate() const override; virtual void clone_copy(Node* dest) const override; diff --git a/engine/node_text_input.cpp b/engine/node_text_input.cpp index 1a83616..f09bc9e 100644 --- a/engine/node_text_input.cpp +++ b/engine/node_text_input.cpp @@ -87,3 +87,11 @@ kEventResult NodeTextInput::handle_event(Event* e) } return kEventResult::Consumed; } + +void NodeTextInput::set_text(const std::string& s) +{ + if (m_text) + m_text->set_text(s.c_str()); + m_string = s; +} + diff --git a/engine/node_text_input.h b/engine/node_text_input.h index 7853c92..15ed09b 100644 --- a/engine/node_text_input.h +++ b/engine/node_text_input.h @@ -10,6 +10,7 @@ public: virtual Node* clone_instantiate() const override; virtual void clone_finalize(Node* dest) const override; virtual void init() override; - void init_controls(); virtual kEventResult handle_event(Event* e) override; + void init_controls(); + void set_text(const std::string& s); };