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);
+ }
+};