settings file and save/restore ui state

This commit is contained in:
2019-04-14 18:03:41 +02:00
parent ada1afbac2
commit a8d475fbfb
15 changed files with 596 additions and 38 deletions

View File

@@ -368,6 +368,7 @@
</ClCompile>
<ClCompile Include="src\rtt.cpp" />
<ClCompile Include="src\serializer.cpp" />
<ClCompile Include="src\settings.cpp" />
<ClCompile Include="src\shader.cpp" />
<ClCompile Include="src\shape.cpp" />
<ClCompile Include="src\texture.cpp" />
@@ -484,6 +485,7 @@
<ClInclude Include="src\pch.h" />
<ClInclude Include="src\rtt.h" />
<ClInclude Include="src\serializer.h" />
<ClInclude Include="src\settings.h" />
<ClInclude Include="src\shader.h" />
<ClInclude Include="src\shape.h" />
<ClInclude Include="src\texture.h" />

View File

@@ -345,6 +345,9 @@
<ClCompile Include="src\node_panel_floating.cpp">
<Filter>Source Files\ui</Filter>
</ClCompile>
<ClCompile Include="src\settings.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="src\app.h">
@@ -572,6 +575,9 @@
<ClInclude Include="src\node_panel_floating.h">
<Filter>Header Files\ui</Filter>
</ClInclude>
<ClInclude Include="src\settings.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="PanoPainter.rc">

View File

@@ -648,7 +648,7 @@
<border height="30" color=".4" align="center" justify="center">
<text text="Grids" color="1 1 1 1"/>
</border>
<border color=".4" pad="5" dir="col" width="100%">
<border color=".4" pad="5" dir="col" width="100%" grow="1">
<node dir="row" margin="0 0 10 0">
<node width="200" grow="1" margin="0 5 0 0">

View File

@@ -8,6 +8,7 @@
#ifdef __APPLE__
#include <Foundation/Foundation.h>
#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<Serializer::Integer>("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();

View File

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

View File

