conditional os in UI xml, add system dialog file open on osx, check api format or error message when opening a document, per-char text wrap on NodeText, additional info on create doc dialog like working path

This commit is contained in:
2018-10-06 14:20:07 +02:00
parent 5baa807cce
commit 739784b0d1
23 changed files with 161 additions and 63 deletions

View File

@@ -37,16 +37,25 @@ void App::open_document(std::string path)
doc_name = path.substr(start, path.length() - start - strlen(".ppi"));
canvas->reset_camera();
layers->clear();
canvas->m_canvas->project_open(path, [this] {
canvas->m_canvas->project_open(path, [this](bool success){
// on complete
async_start();
title_update();
for (auto& i : canvas->m_canvas->m_order)
if (success)
{
auto* l = layers->add_layer(canvas->m_canvas->m_layers[i].m_name.c_str());
l->m_opacity->m_value.x = canvas->m_canvas->m_layers[i].m_opacity;
async_start();
title_update();
for (auto& i : canvas->m_canvas->m_order)
{
auto* l = layers->add_layer(canvas->m_canvas->m_layers[i].m_name.c_str());
l->m_opacity->m_value.x = canvas->m_canvas->m_layers[i].m_opacity;
}
async_end();
}
else
{
message_box("Open Document Error",
"There was an error opening the document.\n"
"It may be inaccessible or corrupted.");
}
async_end();
});
ActionManager::clear();
}

View File

@@ -94,6 +94,7 @@ public:
struct engine* and_engine;
#endif
void pick_image(std::function<void(std::string path)> callback);
void pick_file(std::vector<std::string> types, std::function<void(std::string path)> callback);
void display_file(std::string path);
void showKeyboard();
void hideKeyboard();

View File

@@ -1,5 +1,6 @@
#include "pch.h"
#include "app.h"
#include "action.h"
#include "node_dialog_open.h"
#include "node_dialog_browse.h"
#include "node_dialog_resize.h"
@@ -167,6 +168,7 @@ void App::dialog_newdoc()
}
}
// DEPRECATED
void App::dialog_open()
{
auto show_dialog = [this] {
@@ -184,19 +186,19 @@ void App::dialog_open()
dialog->btn_ok->on_click = [this, dialog](Node*)
{
canvas->reset_camera();
layers->clear();
doc_name = dialog->selected_name;
canvas->m_canvas->project_open(dialog->selected_path, [this] {
// on complete
async_start();
title_update();
for (auto& i : canvas->m_canvas->m_order)
layers->add_layer(canvas->m_canvas->m_layers[i].m_name.c_str());
async_end();
});
dialog->destroy();
ActionManager::clear();
// canvas->reset_camera();
// layers->clear();
// doc_name = dialog->selected_name;
// canvas->m_canvas->project_open(dialog->selected_path, [this](bool success) {
// // on complete
// async_start();
// title_update();
// for (auto& i : canvas->m_canvas->m_order)
// layers->add_layer(canvas->m_canvas->m_layers[i].m_name.c_str());
// async_end();
// });
// dialog->destroy();
// ActionManager::clear();
};
async_end();
};
@@ -410,6 +412,7 @@ void App::dialog_resize()
if (canvas)
canvas->m_canvas->resize(res, res);
App::I.title_update();
ActionManager::clear();
dialog->destroy();
};

View File

