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:
23
src/app.cpp
23
src/app.cpp
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
};
|
||||
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
|
||||
@@ -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();
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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++)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 };
|
||||
|
||||
@@ -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);
|
||||
|
||||
11
src/node.cpp
11
src/node.cpp
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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"),
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
23
src/pch.h
23
src/pch.h
@@ -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
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user