@@ -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<NodeButtonCustom>("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<NodeButtonCustom>("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<NodeText>("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<NodeButtonCustom>("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<NodeButtonCustom>("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<NodeButtonCustom>("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<NodePanelFloating>();
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<NodePanelFloating>();
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<NodePanelFloating>();
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<NodeButtonCustom>("panel-layers")->on_click = [this, popup_time, popup_exp, visible](Node*) {
//if (visible(floating_layers.get()))
// return;
//auto fpanel = floatings_container->add_child<NodePanelFloating>();
//if (!floating_layers)
//{
// floating_layers = fpanel->m_container->add_child_ref<NodePanelLayer>();
//}
//else
//{
// fpanel->m_container->add_child(floating_layers);
//}
if (visible(layers.get()))
return;
auto fpanel = floatings_container->add_child<NodePanelFloating>();
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<NodePanelFloating>();
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<NodePanelFloating>();
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<NodeButtonCustom>("experimental-rtl"))
{
auto ui = main->find("central-row");
NodeCheckBox* cb = rtl_btn->find<NodeCheckBox>("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<NodeCheckBox>("experimental-rtl-check");
cb->set_value(!cb->checked, true);
};
rtl_btn->find<NodeCheckBox>("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<NodeButtonCustom>("experimental-vr"))
{
NodeCheckBox* cb = vr_btn->find<NodeCheckBox>("experimental-vr-check");
cb->set_value(has_vr);
vr_btn->on_click = [this, popup_exp, vr_btn](Node* b)
{
NodeCheckBox* cb = vr_btn->find<NodeCheckBox>("experimental-vr-check");
cb->set_value(!cb->checked, true);
};
vr_btn->find<NodeCheckBox>("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<NodeCheckBox*>(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<NodePanelFloating>(c))
{
auto fd = list_floatings.add<Serializer::Descriptor>();
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<NodePanelFloating>(c))
{
auto fd = list_drop_left.add<Serializer::Descriptor>();
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<NodePanelFloating>(c))
{
auto fd = list_drop_right.add<Serializer::Descriptor>();
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<Serializer::Integer>("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<Serializer::Descriptor>("ui");
for (auto const& l : d->get<Serializer::List>("floatings")->items)
{
auto ld = std::static_pointer_cast<Serializer::Descriptor>(l);
auto pos = ld->value<Serializer::Vec2>("pos");
auto size = ld->value<Serializer::Vec2>("size");
auto cls = static_cast<NodePanelFloating::kClass>(ld->value<Serializer::Integer>("class"));
auto f = floatings->add_child<NodePanelFloating>();
switch (cls)
{
case NodePanelFloating::kClass::Presets:
{
auto floating_presets = f->m_container->add_child<NodePanelBrushPreset>();
floating_presets->SetHeightP(100);
floating_presets->find("toolbar")->destroy();
floating_presets->on_brush_changed = [this](Node* target, std::shared_ptr<Brush>& 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<NodePanelColor>();
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<NodeColorPicker>();
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<Node>();
break;
}
f->m_class = cls;
f->SetSize(size);
f->SetPosition(pos);
f->SetPositioning(YGPositionTypeAbsolute);
}
for (auto const& l : d->get<Serializer::List>("drop-left")->items)
{
auto ld = std::static_pointer_cast<Serializer::Descriptor>(l);
auto size = ld->value<Serializer::Vec2>("size");
auto cls = static_cast<NodePanelFloating::kClass>(ld->value<Serializer::Integer>("class"));
auto f = drop_left->add_child<NodePanelFloating>();
switch (cls)
{
case NodePanelFloating::kClass::Presets:
{
auto floating_presets = f->m_container->add_child<NodePanelBrushPreset>();
floating_presets->SetHeightP(100);
floating_presets->find("toolbar")->destroy();
floating_presets->on_brush_changed = [this](Node* target, std::shared_ptr<Brush>& 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<NodePanelColor>();
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<NodeColorPicker>();
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<Node>();
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<Serializer::List>("drop-right")->items)
{
auto ld = std::static_pointer_cast<Serializer::Descriptor>(l);
auto size = ld->value<Serializer::Vec2>("size");
auto cls = static_cast<NodePanelFloating::kClass>(ld->value<Serializer::Integer>("class"));
auto f = drop_right->add_child<NodePanelFloating>();
switch (cls)
{
case NodePanelFloating::kClass::Presets:
{
auto floating_presets = f->m_container->add_child<NodePanelBrushPreset>();
floating_presets->SetHeightP(100);
floating_presets->find("toolbar")->destroy();
floating_presets->on_brush_changed = [this](Node* target, std::shared_ptr<Brush>& 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<NodePanelColor>();
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<NodeColorPicker>();
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<Node>();
break;
}
f->m_class = cls;
f->m_dock = drop_right;
f->SetPositioning(YGPositionTypeRelative);
f->SetPosition(0, 0);
f->SetSize(size);
}
}

View File

@@ -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<uint8_t> data)
void BinaryStreamWriter::wkey_or_string(std::string s)
{
assert(s.size() > 0);
wstring(s);
}

View File

@@ -1,5 +1,6 @@
#pragma once
#include <codecvt>
#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();

View File

@@ -16,6 +16,7 @@
#include <deque>
#include <chrono>
#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<Serializer::IVec4>("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<Serializer::Integer>("window-show-cmd", show_cmd);
LOG("show main window");
ShowWindow(hWnd, SW_NORMAL);
ShowWindow(hWnd, show_cmd);
if (!sandboxed)
{

View File

@@ -32,6 +32,15 @@ void NodePanelFloating::init_controls()
m_button_minimize = find<NodeButton>("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<NodeButton>("button-close");
m_button_close->on_click = [this](Node*) {

View File

@@ -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<Node> 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<NodeBorder> m_drop_placeholder;
public:
Node* m_container;
std::weak_ptr<Node> 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;

View File

@@ -22,6 +22,9 @@ std::map<std::string /*key*/, std::function<Serializer::Type::Ref()>> Serializer
{ "vec2", [] { return std::make_shared<Serializer::Vec2>(); } },
{ "vec3", [] { return std::make_shared<Serializer::Vec3>(); } },
{ "vec4", [] { return std::make_shared<Serializer::Vec4>(); } },
{ "ive2", [] { return std::make_shared<Serializer::IVec2>(); } },
{ "ive3", [] { return std::make_shared<Serializer::IVec3>(); } },
{ "ive4", [] { return std::make_shared<Serializer::IVec4>(); } },
{ "flt ", [] { return std::make_shared<Serializer::Float>(); } },
{ "cstr", [] { return std::make_shared<Serializer::CString>(); } },
};

View File

@@ -70,7 +70,17 @@ public:
{
w.wi32((int)items.size());
for (auto& i : items)
{
w.wstring_raw(i->type_key());
i->write(w);
}
}
template <typename T>
std::shared_ptr<T> add()
{
auto ptr = std::make_shared<T>();
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<T>(props.at(key)) : nullptr;
}
template<typename T> std::shared_ptr<T> set(const std::string& key, const T value)
{
if (auto ptr = get<T>(key))
{
*ptr = value;
return ptr;
}
else
{
ptr = std::make_shared<T>(value);
props[key] = ptr;
return ptr;
}
}
template<typename T> auto value(const std::string& key) const
{
if (auto v = get<T>(key))
return v->value;
return decltype(T::value){};
}
template<typename T, typename D> auto value_or(const std::string& key, const D val) const
template<typename T, typename D = decltype(T::value)> auto value_or(const std::string& key, const D val) const
{
if (auto v = get<T>(key))
return v->value;
return val;
}
template<typename T, typename D> void value(const std::string& key, D& dest) const
template<typename T, typename D = decltype(T::value)> void value(const std::string& key, D& dest) const
{
if (auto v = get<T>(key))
dest = static_cast<D>(v->value);

26
src/settings.cpp Normal file
View File

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

35
src/settings.h Normal file
View File

@@ -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 <typename T>
static void set(const std::string& key, const T value)
{
I.Descriptor::set(key, value);
}
template <typename T>
static std::shared_ptr<T> get(const std::string& key)
{
return I.Descriptor::get<T>(key);
}
template <typename T, typename D = decltype(T::value)>
static void value(const std::string& key, D& dest)
{
I.Descriptor::value<T, D>(key, dest);
}
template <typename T>
static auto value(const std::string& key)
{
return I.Descriptor::value<T>(key);
}
};