@@ -51,7 +51,33 @@ void App::pick_image(std::function<void(std::string path)> callback)
[ios_view pick_photo:callback];
#elif __OSX__
dispatch_async(dispatch_get_main_queue(), ^{
std::string path = [osx_view pick_file];
NSArray* fileTypes = [NSArray arrayWithObjects:@"png", @"PNG", @"jpg", @"JPG", @"jpeg", nil];
std::string path = [osx_view pick_file:fileTypes];
if (!path.empty())
callback(path);
});
#elif __ANDROID__
pick_file(and_app, callback);
#elif _WIN32
std::string path = win32_open_file();
if (!path.empty())
callback(path);
#endif
}
void App::pick_file(std::vector<std::string> types, std::function<void (std::string)> callback)
{
redraw = true;
#ifdef __IOS__
// not implemented on ios
//[ios_view pick_photo:callback];
#elif __OSX__
dispatch_async(dispatch_get_main_queue(), ^{
//NSArray* fileTypes = [NSArray arrayWithObjects:@"ppi", @"PPI", nil];
NSMutableArray<NSString*>* fileTypes = [NSMutableArray arrayWithCapacity:types.size()];
for (const auto& t : types)
[fileTypes addObject:[NSString stringWithCString:t.c_str() encoding:NSUTF8StringEncoding]];
std::string path = [osx_view pick_file:fileTypes];
if (!path.empty())
callback(path);
});

View File

@@ -389,7 +389,10 @@ void App::init_menu_file()
};
if (auto b = popup->find<NodeButtonCustom>("file-open"))
b->on_click = [this](Node*) {
dialog_open();
//dialog_open();
App::I.pick_file({"ppi","PPI"}, [this](std::string path){
App::I.open_document(path);
});
popup->mouse_release();
popup->destroy();
};

View File

@@ -13,7 +13,7 @@ AAssetManager* Asset::m_am;
bool Asset::delete_file(const std::string& path)
{
LOG("delete project: %s", path.c_str());
LOG("delete file: %s", path.c_str());
std::remove(path.c_str());
return true;
}
@@ -136,7 +136,7 @@ bool Asset::open(const char* path)
#ifdef __ANDROID__
if (!(m_asset = AAssetManager_open(m_am, path, AASSET_MODE_RANDOM)))
{
LOG("AAssetManager_open failed");
LOG("AAssetManager_open failed %s", path);
return false;
}
m_len = (int)AAsset_getLength(m_asset);
@@ -150,7 +150,7 @@ bool Asset::open(const char* path)
//LOG("asset file: %s", file_path.c_str());
if (!(m_fp = fopen(file_path.c_str(), "rb")))
{
LOG("errno = %d", errno);
LOG("asset open errno = %d, %s", errno, path);
return false;
}
fseek(m_fp, 0, SEEK_END);

View File

@@ -1674,31 +1674,34 @@ void ui::Canvas::project_save_thread(std::string file_path)
App::I.async_end();
}
void ui::Canvas::project_open(std::string file_path, std::function<void()> on_complete)
void ui::Canvas::project_open(std::string file_path, std::function<void(bool)> on_complete)
{
std::thread t([=] {
project_open_thread(file_path);
bool result = project_open_thread(file_path);
if (on_complete)
on_complete();
on_complete(result);
});
t.detach();
}
void ui::Canvas::project_open_thread(std::string file_path)
bool ui::Canvas::project_open_thread(std::string file_path)
{
FILE* fp = fopen(file_path.c_str(), "rb");
if (!fp)
{
LOG("cannot write project to %s", file_path.c_str());
return; // should probably return a bool
return false; // should probably return a bool
}
PPIHeader ppi_header;
fread(&ppi_header, sizeof(PPIHeader), 1, fp);
if (!ppi_header.valid())
return;
{
LOG("INVALID PPI HEADER");
return false;
}
gl_state gl;
std::shared_ptr<NodeProgressBar> pb;
if (App::I.layout.m_loaded)
@@ -1832,6 +1835,7 @@ void ui::Canvas::project_open_thread(std::string file_path)
App::I.title_update();
App::I.async_end();
}
return true;
}
ui::Image ui::Canvas::thumbnail_generate(int w, int h)
@@ -2134,7 +2138,6 @@ ui::Layer::Snapshot ui::Layer::snapshot(std::string data_path)
{
Snapshot snap;
static int counter = 0;
LOG("errno = %d", errno);
glBindTexture(GL_TEXTURE_2D, 0);
//glBindFramebuffer(GL_FRAMEBUFFER, 0);
for (int i = 0; i < 6; i++)

View File

@@ -216,8 +216,8 @@ public:
void project_save(std::function<void()> on_complete = nullptr);
void project_save(std::string file_path, std::function<void()> on_complete = nullptr);
void project_save_thread(std::string file_path);
void project_open(std::string file_path, std::function<void()> on_complete = nullptr);
void project_open_thread(std::string file_path);
void project_open(std::string file_path, std::function<void(bool)> on_complete = nullptr);
bool project_open_thread(std::string file_path);
void inject_xmp(std::string jpg_path);
ui::Image thumbnail_generate(int w, int h);
ui::Image thumbnail_read(std::string data_path);

View File

@@ -75,9 +75,14 @@ void TextMesh::update(kFont id, const char* text)
if (text[i] == '\n')
{
x = 0;
y += f.size *2;
y += f.size * 2;
continue;
}
if (max_width > 0 && x > max_width * 2 /*font scale factor*/)
{
x = 0;
y += f.size * 2;
}
int c = text[i] - f.start_char;
stbtt_aligned_quad q;
stbtt_GetBakedQuad((stbtt_bakedchar*)f.chars.data(), f.w, f.h, c, &x, &y, &q, true);

View File

@@ -40,6 +40,7 @@ class TextMesh
public:
GLuint font_array = 0;
int font_array_count = 0;
int max_width = 0;
GLuint font_buffers[2] = {0, 0};
kFont font_id;
glm::vec2 bb = { 0, 0 };

View File

@@ -48,6 +48,16 @@ bool LayoutManager::load(const char* path)
LOG("Layout node without id");
return false;
}
if (auto os = current->Attribute("os"))
{
auto osv = split(os, ',');
if (std::find(osv.begin(), osv.end(), PP_OS) == osv.end())
{
LOG("Layout %s not for this os(%s), skipping", id_str, PP_OS)
current = current->NextSiblingElement("layout");
continue;
}
}
//LOG("Parsing layout: %s", id_str);
uint16_t id = const_hash(id_str);
auto p = m_layouts.find(id);

