From a8d475fbfb7ea1440d8fbb1941c70c76078a650d Mon Sep 17 00:00:00 2001 From: omigamedev Date: Sun, 14 Apr 2019 18:03:41 +0200 Subject: [PATCH] settings file and save/restore ui state --- PanoPainter.vcxproj | 2 + PanoPainter.vcxproj.filters | 6 + data/layout.xml | 2 +- src/app.cpp | 16 +- src/app.h | 3 + src/app_layout.cpp | 358 +++++++++++++++++++++++++++++++++--- src/binary_stream.cpp | 26 ++- src/binary_stream.h | 4 + src/main.cpp | 35 +++- src/node_panel_floating.cpp | 9 + src/node_panel_floating.h | 4 +- src/serializer.cpp | 3 + src/serializer.h | 105 ++++++++++- src/settings.cpp | 26 +++ src/settings.h | 35 ++++ 15 files changed, 596 insertions(+), 38 deletions(-) create mode 100644 src/settings.cpp create mode 100644 src/settings.h diff --git a/PanoPainter.vcxproj b/PanoPainter.vcxproj index ccb777f..e375345 100644 --- a/PanoPainter.vcxproj +++ b/PanoPainter.vcxproj @@ -368,6 +368,7 @@ + @@ -484,6 +485,7 @@ + diff --git a/PanoPainter.vcxproj.filters b/PanoPainter.vcxproj.filters index 1c57556..60e0da6 100644 --- a/PanoPainter.vcxproj.filters +++ b/PanoPainter.vcxproj.filters @@ -345,6 +345,9 @@ Source Files\ui + + Source Files + @@ -572,6 +575,9 @@ Header Files\ui + + Header Files + diff --git a/data/layout.xml b/data/layout.xml index bd51a7e..7eb4928 100644 --- a/data/layout.xml +++ b/data/layout.xml @@ -648,7 +648,7 @@ - + diff --git a/src/app.cpp b/src/app.cpp index 97873d6..b75bdee 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -8,6 +8,7 @@ #ifdef __APPLE__ #include #endif +#include "settings.h" #ifdef __ANDROID__ void android_async_lock(struct engine* engine); @@ -264,6 +265,10 @@ void App::initLog() //LogRemote::I.start(); LogRemote::I.file_init(); LOG("%s", g_version); + + LOG("load preferences"); + if (!Settings::load()) + LOG("load preferences failed"); } int progress_callback_download(void *clientp, curl_off_t dltotal, @@ -439,6 +444,13 @@ void App::init() glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendEquationSeparate(GL_FUNC_ADD, GL_MAX); + int run_counter = Settings::value("run_counter") + 1; + Settings::set("run_counter", Serializer::Integer(run_counter)); + LOG("run_counter %d", run_counter); + + if (!Settings::save()) + LOG("save preferences failed"); + initShaders(); initAssets(); initLayout(); @@ -537,7 +549,7 @@ void App::update(float dt) //glClear(GL_COLOR_BUFFER_BIT); //if (!canvas->m_mouse_captured) -#if _DEBUG && (_WIN32 || __OSX__) +#if /*_DEBUG &&*/ (_WIN32 || __OSX__) reload_timer += dt; if (reload_timer > 1.0) { @@ -678,6 +690,8 @@ void App::update(float dt) void App::terminate() { LOG("App::terminate"); + ui_save(); + NodeStrokePreview::terminate_renderer(); rec_stop(); diff --git a/src/app.h b/src/app.h index bb89a6d..c064695 100644 --- a/src/app.h +++ b/src/app.h @@ -206,5 +206,8 @@ public: std::string res_to_string(int res); void crash_test(); + void ui_save(); + void ui_restore(); + void cmd_convert(std::string pano_path, std::string out_path); }; diff --git a/src/app_layout.cpp b/src/app_layout.cpp index 398c51a..1cd9991 100644 --- a/src/app_layout.cpp +++ b/src/app_layout.cpp @@ -6,6 +6,7 @@ #include "node_progress_bar.h" #include "node_dialog_picker.h" #include "node_panel_floating.h" +#include "settings.h" void App::title_update() { @@ -511,7 +512,7 @@ void App::init_menu_file() }; if (auto b = popup->find("file-import")) b->on_click = [this, popup](Node*) { - App::I.pick_file({ "JPG", "PNG", "ABR" }, [this](std::string path){ + pick_file({ "JPG", "PNG", "ABR" }, [this](std::string path){ std::string name, base, ext; std::regex r(R"((.*)[\\/]([^\\/]+)\.(\w+)$)"); std::smatch m; @@ -551,8 +552,8 @@ void App::init_menu_file() if (auto b = popup->find("file-open")) b->on_click = [this, popup](Node*) { //dialog_open(); - App::I.pick_file({"ppi","PPI"}, [this](std::string path){ - App::I.open_document(path); + pick_file({"ppi","PPI"}, [this](std::string path){ + open_document(path); }); popup->mouse_release(); popup->destroy(); @@ -723,18 +724,18 @@ void App::init_menu_experimental() { if (auto text = popup_time->find("menu-label")) { - text->set_text(App::I.rec_running ? "Stop Recording" : "Start Recording"); + text->set_text(rec_running ? "Stop Recording" : "Start Recording"); } } popup_time->find("timelapse-start")->on_click = [this, popup_time, popup_exp](Node*) { - App::I.rec_running ? App::I.rec_stop() : App::I.rec_start(); + rec_running ? rec_stop() : rec_start(); popup_time->destroy(); popup_exp->destroy(); }; popup_time->find("timelapse-clear")->on_click = [this, popup_time, popup_exp](Node*) { - App::I.rec_clear(); + rec_clear(); popup_time->destroy(); popup_exp->destroy(); }; @@ -742,7 +743,7 @@ void App::init_menu_experimental() popup_time->find("timelapse-export")->on_click = [this, popup_time, popup_exp](Node*) { popup_time->destroy(); popup_exp->destroy(); - App::I.rec_export(""); + rec_export(""); }; } }; @@ -783,6 +784,7 @@ void App::init_menu_experimental() if (visible(floating_presets.get())) return; auto fpanel = floatings_container->add_child(); + fpanel->m_class = NodePanelFloating::kClass::Presets; fpanel->SetHeight(300); fpanel->SetMinHeight(300); if (!floating_presets) @@ -811,6 +813,7 @@ void App::init_menu_experimental() if (visible(floating_color.get())) return; auto fpanel = floatings_container->add_child(); + fpanel->m_class = NodePanelFloating::kClass::Color; fpanel->SetHeight(300); fpanel->SetMinHeight(300); if (!floating_color) @@ -835,6 +838,7 @@ void App::init_menu_experimental() if (visible(floating_picker.get())) return; auto fpanel = floatings_container->add_child(); + fpanel->m_class = NodePanelFloating::kClass::ColorAdv; fpanel->SetHeight(300); fpanel->SetWidth(300); if (!floating_picker) @@ -856,21 +860,10 @@ void App::init_menu_experimental() popup_exp->destroy(); }; popup_time->find("panel-layers")->on_click = [this, popup_time, popup_exp, visible](Node*) { - //if (visible(floating_layers.get())) - // return; - //auto fpanel = floatings_container->add_child(); - //if (!floating_layers) - //{ - // floating_layers = fpanel->m_container->add_child_ref(); - //} - //else - //{ - // fpanel->m_container->add_child(floating_layers); - //} - if (visible(layers.get())) return; auto fpanel = floatings_container->add_child(); + fpanel->m_class = NodePanelFloating::kClass::Layers; fpanel->SetMinHeight(100); fpanel->SetHeight(300); fpanel->m_container->add_child(layers); @@ -887,10 +880,13 @@ void App::init_menu_experimental() if (visible(stroke.get())) return; auto fpanel = floatings_container->add_child(); + fpanel->m_class = NodePanelFloating::kClass::Brush; fpanel->m_container->add_child(stroke); fpanel->SetHeight(300); stroke->SetPositioning(YGPositionTypeRelative); stroke->SetPosition(0, 0); + stroke->SetWidthP(100); + stroke->SetHeightP(100); popup_time->destroy(); popup_exp->destroy(); @@ -899,6 +895,7 @@ void App::init_menu_experimental() if (visible(grid.get())) return; auto fpanel = floatings_container->add_child(); + fpanel->m_class = NodePanelFloating::kClass::Grids; fpanel->m_container->add_child(grid); fpanel->SetHeight(300); grid->SetPositioning(YGPositionTypeRelative); @@ -914,11 +911,16 @@ void App::init_menu_experimental() if (auto rtl_btn = popup_exp->find("experimental-rtl")) { + auto ui = main->find("central-row"); + NodeCheckBox* cb = rtl_btn->find("experimental-rtl-check"); + cb->set_value(ui->GetRTL() == YGDirectionRTL, false); + rtl_btn->on_click = [this, popup_exp, rtl_btn](Node* b) { NodeCheckBox* cb = rtl_btn->find("experimental-rtl-check"); cb->set_value(!cb->checked, true); }; + rtl_btn->find("experimental-rtl-check")->on_value_changed = [this, main](Node*, bool checked) { auto ui = main->find("central-row"); @@ -928,25 +930,29 @@ void App::init_menu_experimental() if (auto vr_btn = popup_exp->find("experimental-vr")) { + NodeCheckBox* cb = vr_btn->find("experimental-vr-check"); + cb->set_value(has_vr); + vr_btn->on_click = [this, popup_exp, vr_btn](Node* b) { NodeCheckBox* cb = vr_btn->find("experimental-vr-check"); cb->set_value(!cb->checked, true); }; + vr_btn->find("experimental-vr-check")->on_value_changed = [this, main](Node* target, bool checked) { if (checked) { - if (!App::I.vr_start()) + if (!vr_start()) { auto cb = static_cast(target); cb->set_value(false); - App::I.message_box("VR Failed", "Couldn't start Virtual Reality mode"); + message_box("VR Failed", "Couldn't start Virtual Reality mode"); } } else { - App::I.vr_stop(); + vr_stop(); } }; } @@ -1006,7 +1012,7 @@ void App::init_menu_about() { b->on_click = [this, popup](Node*) { LOG("crashing"); - App::I.crash_test(); + crash_test(); popup->mouse_release(); popup->destroy(); }; @@ -1038,7 +1044,7 @@ void App::init_menu_about() LOG("%lld ms", ms); static char str[256]; sprintf(str, "Time %lld ms", ms); - App::I.message_box("Performance test", str); + message_box("Performance test", str); popup->mouse_release(); popup->destroy(); }; @@ -1302,8 +1308,9 @@ void App::initLayout() //picker->SetHeightP(100); //color->find("title")->destroy(); */ + ui_restore(); - App::I.redraw = true; + redraw = true; }; LOG("initializing layout xml"); @@ -1316,3 +1323,304 @@ void App::initLayout() layout.load("data/layout.xml"); LOG("initializing layout completed"); } + +void App::ui_save() +{ + Serializer::Descriptor d; + d.class_id = "ui-state"; + + Serializer::List list_floatings; + for (auto const& c : layout[main_id]->find("floatings")->m_children) + { + if (auto const& f = std::dynamic_pointer_cast(c)) + { + auto fd = list_floatings.add(); + fd->class_id = "ui-flt"; + fd->set("pos", Serializer::Vec2(f->GetPosition())); + fd->set("size", Serializer::Vec2(f->m_size)); + fd->set("class", Serializer::Integer((int)f->m_class)); + } + } + d.set("floatings", list_floatings); + + Serializer::List list_drop_left; + for (auto const& c : layout[main_id]->find("drop-left")->m_children) + { + if (auto const& f = std::dynamic_pointer_cast(c)) + { + auto fd = list_drop_left.add(); + fd->class_id = "ui-dpl"; + fd->set("size", Serializer::Vec2(f->m_size)); + fd->set("class", Serializer::Integer((int)f->m_class)); + } + } + d.set("drop-left", list_drop_left); + + Serializer::List list_drop_right; + for (auto const& c : layout[main_id]->find("drop-right")->m_children) + { + if (auto const& f = std::dynamic_pointer_cast(c)) + { + auto fd = list_drop_right.add(); + fd->class_id = "ui-dpr"; + fd->set("size", Serializer::Vec2(f->m_size)); + fd->set("class", Serializer::Integer((int)f->m_class)); + } + } + d.set("drop-right", list_drop_right); + + Settings::set("ui", d); + Settings::set("ui-rtl", Serializer::Integer(layout[main_id]->find("central-row")->GetRTL())); + +#if _WIN32 + extern void win32_save_window_state(); + win32_save_window_state(); +#endif + + Settings::save(); +} + +void App::ui_restore() +{ + if (Settings::has("ui-rtl")) + layout[main_id]->find("central-row")->SetRTL((YGDirection)Settings::value("ui-rtl")); + + if (!Settings::has("ui")) + return; + auto floatings = layout[main_id]->find_ref("floatings"); + auto drop_left = layout[main_id]->find_ref("drop-left"); + auto drop_right = layout[main_id]->find_ref("drop-right"); + auto d = Settings::get("ui"); + for (auto const& l : d->get("floatings")->items) + { + auto ld = std::static_pointer_cast(l); + auto pos = ld->value("pos"); + auto size = ld->value("size"); + auto cls = static_cast(ld->value("class")); + auto f = floatings->add_child(); + switch (cls) + { + case NodePanelFloating::kClass::Presets: + { + auto floating_presets = f->m_container->add_child(); + floating_presets->SetHeightP(100); + floating_presets->find("toolbar")->destroy(); + floating_presets->on_brush_changed = [this](Node* target, std::shared_ptr& b) { + auto c = Canvas::I->m_current_brush->m_tip_color; + *Canvas::I->m_current_brush = *b; + Canvas::I->m_current_brush->m_tip_color = c; + Canvas::I->m_current_brush->load(); + brush_update(); + }; + break; + } + case NodePanelFloating::kClass::Color: + { + auto floating_color = f->m_container->add_child(); + floating_color->SetHeightP(100); + floating_color->find("title")->destroy(); + floating_color->on_color_changed = [this](Node* target, glm::vec4 color) { + Canvas::I->m_current_brush->m_tip_color = color; + brush_update(); + }; + break; + } + case NodePanelFloating::kClass::ColorAdv: + { + floating_picker = f->m_container->add_child_ref(); + floating_picker->m_autohide = false; + floating_picker->on_color_change = [this](Node* target, glm::vec3 color) { + Canvas::I->m_current_brush->m_tip_color = glm::vec4(color, 1.f); + brush_update(); + }; + break; + } + case NodePanelFloating::kClass::Layers: + f->m_container->add_child(layers); + f->SetMinHeight(100); + f->SetHeight(300); + layers->SetPositioning(YGPositionTypeRelative); + layers->SetPosition(0, 0); + layers->SetWidthP(100); + layers->SetHeightP(100); + layers->SetFlexShrink(0); + break; + case NodePanelFloating::kClass::Brush: + f->m_container->add_child(stroke); + stroke->SetPositioning(YGPositionTypeRelative); + stroke->SetPosition(0, 0); + stroke->SetWidthP(100); + stroke->SetHeightP(100); + break; + case NodePanelFloating::kClass::Grids: + f->m_container->add_child(grid); + grid->SetPositioning(YGPositionTypeRelative); + grid->SetPosition(0, 0); + grid->SetWidthP(100); + grid->SetHeightP(100); + break; + case NodePanelFloating::kClass::Generic: + default: + f->m_container->add_child(); + break; + } + f->m_class = cls; + f->SetSize(size); + f->SetPosition(pos); + f->SetPositioning(YGPositionTypeAbsolute); + } + + for (auto const& l : d->get("drop-left")->items) + { + auto ld = std::static_pointer_cast(l); + auto size = ld->value("size"); + auto cls = static_cast(ld->value("class")); + auto f = drop_left->add_child(); + switch (cls) + { + case NodePanelFloating::kClass::Presets: + { + auto floating_presets = f->m_container->add_child(); + floating_presets->SetHeightP(100); + floating_presets->find("toolbar")->destroy(); + floating_presets->on_brush_changed = [this](Node* target, std::shared_ptr& b) { + auto c = Canvas::I->m_current_brush->m_tip_color; + *Canvas::I->m_current_brush = *b; + Canvas::I->m_current_brush->m_tip_color = c; + Canvas::I->m_current_brush->load(); + brush_update(); + }; + break; + } + case NodePanelFloating::kClass::Color: + { + auto floating_color = f->m_container->add_child(); + floating_color->SetHeightP(100); + floating_color->find("title")->destroy(); + floating_color->on_color_changed = [this](Node* target, glm::vec4 color) { + Canvas::I->m_current_brush->m_tip_color = color; + brush_update(); + }; + break; + } + case NodePanelFloating::kClass::ColorAdv: + { + floating_picker = f->m_container->add_child_ref(); + floating_picker->m_autohide = false; + floating_picker->on_color_change = [this](Node* target, glm::vec3 color) { + Canvas::I->m_current_brush->m_tip_color = glm::vec4(color, 1.f); + brush_update(); + }; + break; + } + case NodePanelFloating::kClass::Layers: + f->m_container->add_child(layers); + layers->SetPositioning(YGPositionTypeRelative); + layers->SetPosition(0, 0); + layers->SetWidthP(100); + layers->SetHeightP(100); + layers->SetFlexShrink(0); + break; + case NodePanelFloating::kClass::Brush: + f->m_container->add_child(stroke); + stroke->SetPositioning(YGPositionTypeRelative); + stroke->SetPosition(0, 0); + stroke->SetWidthP(100); + stroke->SetHeightP(100); + break; + case NodePanelFloating::kClass::Grids: + f->m_container->add_child(grid); + grid->SetPositioning(YGPositionTypeRelative); + grid->SetPosition(0, 0); + grid->SetWidthP(100); + grid->SetHeightP(100); + break; + case NodePanelFloating::kClass::Generic: + default: + f->m_container->add_child(); + break; + } + f->m_class = cls; + f->m_dock = drop_left; + f->SetPositioning(YGPositionTypeRelative); + f->SetPosition(0, 0); + f->SetSize(size); + } + + for (auto const& l : d->get("drop-right")->items) + { + auto ld = std::static_pointer_cast(l); + auto size = ld->value("size"); + auto cls = static_cast(ld->value("class")); + auto f = drop_right->add_child(); + switch (cls) + { + case NodePanelFloating::kClass::Presets: + { + auto floating_presets = f->m_container->add_child(); + floating_presets->SetHeightP(100); + floating_presets->find("toolbar")->destroy(); + floating_presets->on_brush_changed = [this](Node* target, std::shared_ptr& b) { + auto c = Canvas::I->m_current_brush->m_tip_color; + *Canvas::I->m_current_brush = *b; + Canvas::I->m_current_brush->m_tip_color = c; + Canvas::I->m_current_brush->load(); + brush_update(); + }; + break; + } + case NodePanelFloating::kClass::Color: + { + auto floating_color = f->m_container->add_child(); + floating_color->SetHeightP(100); + floating_color->find("title")->destroy(); + floating_color->on_color_changed = [this](Node* target, glm::vec4 color) { + Canvas::I->m_current_brush->m_tip_color = color; + brush_update(); + }; + break; + } + case NodePanelFloating::kClass::ColorAdv: + { + floating_picker = f->m_container->add_child_ref(); + floating_picker->m_autohide = false; + floating_picker->on_color_change = [this](Node* target, glm::vec3 color) { + Canvas::I->m_current_brush->m_tip_color = glm::vec4(color, 1.f); + brush_update(); + }; + break; + } + case NodePanelFloating::kClass::Layers: + f->m_container->add_child(layers); + layers->SetPositioning(YGPositionTypeRelative); + layers->SetPosition(0, 0); + layers->SetWidthP(100); + layers->SetHeightP(100); + layers->SetFlexShrink(0); + break; + case NodePanelFloating::kClass::Brush: + f->m_container->add_child(stroke); + stroke->SetPositioning(YGPositionTypeRelative); + stroke->SetPosition(0, 0); + stroke->SetWidthP(100); + stroke->SetHeightP(100); + break; + case NodePanelFloating::kClass::Grids: + f->m_container->add_child(grid); + grid->SetPositioning(YGPositionTypeRelative); + grid->SetPosition(0, 0); + grid->SetWidthP(100); + grid->SetHeightP(100); + break; + case NodePanelFloating::kClass::Generic: + default: + f->m_container->add_child(); + break; + } + f->m_class = cls; + f->m_dock = drop_right; + f->SetPositioning(YGPositionTypeRelative); + f->SetPosition(0, 0); + f->SetSize(size); + } +} diff --git a/src/binary_stream.cpp b/src/binary_stream.cpp index a4144c7..2c8f0c1 100644 --- a/src/binary_stream.cpp +++ b/src/binary_stream.cpp @@ -1,7 +1,6 @@ #include "pch.h" #include "binary_stream.h" - - +#include "asset.h" BinaryStreamReader::~BinaryStreamReader() { @@ -17,6 +16,17 @@ void BinaryStreamReader::init(uint8_t* data_ptr, size_t size, ByteOrder byte_ord m_swap = byte_order == ByteOrder::Host ? false : byte_order != sys_order(); } +bool BinaryStreamReader::load(const std::string& path, ByteOrder byte_order /*= ByteOrder::Host*/) +{ + if (m_asset.open(path.c_str())) + { + m_asset.read_all(); + init(m_asset.m_data, m_asset.m_len, byte_order); + return true; + } + return false; +} + size_t BinaryStreamReader::pos() { return std::distance(m_ptr, m_cur); @@ -198,6 +208,17 @@ void BinaryStreamWriter::init(ByteOrder byte_order /*= ByteOrder::Host*/) m_swap = byte_order == ByteOrder::Host ? false : byte_order != sys_order(); } +bool BinaryStreamWriter::save(const std::string& path) const +{ + std::ofstream f(path, std::ios::binary); + if (f.good()) + { + f.write((char*)m_data.data(), m_data.size()); + return true; + } + return false; +} + void BinaryStreamWriter::skip(size_t bytes, uint8_t fill /*= 0*/) { m_data.resize(m_data.size() + bytes); @@ -334,5 +355,6 @@ void BinaryStreamWriter::wrle(std::vector data) void BinaryStreamWriter::wkey_or_string(std::string s) { + assert(s.size() > 0); wstring(s); } diff --git a/src/binary_stream.h b/src/binary_stream.h index 62a20c7..e4eed84 100644 --- a/src/binary_stream.h +++ b/src/binary_stream.h @@ -1,5 +1,6 @@ #pragma once #include +#include "asset.h" class BinaryStream { @@ -70,6 +71,7 @@ public: BinaryStreamReader() = default; ~BinaryStreamReader(); void init(uint8_t* data_ptr, size_t size, ByteOrder byte_order = ByteOrder::Host); + bool load(const std::string& path, ByteOrder byte_order = ByteOrder::Host); size_t pos(); void skip(size_t bytes); // snap to the next 4-alignment @@ -127,6 +129,7 @@ private: uint8_t *m_ptr = nullptr; uint8_t *m_cur = nullptr; size_t m_size = 0; + Asset m_asset; }; class BinaryStreamWriter : public BinaryStream @@ -137,6 +140,7 @@ public: BinaryStreamWriter() = default; ~BinaryStreamWriter() = default; void init(ByteOrder byte_order = ByteOrder::Host); + bool save(const std::string& path) const; void skip(size_t bytes, uint8_t fill = 0); // snap to the next 4-alignment void snap(); diff --git a/src/main.cpp b/src/main.cpp index bdb0d46..1d546b7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -16,6 +16,7 @@ #include #include #include "abr.h" +#include "settings.h" #define WM_USER_CLOSE (WM_USER + 1) @@ -517,6 +518,15 @@ void win32_vr_stop() } } +void win32_save_window_state() +{ + WINDOWPLACEMENT p; + GetWindowPlacement(hWnd, &p); + Settings::set("window-show-cmd", Serializer::Integer(p.showCmd)); + Settings::set("window-rect", Serializer::IVec4({ p.rcNormalPosition.left, + p.rcNormalPosition.top, p.rcNormalPosition.right, p.rcNormalPosition.bottom })); +} + int main(int argc, char** argv) { WNDCLASS wc; @@ -562,7 +572,6 @@ int main(int argc, char** argv) read_WMI_info(); App::I.create(); - RECT clientRect = { 0, 0, (int)App::I.width, (int)App::I.height }; // Inizialize data structures to zero memset(&wc, 0, sizeof(wc)); @@ -588,8 +597,21 @@ int main(int argc, char** argv) GetDpiForMonitor(monitor, MDT_EFFECTIVE_DPI, &x, &y); App::I.zoom *= (float)x / 96.f; - AdjustWindowRect(&clientRect, WS_OVERLAPPEDWINDOW, false); - hWnd = CreateWindow(wc.lpszClassName, L"PanoPainter", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, + RECT clientRect = { 0, 0, (int)App::I.width, (int)App::I.height }; + POINT clientPos = { CW_USEDEFAULT, CW_USEDEFAULT }; + if (Settings::has("window-rect")) + { + auto wnd_rect = Settings::value("window-rect"); + App::I.width = wnd_rect.z - wnd_rect.x; + App::I.height = wnd_rect.w - wnd_rect.y; + clientRect = { wnd_rect.x, wnd_rect.y, wnd_rect.z, wnd_rect.w }; + clientPos = { wnd_rect.x, wnd_rect.y }; + } + else + { + AdjustWindowRect(&clientRect, WS_OVERLAPPEDWINDOW, false); + } + hWnd = CreateWindow(wc.lpszClassName, L"PanoPainter", WS_OVERLAPPEDWINDOW, clientPos.x, clientPos.y, (float)(clientRect.right - clientRect.left) * App::I.zoom, (float)(clientRect.bottom - clientRect.top) * App::I.zoom, 0, 0, hInst, 0); @@ -651,7 +673,7 @@ int main(int argc, char** argv) wglDeleteContext(hRC); DestroyWindow(hWnd); - hWnd = CreateWindow(wc.lpszClassName, window_title, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, + hWnd = CreateWindow(wc.lpszClassName, window_title, WS_OVERLAPPEDWINDOW, clientPos.x, clientPos.y, (float)(clientRect.right - clientRect.left) * App::I.zoom, (float)(clientRect.bottom - clientRect.top) * App::I.zoom, 0, 0, hInst, 0); @@ -691,8 +713,11 @@ int main(int argc, char** argv) LOG("init app"); App::I.init(); + int show_cmd = SW_NORMAL; + Settings::value("window-show-cmd", show_cmd); + LOG("show main window"); - ShowWindow(hWnd, SW_NORMAL); + ShowWindow(hWnd, show_cmd); if (!sandboxed) { diff --git a/src/node_panel_floating.cpp b/src/node_panel_floating.cpp index de26dc0..0552e1b 100644 --- a/src/node_panel_floating.cpp +++ b/src/node_panel_floating.cpp @@ -32,6 +32,15 @@ void NodePanelFloating::init_controls() m_button_minimize = find("button-minimize"); m_button_minimize->on_click = [this](Node*) { m_container->ToggleVisibility(); + if (m_container->m_display) + { + SetHeight(m_extended_size.y); + } + else + { + m_extended_size.y = GetHeight(); + SetHeight(YGUndefined); + } }; m_button_close = find("button-close"); m_button_close->on_click = [this](Node*) { diff --git a/src/node_panel_floating.h b/src/node_panel_floating.h index fca1d3c..0b5ef26 100644 --- a/src/node_panel_floating.h +++ b/src/node_panel_floating.h @@ -6,7 +6,7 @@ class NodePanelFloating : public NodeBorder { enum class kDragAction : uint8_t { Move, Resize, Reheight } m_action; bool m_dragging = false; - std::weak_ptr m_dock; + glm::vec2 m_extended_size; glm::vec2 m_drag_start_pos; glm::vec2 m_drag_start_cur; NodeButton* m_button_minimize; @@ -15,8 +15,10 @@ class NodePanelFloating : public NodeBorder std::shared_ptr m_drop_placeholder; public: Node* m_container; + std::weak_ptr m_dock; using this_class = NodePanelFloating; using parent = NodeBorder; + enum class kClass : uint8_t { Presets, Color, ColorAdv, Layers, Brush, Grids, Generic } m_class = kClass::Generic; virtual Node* clone_instantiate() const override; virtual void clone_finalize(Node* dest) const override; virtual kEventResult handle_event(Event* e) override; diff --git a/src/serializer.cpp b/src/serializer.cpp index d84d3cf..c6e7c3a 100644 --- a/src/serializer.cpp +++ b/src/serializer.cpp @@ -22,6 +22,9 @@ std::map> Serializer { "vec2", [] { return std::make_shared(); } }, { "vec3", [] { return std::make_shared(); } }, { "vec4", [] { return std::make_shared(); } }, + { "ive2", [] { return std::make_shared(); } }, + { "ive3", [] { return std::make_shared(); } }, + { "ive4", [] { return std::make_shared(); } }, { "flt ", [] { return std::make_shared(); } }, { "cstr", [] { return std::make_shared(); } }, }; diff --git a/src/serializer.h b/src/serializer.h index 45a44c7..d1a2415 100644 --- a/src/serializer.h +++ b/src/serializer.h @@ -70,7 +70,17 @@ public: { w.wi32((int)items.size()); for (auto& i : items) + { + w.wstring_raw(i->type_key()); i->write(w); + } + } + template + std::shared_ptr add() + { + auto ptr = std::make_shared(); + items.emplace_back(ptr); + return ptr; } }; struct Double : public Type @@ -263,6 +273,81 @@ public: w.wflt(value.w); } }; + struct IVec2 : public Type + { + using native_type = glm::ivec2; + glm::ivec2 value; + IVec2() = default; + IVec2(glm::ivec2 v) : value(v) { } + virtual std::string type_key() const override { return "ive2"; } + virtual std::string str(int indent, const std::string& prefix) const override + { + return std::string(indent, '-') + prefix + fmt::format("ivec2: {} {}", value.x, value.y); + } + virtual bool read(BinaryStreamReader& r) override + { + value.x = r.ri32(); + value.y = r.ri32(); + return true; + } + virtual void write(BinaryStreamWriter& w) const override + { + w.wi32(value.x); + w.wi32(value.y); + } + }; + struct IVec3 : public Type + { + using native_type = glm::ivec3; + glm::ivec3 value; + IVec3() = default; + IVec3(glm::ivec3 v) : value(v) { } + virtual std::string type_key() const override { return "ive3"; } + virtual std::string str(int indent, const std::string& prefix) const override + { + return std::string(indent, '-') + prefix + fmt::format("ivec3: {} {} {}", value.x, value.y, value.z); + } + virtual bool read(BinaryStreamReader& r) override + { + value.x = r.ri32(); + value.y = r.ri32(); + value.z = r.ri32(); + return true; + } + virtual void write(BinaryStreamWriter& w) const override + { + w.wu32(value.x); + w.wu32(value.y); + w.wu32(value.z); + } + }; + struct IVec4 : public Type + { + using native_type = glm::ivec4; + glm::ivec4 value; + IVec4() = default; + IVec4(glm::ivec4 v) : value(v) { } + virtual std::string type_key() const override { return "ive4"; } + virtual std::string str(int indent, const std::string& prefix) const override + { + return std::string(indent, '-') + prefix + fmt::format("ivec4: {} {} {} {}", value.x, value.y, value.z, value.w); + } + virtual bool read(BinaryStreamReader& r) override + { + value.x = r.ri32(); + value.y = r.ri32(); + value.z = r.ri32(); + value.w = r.ri32(); + return true; + } + virtual void write(BinaryStreamWriter& w) const override + { + w.wi32(value.x); + w.wi32(value.y); + w.wi32(value.z); + w.wi32(value.w); + } + }; struct Enum : public Type { std::string type; @@ -352,7 +437,7 @@ public: struct Descriptor : public Type { std::wstring name; - std::string class_id; + std::string class_id = "desc"; Type::Map props; Descriptor() = default; virtual std::string type_key() const override { return "Objc"; } @@ -372,19 +457,33 @@ public: { return has(key) ? std::dynamic_pointer_cast(props.at(key)) : nullptr; } + template std::shared_ptr set(const std::string& key, const T value) + { + if (auto ptr = get(key)) + { + *ptr = value; + return ptr; + } + else + { + ptr = std::make_shared(value); + props[key] = ptr; + return ptr; + } + } template auto value(const std::string& key) const { if (auto v = get(key)) return v->value; return decltype(T::value){}; } - template auto value_or(const std::string& key, const D val) const + template auto value_or(const std::string& key, const D val) const { if (auto v = get(key)) return v->value; return val; } - template void value(const std::string& key, D& dest) const + template void value(const std::string& key, D& dest) const { if (auto v = get(key)) dest = static_cast(v->value); diff --git a/src/settings.cpp b/src/settings.cpp new file mode 100644 index 0000000..b1d34ef --- /dev/null +++ b/src/settings.cpp @@ -0,0 +1,26 @@ +#include "pch.h" +#include "settings.h" +#include "app.h" + +Settings Settings::I; + +bool Settings::load() +{ + auto path = App::I.data_path + "/settings/pref.bin"; + BinaryStreamReader sr; + if (sr.load(path)) + { + I.props.clear(); + return I.read(sr); + } + return false; +} + +bool Settings::save() +{ + auto path = App::I.data_path + "/settings/pref.bin"; + BinaryStreamWriter sw; + sw.init(); + I.write(sw); + return sw.save(path); +} diff --git a/src/settings.h b/src/settings.h new file mode 100644 index 0000000..f865ed1 --- /dev/null +++ b/src/settings.h @@ -0,0 +1,35 @@ +#pragma once +#include "serializer.h" + +class Settings : public Serializer::Descriptor +{ +public: + Settings() { class_id = "pref"; } + static Settings I; + static bool load(); + static bool save(); + static bool has(const std::string& key) + { + return I.Descriptor::has(key); + } + template + static void set(const std::string& key, const T value) + { + I.Descriptor::set(key, value); + } + template + static std::shared_ptr get(const std::string& key) + { + return I.Descriptor::get(key); + } + template + static void value(const std::string& key, D& dest) + { + I.Descriptor::value(key, dest); + } + template + static auto value(const std::string& key) + { + return I.Descriptor::value(key); + } +};