diff --git a/engine/app.cpp b/engine/app.cpp index 6ebc4c8..dc7f78f 100644 --- a/engine/app.cpp +++ b/engine/app.cpp @@ -17,6 +17,7 @@ void android_async_unlock(struct engine* engine); void async_lock(); void async_swap(); void async_unlock(); +void destroy_window(); #endif using namespace ui; @@ -29,6 +30,30 @@ void App::create() height = 1080/2; } +bool App::request_close() +{ + static bool dialog_already_opened = false; + if (ui::Canvas::I->m_unsaved && !dialog_already_opened) + { + async_start(); + auto* m = layout[main_id]->add_child(); + m->m_title->set_text("Unsaved document"); + m->m_message->set_text("Would you like to save before closing?"); + m->btn_ok->m_text->set_text("Yes"); + m->btn_ok->on_click = [](Node*) { + }; + m->btn_cancel->m_text->set_text("No"); + m->btn_cancel->on_click = [](Node*) { + destroy_window(); + PostQuitMessage(0); + }; + async_redraw(); + async_end(); + dialog_already_opened = true; + } + return false; +} + void App::clear() { glClearColor(.1f, .1f, .1f, 1.f); diff --git a/engine/app.h b/engine/app.h index 9802493..f09ee6a 100644 --- a/engine/app.h +++ b/engine/app.h @@ -101,6 +101,7 @@ public: void initAssets(); void initLayout(); void create(); + bool request_close(); void terminate(); void clear(); void update(float dt); diff --git a/engine/app_layout.cpp b/engine/app_layout.cpp index ae14c6f..30cc77c 100644 --- a/engine/app_layout.cpp +++ b/engine/app_layout.cpp @@ -14,7 +14,7 @@ static glm::vec4 color_button_hlight{ 1, .0, .0, 1 }; void App::title_update(std::string name, int resolution) { static char str[256]; - snprintf(str, 256, "Panodoc: %s (%dpx)", doc_name.c_str(), resolution); + snprintf(str, 256, "Panodoc: %s%s (%dpx)", doc_name.c_str(), canvas->m_canvas->m_unsaved ? "*" : "", resolution); if (auto docname = layout[main_id]->find("txt-docname")) docname->set_text(str); } @@ -661,6 +661,7 @@ void App::initLayout() layout[main_id]->add_child(butt); butt->on_click = [this](Node*){ + toggle_ui(); }; if (auto* slider = layout[main_id]->find("frames-slider")) diff --git a/engine/brush.cpp b/engine/brush.cpp index 48a1623..30dc9a0 100644 --- a/engine/brush.cpp +++ b/engine/brush.cpp @@ -145,7 +145,7 @@ ui::StrokeSample ui::Stroke::randomize_sample(const glm::vec2& pos, float pressu s.flow = m_brush.m_tip_flow * (1.f - rnd_nor() * m_brush.m_jitter_flow) * flow_dyn; auto hsv = convert_rgb2hsv(m_brush.m_tip_color); hsv.x = glm::clamp(glm::mix(hsv.x, (pressure - 0.5f) * 2.0f, m_brush.m_tip_hue * (float)m_brush.m_tip_hue_pressure) + (rnd_nor() - 0.5f) * m_brush.m_jitter_hue, 0.f, 1.f); - hsv.y = glm::clamp(glm::mix(hsv.y, (pressure - 0.5f) * 2.0f, m_brush.m_tip_sat * (float)m_brush.m_tip_sat_pressure) + (rnd_nor() - 0.5f) * m_brush.m_jitter_sat, 0.f, 1.f); + hsv.y = glm::clamp(glm::mix(hsv.y, (1.f - pressure - 0.5f) * 2.0f, m_brush.m_tip_sat * (float)m_brush.m_tip_sat_pressure) + (rnd_nor() - 0.5f) * m_brush.m_jitter_sat, 0.f, 1.f); hsv.z = glm::clamp(glm::mix(hsv.z, (pressure - 0.5f) * 2.0f, m_brush.m_tip_val * (float)m_brush.m_tip_val_pressure) + (rnd_nor() - 0.5f) * m_brush.m_jitter_val, 0.f, 1.f); m_hsv_jitter.add(hsv); s.col = convert_hsv2rgb(m_hsv_jitter.average()); diff --git a/engine/canvas.cpp b/engine/canvas.cpp index 2782e94..d3faa59 100644 --- a/engine/canvas.cpp +++ b/engine/canvas.cpp @@ -462,6 +462,7 @@ void ui::Canvas::stroke_commit() { if (!m_dirty || m_layers.empty()) return; + m_unsaved = true; m_dirty = false; m_dirty_stroke = true; // new stroke ready for timelapse capture App::I.redraw = true; @@ -805,6 +806,7 @@ bool ui::Canvas::create(int width, int height) } m_smask.create(width*2, height*2, "mask"); m_smask.clear({1, 1, 1, 1}); + m_unsaved = true; return true; } @@ -1452,6 +1454,7 @@ void ui::Canvas::project_save_thread(std::string file_path) pb->destroy(); App::I.async_update(); App::I.async_end(); + m_unsaved = false; } void ui::Canvas::project_open(std::string file_path, std::function on_complete) @@ -1597,6 +1600,7 @@ void ui::Canvas::project_open_thread(std::string file_path) gl.restore(); App::I.async_end(); } + m_unsaved = false; } ui::Image ui::Canvas::thumbnail_generate(int w, int h) diff --git a/engine/canvas.h b/engine/canvas.h index 61b69cc..25e73fb 100644 --- a/engine/canvas.h +++ b/engine/canvas.h @@ -48,6 +48,7 @@ public: Plane m_plane; Plane m_plane_brush; BrushMesh m_mesh; + bool m_unsaved = false; bool m_dirty = false; bool m_commit_delayed = false; bool m_dirty_stroke = false; diff --git a/engine/main.cpp b/engine/main.cpp index b608b07..c41d37b 100644 --- a/engine/main.cpp +++ b/engine/main.cpp @@ -47,6 +47,11 @@ std::string GetLastErrorAsString() return message; } +void destroy_window() +{ + DestroyWindow(hWnd); +} + void async_lock() { //std::lock_guard _lock(async_mutex); @@ -456,7 +461,9 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) BT_SetTerminate(); break; case WM_CLOSE: - PostQuitMessage(0); + if (App::I.request_close()) + PostQuitMessage(0); + else return true; break; case WM_SIZE: {