View File

@@ -866,6 +866,17 @@ void Node::load_internal(const tinyxml2::XMLElement* x_node)
auto x_child = x_node->FirstChildElement();
while (x_child)
{
if (auto os = x_child->Attribute("os"))
{
auto osv = split(os, ',');
if (std::find(osv.begin(), osv.end(), PP_OS) == osv.end())
{
LOG("Element %s not for this os(%s), skipping", x_child->Name(), PP_OS)
x_child = x_child->NextSiblingElement();
continue;
}
}
kWidget child_id = (kWidget)const_hash(x_child->Name());
switch (child_id)
{

View File

@@ -24,6 +24,7 @@ enum class kAttribute : uint16_t
BorderColor = const_hash("border-color"),
Type = const_hash("type"),
Text = const_hash("text"),
TextWrapWidth = const_hash("text-wrap-width"),
FontFace = const_hash("font-face"),
FontSize = const_hash("font-size"),
Justify = const_hash("justify"),

View File

@@ -232,6 +232,12 @@ void NodeDialogNewDoc::init_controls()
if (btn_ok->on_click)
btn_ok->on_click(btn_ok);
};
#if defined(_WIN32) || defined(__OSX__)
working_path = find<NodeText>("path");
static char path_buffer[256];
realpath(App::I.data_path.c_str(), path_buffer);
working_path->set_text_format("Working dir: %s", path_buffer);
#endif
}
void NodeDialogNewDoc::loaded()
{

View File

@@ -66,6 +66,7 @@ public:
NodeButton* btn_cancel;
NodeButton* btn_ok;
NodeTextInput* input;
NodeText* working_path;
NodeComboBox* m_resolution;
virtual Node* clone_instantiate() const override;
virtual void clone_finalize(Node* dest) const override;

View File

@@ -12,6 +12,7 @@ void NodeText::clone_copy(Node* dest) const
{
Node::clone_copy(dest);
NodeText* n = static_cast<NodeText*>(dest);
n->m_text_mesh.max_width = m_text_mesh.max_width;
n->m_text_mesh.create();
n->m_text_mesh.update(font_id, m_text.c_str());
n->m_text = m_text;
@@ -53,6 +54,9 @@ void NodeText::parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* att
Node::parse_attributes(ka, attr);
switch (ka)
{
case kAttribute::TextWrapWidth:
m_text_mesh.max_width = attr->IntValue();
break;
case kAttribute::Text:
m_text = unescape(attr->Value());
break;
@@ -84,6 +88,18 @@ void NodeText::set_text(const char* s)
SetSize(m_text_mesh.bb);
}
void NodeText::set_text_format(const char* fmt, ...)
{
static char buffer[4096];
va_list args;
va_start(args, fmt);
vsnprintf(buffer, sizeof(buffer), fmt, args);
va_end(args);
m_text = buffer;
m_text_mesh.update(font_id, buffer);
SetSize(m_text_mesh.bb);
}
void NodeText::draw()
{
using namespace ui;

View File

@@ -17,6 +17,7 @@ public:
virtual void restore_context() override;
virtual void parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* attr) override;
void set_text(const char* s);
void set_text_format(const char* fmt, ...);
void set_font(kFont fontID);
virtual void draw() override;
};

View File

@@ -8,21 +8,7 @@
#ifdef __APPLE__
#include "TargetConditionals.h"
#if TARGET_OS_IPHONE && TARGET_IPHONE_SIMULATOR
#define TARGET_OS_IOS 1
#define __IOS__ 1
#include <CoreFoundation/CoreFoundation.h>
#ifdef __OBJC__
#import <Foundation/Foundation.h>
#import <AVFoundation/AVFoundation.h>
#import <UIKit/UIKit.h>
#import <GLKit/GLKit.h>
#endif
#include <OpenGLES/ES3/gl.h>
#include <OpenGLES/ES3/glext.h>
#define SHADER_VERSION "#version 300 es\n"
#elif TARGET_OS_IPHONE
#define TARGET_OS_IOS 1
#if TARGET_OS_IOS
#define __IOS__ 1
#include <CoreFoundation/CoreFoundation.h>
#ifdef __OBJC__
@@ -34,8 +20,8 @@
#include <OpenGLES/ES3/gl.h>
#include <OpenGLES/ES3/glext.h>
#define SHADER_VERSION "#version 300 es\n"
#define PP_OS "ios"
#else
#define TARGET_OS_OSX 1
#define __OSX__ 1
#ifdef __OBJC__
#import <Foundation/Foundation.h>
@@ -44,6 +30,7 @@
#include <OpenGL/gl3.h>
#include <OpenGL/gl3ext.h>
#define SHADER_VERSION "#version 150\n"
#define PP_OS "osx"
#endif
#include <sys/stat.h>
@@ -51,6 +38,7 @@
#include <dirent.h>
#elif __ANDROID__
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES3/gl3.h>
@@ -61,8 +49,10 @@
#include <android_native_app_glue.h>
#define SHADER_VERSION "#version 300 es\n"
#define PP_OS "android"
#elif _WIN32
#define _USE_MATH_DEFINES
#define _CRT_SECURE_NO_WARNINGS
#define _SCL_SECURE_NO_WARNINGS
@@ -77,6 +67,7 @@
#include <shlwapi.h>
#define SHADER_VERSION "#version 150\n"
#define PP_OS "win"
#endif

View File

@@ -15,7 +15,7 @@ public:
void assign(GLuint tex, int w = -1, int h = -1, GLuint internal_format = GL_RGBA8, GLuint format = GL_RGBA);
bool load(std::string filename);
bool load_file(std::string filename);
void destroy() { if (m_tex) LOG("TEX destroy %d", m_tex); glDeleteTextures(1, &m_tex); m_tex = 0; }
void destroy() { if (m_tex) /*LOG("TEX destroy %d", m_tex);*/ glDeleteTextures(1, &m_tex); m_tex = 0; }
void bind() const { glBindTexture(GL_TEXTURE_2D, m_tex); }
void unbind() const { glBindTexture(GL_TEXTURE_2D, 0); }
void update(const uint8_t* data);