diff --git a/data/layout.xml b/data/layout.xml
index 51b1227..33d72b5 100644
--- a/data/layout.xml
+++ b/data/layout.xml
@@ -258,14 +258,41 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
@@ -425,6 +452,10 @@
+
+
+
+
@@ -605,7 +636,6 @@
-->
-
diff --git a/engine.vcxproj b/engine.vcxproj
index 590d27a..0981fa3 100644
--- a/engine.vcxproj
+++ b/engine.vcxproj
@@ -192,6 +192,7 @@
+
@@ -301,6 +302,7 @@
+
diff --git a/engine.vcxproj.filters b/engine.vcxproj.filters
index 7aeba11..9be1bad 100644
--- a/engine.vcxproj.filters
+++ b/engine.vcxproj.filters
@@ -222,6 +222,9 @@
Source Files\ui
+
+ Source Files\ui
+
@@ -395,6 +398,9 @@
Header Files\ui
+
+ Header Files\ui
+
diff --git a/engine/app.cpp b/engine/app.cpp
index 61880b1..b7f75ef 100644
--- a/engine/app.cpp
+++ b/engine/app.cpp
@@ -231,8 +231,8 @@ void App::update(float dt)
//glViewport(0, 0, (GLsizei)width, (GLsizei)height);
//glClear(GL_COLOR_BUFFER_BIT);
-#ifndef __ANDROID__
- //layout.reload();
+#ifdef _WIN32
+ layout.reload();
#endif
if (auto* main = layout[main_id])
main->update(width, height, zoom);
diff --git a/engine/app.h b/engine/app.h
index 8a84458..1b228ca 100644
--- a/engine/app.h
+++ b/engine/app.h
@@ -123,6 +123,7 @@ public:
void dialog_newdoc();
void dialog_save();
void dialog_open();
+ void dialog_browse();
void dialog_export();
void dialog_layer_rename();
void brush_update();
diff --git a/engine/app_dialogs.cpp b/engine/app_dialogs.cpp
index 6fd5b3d..61875a8 100644
--- a/engine/app_dialogs.cpp
+++ b/engine/app_dialogs.cpp
@@ -1,6 +1,7 @@
#include "pch.h"
#include "app.h"
#include "node_dialog_open.h"
+#include "node_dialog_browse.h"
void App::dialog_newdoc()
{
@@ -75,6 +76,37 @@ void App::dialog_open()
}
}
+void App::dialog_browse()
+{
+ if (canvas)
+ {
+ // load thumbnail test
+ auto dialog = std::make_shared();
+ dialog->m_manager = &layout;
+ dialog->data_path = data_path;
+ dialog->init();
+ dialog->create();
+ dialog->loaded();
+
+ layout[main_id]->add_child(dialog);
+ layout[main_id]->update();
+
+ dialog->btn_ok->on_click = [this, dialog](Node*)
+ {
+ canvas->reset_camera();
+ layers->clear();
+ canvas->m_canvas->project_open(dialog->selected_path);
+ doc_name = dialog->selected_name;
+ if (auto docname = layout[main_id]->find("txt-docname"))
+ docname->set_text(("Panodoc: " + doc_name).c_str());
+ for (auto& i : canvas->m_canvas->m_order)
+ layers->add_layer(canvas->m_canvas->m_layers[i].m_name.c_str());
+ dialog->destroy();
+ ActionManager::clear();
+ };
+ }
+}
+
void App::dialog_save()
{
if (canvas)
diff --git a/engine/app_layout.cpp b/engine/app_layout.cpp
index 692f215..65b3642 100644
--- a/engine/app_layout.cpp
+++ b/engine/app_layout.cpp
@@ -360,6 +360,11 @@ void App::init_menu_file()
popup->mouse_release();
popup->destroy();
};
+ popup->find("file-browse")->on_click = [this](Node*) {
+ dialog_browse();
+ popup->mouse_release();
+ popup->destroy();
+ };
popup->find("file-save")->on_click = [this](Node*) {
dialog_save();
popup->mouse_release();
diff --git a/engine/layout.cpp b/engine/layout.cpp
index e9bab05..59687a1 100644
--- a/engine/layout.cpp
+++ b/engine/layout.cpp
@@ -8,16 +8,17 @@
bool LayoutManager::load(const char* path)
{
- if (m_loaded)
- return true; // already loaded
-#if !defined(__ANDROID__)
-// struct stat tmp_info;
-// if (stat(path, &tmp_info) != 0)
-// return false;
-// if (tmp_info.st_mtime <= m_file_info.st_mtime)
-// return false;
-// m_file_info = tmp_info;
+#if _WIN32
+ struct stat tmp_info;
+ if (stat(path, &tmp_info) != 0)
+ return false;
+ if (tmp_info.st_mtime <= m_file_info.st_mtime)
+ return false;
+ m_file_info = tmp_info;
+#else
+ if (m_loaded)
+ return true; // already loaded
#endif // __ANDROID__
m_path = path;
diff --git a/engine/main.cpp b/engine/main.cpp
index 587cde7..9846bd7 100644
--- a/engine/main.cpp
+++ b/engine/main.cpp
@@ -349,6 +349,7 @@ int main(int argc, char** argv)
bool running = true;
unsigned long t0 = GetTickCount();
unsigned long t1;
+ float one_sec = 0;
while (running)
{
// If there any message in the queue process it
@@ -362,6 +363,15 @@ int main(int argc, char** argv)
{
t1 = GetTickCount();
float dt = (float)(t1 - t0) / 1000.0f;
+
+ // force redraw every one second
+ one_sec += dt;
+ if (one_sec > 1.f)
+ {
+ one_sec = 0;
+ App::I.redraw = true;
+ }
+
if (dt > 1.0f / 60.0f)
{
t0 = t1;
diff --git a/engine/node.cpp b/engine/node.cpp
index c8ea42d..4efe034 100644
--- a/engine/node.cpp
+++ b/engine/node.cpp
@@ -24,6 +24,7 @@
#include "node_stroke_preview.h"
#include "node_canvas.h"
#include "node_scroll.h"
+#include "node_dialog_browse.h"
void Node::watch(std::function observer)
{
@@ -739,6 +740,9 @@ void Node::parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* attr)
case kAttribute::FloodEvents:
m_flood_events = attr->IntValue() > 0;
break;
+ case kAttribute::AspectRatio:
+ YGNodeStyleSetAspectRatio(y_node, attr->FloatValue());
+ break;
default:
break;
}
@@ -791,6 +795,8 @@ void Node::load_internal(const tinyxml2::XMLElement* x_node)
CASE(kWidget::StrokePreview, NodeStrokePreview);
CASE(kWidget::Canvas, NodeCanvas);
CASE(kWidget::Scroll, NodeScroll);
+ CASE(kWidget::DialogBrowse, NodeDialogBrowse);
+ CASE(kWidget::DialogBrowseItem, NodeDialogBrowseItem);
#undef CASE
case kWidget::Ref:
{
diff --git a/engine/node.h b/engine/node.h
index 221ca9d..5d702e2 100644
--- a/engine/node.h
+++ b/engine/node.h
@@ -38,6 +38,7 @@ enum class kAttribute : uint16_t
Template = const_hash("template"),
Value = const_hash("value"),
Range = const_hash("range"),
+ AspectRatio = const_hash("aspect-ratio"),
};
enum class kWidget : uint16_t
@@ -68,6 +69,8 @@ enum class kWidget : uint16_t
StrokePreview = const_hash("stroke-preview"),
Canvas = const_hash("canvas"),
Scroll = const_hash("scroll"),
+ DialogBrowse = const_hash("dialog-browse"),
+ DialogBrowseItem = const_hash("dialog-browse-item"),
};
class Node
diff --git a/engine/node_dialog_browse.cpp b/engine/node_dialog_browse.cpp
new file mode 100644
index 0000000..af7181b
--- /dev/null
+++ b/engine/node_dialog_browse.cpp
@@ -0,0 +1,166 @@
+#include "pch.h"
+#include "log.h"
+#include "node_dialog_browse.h"
+#include "canvas.h"
+#include "node_image_texture.h"
+#include "asset.h"
+#include "node_message_box.h"
+#include "app.h"
+
+Node* NodeDialogBrowse::clone_instantiate() const
+{
+ return new NodeDialogBrowse();
+}
+
+void NodeDialogBrowse::clone_finalize(Node* dest) const
+{
+ NodeDialogBrowse* n = static_cast(dest);
+ n->init_controls();
+}
+
+void NodeDialogBrowse::init()
+{
+ auto tpl = static_cast(init_template("dialog-browse"));
+ m_color = tpl->m_color;
+ m_border_color = tpl->m_border_color;;
+ m_thinkness = tpl->m_thinkness;;
+ init_controls();
+}
+
+void NodeDialogBrowse::init_controls()
+{
+ btn_ok = find("btn-ok");
+ btn_cancel = find("btn-cancel");
+ btn_cancel->on_click = [this](Node*) {
+ destroy();
+ };
+ btn_delete = find("btn-delete");
+ btn_delete->on_click = [this](Node*) {
+ if (!current)
+ return;
+
+ auto msgbox = new NodeMessageBox();
+ msgbox->m_manager = m_manager;
+ msgbox->init();
+ msgbox->m_title->set_text("Delete Project");
+ msgbox->m_message->set_text(("Are you sure you want to delete " + current->m_file_name + "?").c_str());
+ msgbox->btn_ok->on_click = [this,msgbox](Node*){
+ auto path = current->m_path;
+ int idx = container->get_child_index(current);
+ container->remove_child(current);
+ if (!container->m_children.empty())
+ {
+ int newidx = std::min(idx, (int)container->m_children.size() - 1);
+ auto next = (NodeDialogBrowseItem*)container->get_child_at(newidx);
+ current = nullptr;
+ next->on_selected(next);
+ next->m_selected = true;
+ }
+ else
+ {
+ current = nullptr;
+ auto image_tex = find("thumb-tex");
+ image_tex->tex.destroy();
+ }
+ Asset::delete_file(path);
+ msgbox->destroy();
+ };
+ root()->add_child(msgbox);
+ root()->update();
+ };
+ container = find("files-list");
+ auto names = Asset::list_files(data_path, false, ".*\\.pano");
+ for (const auto& n : names)
+ {
+ auto node = new NodeDialogBrowseItem;
+ node->m_manager = m_manager;
+ node->init();
+ node->m_text->set_text(n.c_str());
+ node->m_path = data_path + "/" + n;
+ node->m_file_name = n;
+ node->on_selected = [&](NodeDialogBrowseItem* target) {
+ if (target == current)
+ return;
+ selected_path = target->m_path;
+ selected_file = target->m_file_name;
+ selected_name = selected_file.substr(0, selected_file.length() - 5);
+ if (current)
+ current->m_selected = false;
+ current = target;
+ };
+
+ // load thumb
+ ui::Image thumb = ui::Canvas::I->thumbnail_read(node->m_path);
+ auto image_tex = node->find("thumb-tex");
+ image_tex->tex.destroy();
+ image_tex->tex.create(thumb);
+
+ container->add_child(node);
+ }
+// if (auto* first = (NodeDialogBrowseItem*)container->get_child_at(0))
+// {
+// first->on_selected(first);
+// first->m_selected = true;
+// }
+}
+
+void NodeDialogBrowse::loaded()
+{
+}
+
+//////////////////////////////////////////////////////////////////
+
+Node* NodeDialogBrowseItem::clone_instantiate() const
+{
+ return new NodeDialogBrowseItem;
+}
+void NodeDialogBrowseItem::clone_finalize(Node* dest) const
+{
+ NodeDialogBrowseItem* n = static_cast(dest);
+ n->init_controls();
+}
+void NodeDialogBrowseItem::init()
+{
+ auto tpl = static_cast(init_template("dialog-browse-item"));
+ m_color = tpl->m_color;
+ m_border_color = tpl->m_border_color;
+ m_thinkness = tpl->m_thinkness;
+ init_controls();
+}
+void NodeDialogBrowseItem::init_controls()
+{
+ m_text = find("title");
+}
+void NodeDialogBrowseItem::loaded()
+{
+
+}
+void NodeDialogBrowseItem::draw()
+{
+ auto c = m_selected ? m_color_selected : m_color_normal;
+ m_thinkness = m_selected ? 1.f : 0.f;
+ m_color = m_mouse_inside ? m_color_hover : c;
+ NodeBorder::draw();
+}
+kEventResult NodeDialogBrowseItem::handle_event(Event* e)
+{
+ NodeBorder::handle_event(e);
+ switch (e->m_type)
+ {
+ case kEventType::MouseEnter:
+ break;
+ case kEventType::MouseLeave:
+ break;
+ case kEventType::MouseDownL:
+ m_selected = true;
+ if (on_selected)
+ on_selected(this);
+ break;
+ case kEventType::MouseUpL:
+ break;
+ default:
+ return kEventResult::Available;
+ break;
+ }
+ return kEventResult::Consumed;
+}
diff --git a/engine/node_dialog_browse.h b/engine/node_dialog_browse.h
new file mode 100644
index 0000000..046cb71
--- /dev/null
+++ b/engine/node_dialog_browse.h
@@ -0,0 +1,46 @@
+#pragma once
+#include "node_border.h"
+#include "node_button.h"
+#include "node_image_texture.h"
+#include "node_text.h"
+#include "node_text_input.h"
+
+class NodeDialogBrowseItem : public NodeBorder
+{
+public:
+ NodeText* m_text;
+ NodeImageTexture* m_thumb;
+ glm::vec4 m_color_normal = glm::vec4(.4, .4, .4, 1);
+ glm::vec4 m_color_selected = glm::vec4(.3, .3, .3, 1);
+ glm::vec4 m_color_hover = glm::vec4(.5, .5, .5, 1);
+ bool m_selected = false;
+ std::string m_path;
+ std::string m_file_name;
+ std::function on_selected;
+ virtual Node* clone_instantiate() const override;
+ virtual void clone_finalize(Node* dest) const override;
+ virtual void init() override;
+ void init_controls();
+ virtual void loaded() override;
+ virtual void draw() override;
+ virtual kEventResult handle_event(Event* e) override;
+};
+
+class NodeDialogBrowse : public NodeBorder
+{
+public:
+ NodeButton* btn_cancel;
+ NodeButton* btn_ok;
+ NodeButton* btn_delete;
+ NodeDialogBrowseItem* current = nullptr;
+ Node* container;
+ std::string selected_path;
+ std::string selected_file;
+ std::string selected_name;
+ std::string data_path;
+ virtual Node* clone_instantiate() const override;
+ virtual void clone_finalize(Node* dest) const override;
+ virtual void init() override;
+ void init_controls();
+ virtual void loaded() override;
+};
diff --git a/engine/wacom.cpp b/engine/wacom.cpp
index cfe3652..3a32526 100644
--- a/engine/wacom.cpp
+++ b/engine/wacom.cpp
@@ -118,8 +118,14 @@ bool WacomTablet::init(HWND hWnd)
if (LoadWintab())
{
/* check if WinTab available. */
- if (gpWTInfoA(0, 0, NULL))
+ gpWTInfoA(0, 0, 0);
+ if (UINT ret = gpWTInfoA(WTI_DEFSYSCTX, 0, &glogContext))
{
+#ifdef _DEBUG
+ // this should just avoid errors in debug mode
+ if (ret != sizeof(LOGCONTEXTA))
+ return false;
+#endif // _DEBUG
g_hCtx = TabletInit(hWnd);
if (!g_hCtx)
{
@@ -147,6 +153,7 @@ bool WacomTablet::init(HWND hWnd)
void WacomTablet::terminate()
{
+ gpWTClose(g_hCtx);
UnloadWintab();
}