431 lines
11 KiB
C++
431 lines
11 KiB
C++
#include "pch.h"
|
|
#include "app.h"
|
|
|
|
#ifdef __ANDROID__
|
|
void displayKeyboard(android_app* mApplication, bool pShow);
|
|
void android_pick_file(android_app* mApplication, std::function<void(std::string)> callback);
|
|
#elif _WIN32
|
|
std::string win32_open_file(const char* filter);
|
|
std::string win32_open_dir();
|
|
void win32_show_cursor(bool visible);
|
|
bool win32_clipboard_set_text(const std::string & s);
|
|
std::string win32_clipboard_get_text();
|
|
#endif
|
|
|
|
|
|
std::string App::clipboard_get_text()
|
|
{
|
|
#if _WIN32
|
|
return win32_clipboard_get_text();
|
|
#elif __IOS__
|
|
return [ios_view clipboard_get_string];
|
|
#elif __OSX__
|
|
return [osx_view clipboard_get_string];
|
|
#endif
|
|
}
|
|
|
|
bool App::clipboard_set_text(const std::string& s)
|
|
{
|
|
#if _WIN32
|
|
return win32_clipboard_set_text(s);
|
|
#elif __IOS__
|
|
return [ios_view clipboard_set_string:s];
|
|
#elif __OSX__
|
|
return [osx_view clipboard_set_string:s];
|
|
#endif
|
|
}
|
|
|
|
|
|
void App::crash_test()
|
|
{
|
|
#ifdef __IOS__
|
|
[ios_view crash];
|
|
#elif __OSX__
|
|
[osx_view hockeyapp_crash];
|
|
#elif defined(_WIN32)
|
|
__debugbreak();
|
|
#elif defined(__ANDROID__)
|
|
#endif
|
|
}
|
|
|
|
void App::tick(float dt)
|
|
{
|
|
if (auto* main = layout[main_id])
|
|
main->tick(dt);
|
|
}
|
|
|
|
void App::resize(float w, float h)
|
|
{
|
|
LOG("App::resize %d %d", (int)w, (int)h);
|
|
uirtt.create(w, h, -1, GL_RGBA8, true);
|
|
redraw = true;
|
|
width = w;
|
|
height = h;
|
|
if (auto* main = layout[main_id])
|
|
main->update(w , h, zoom);
|
|
}
|
|
|
|
void App::show_cursor()
|
|
{
|
|
#ifdef _WIN32
|
|
win32_show_cursor(true);
|
|
#elif __OSX__
|
|
[osx_view show_cursor:true];
|
|
#endif
|
|
}
|
|
|
|
void App::hide_cursor()
|
|
{
|
|
#ifdef _WIN32
|
|
win32_show_cursor(false);
|
|
#elif __OSX__
|
|
[osx_view show_cursor:false];
|
|
#endif
|
|
}
|
|
|
|
void App::showKeyboard()
|
|
{
|
|
LOG("show keyboard");
|
|
redraw = true;
|
|
#ifdef __IOS__
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
[ios_view registerForKeyboardNotifications];
|
|
[ios_view becomeFirstResponder];
|
|
});
|
|
#elif __ANDROID__
|
|
displayKeyboard(and_app, true);
|
|
#endif
|
|
}
|
|
|
|
void App::hideKeyboard()
|
|
{
|
|
LOG("hide keyboard");
|
|
redraw = true;
|
|
#ifdef __IOS__
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
[ios_view resignFirstResponder];
|
|
// [ios_view unregisterForKeyboardNotifications];
|
|
});
|
|
#elif __ANDROID__
|
|
displayKeyboard(and_app, false);
|
|
#endif
|
|
}
|
|
|
|
void App::pick_image(std::function<void(std::string path)> callback)
|
|
{
|
|
redraw = true;
|
|
#ifdef __IOS__
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
[ios_view pick_photo:callback];
|
|
});
|
|
#elif __OSX__
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
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__
|
|
android_pick_file(and_app, callback);
|
|
#elif _WIN32
|
|
std::string path = win32_open_file("Image Files (*.jpg, *.png)\0*.jpg;*.png");
|
|
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
|
|
// fallback to pick_image
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
[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);
|
|
});
|
|
#elif __ANDROID__
|
|
android_pick_file(and_app, callback);
|
|
#elif _WIN32
|
|
std::string filter = "Supported Files (";
|
|
bool first_type = true;
|
|
for (auto& t : types)
|
|
{
|
|
filter.append(std::string(first_type ? "" : " ,") + "*." + t);
|
|
first_type = false;
|
|
}
|
|
filter.append(")");
|
|
filter.push_back(0);
|
|
first_type = true;
|
|
for (auto& t : types)
|
|
{
|
|
filter.append(std::string(first_type ? "" : ";") + "*." + t);
|
|
first_type = false;
|
|
}
|
|
filter.push_back(0);
|
|
std::string path = win32_open_file(filter.c_str());
|
|
if (!path.empty())
|
|
callback(path);
|
|
#endif
|
|
}
|
|
|
|
void App::pick_dir(std::function<void(std::string path)> callback)
|
|
{
|
|
redraw = true;
|
|
#ifdef __IOS__
|
|
// NOT IMPLEMENTED
|
|
#elif __OSX__
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
std::string path = [osx_view pick_dir];
|
|
if (!path.empty())
|
|
callback(path);
|
|
});
|
|
#elif __ANDROID__
|
|
// NOT IMPLEMENTED
|
|
#elif _WIN32
|
|
// TODO: to be implemented
|
|
std::string path = win32_open_dir();
|
|
if (!path.empty())
|
|
callback(path);
|
|
#endif
|
|
}
|
|
|
|
void App::display_file(std::string path)
|
|
{
|
|
#ifdef __IOS__
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
[ios_view display_file:path];
|
|
});
|
|
#elif __OSX__
|
|
[[NSWorkspace sharedWorkspace] openFile:[NSString stringWithUTF8String:path.c_str()]];
|
|
// dispatch_async(dispatch_get_main_queue(), ^{
|
|
// std::string path = [osx_view pick_file];
|
|
// if (!path.empty())
|
|
// callback(path);
|
|
// });
|
|
#elif __ANDROID__
|
|
//displayKeyboard(and_app, false);
|
|
#elif _WIN32
|
|
// std::string path = win32_open_file();
|
|
// if (!path.empty())
|
|
// callback(path);
|
|
#endif
|
|
}
|
|
|
|
void App::share_file(std::string path)
|
|
{
|
|
if (path.empty())
|
|
{
|
|
message_box("Sharing failed", "Please save the document before sharing it.");
|
|
return;
|
|
}
|
|
#ifdef __IOS__
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
[ios_view share_file:[NSString stringWithUTF8String:path.c_str()]];
|
|
});
|
|
#elif __OSX__
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
[osx_view share_file:[NSString stringWithUTF8String:path.c_str()]];
|
|
});
|
|
#elif __ANDROID__
|
|
#elif _WIN32
|
|
// not implemented
|
|
#endif
|
|
}
|
|
|
|
bool App::mouse_down(int button, float x, float y, float pressure, kEventSource source, bool eraser)
|
|
{
|
|
redraw = true;
|
|
MouseEvent e;
|
|
e.m_type = button ? kEventType::MouseDownR : kEventType::MouseDownL;
|
|
e.m_pos = { x / zoom, y / zoom };
|
|
e.m_pressure = pressure;
|
|
e.m_source = source;
|
|
e.m_eraser = eraser;
|
|
kEventResult ret = kEventResult::Available;
|
|
if (auto* main = layout[main_id])
|
|
{
|
|
ret = main->on_event(&e);
|
|
main->update();
|
|
}
|
|
return ret == kEventResult::Consumed;
|
|
}
|
|
bool App::mouse_move(float x, float y, float pressure, kEventSource source, bool eraser)
|
|
{
|
|
cursor = { x / zoom, y / zoom };
|
|
redraw = true;
|
|
MouseEvent e;
|
|
e.m_type = kEventType::MouseMove;
|
|
e.m_pos = { x / zoom, y / zoom };
|
|
e.m_pressure = pressure;
|
|
e.m_source = source;
|
|
e.m_eraser = eraser;
|
|
kEventResult ret = kEventResult::Available;
|
|
if (auto* main = layout[main_id])
|
|
ret = main->on_event(&e);
|
|
return ret == kEventResult::Consumed;
|
|
}
|
|
bool App::mouse_up(int button, float x, float y, kEventSource source, bool eraser)
|
|
{
|
|
redraw = true;
|
|
MouseEvent e;
|
|
e.m_type = button ? kEventType::MouseUpR : kEventType::MouseUpL;
|
|
e.m_pos = { x / zoom, y / zoom };
|
|
e.m_source = source;
|
|
e.m_eraser = eraser;
|
|
kEventResult ret = kEventResult::Available;
|
|
if (auto* main = layout[main_id])
|
|
{
|
|
ret = main->on_event(&e);
|
|
main->update();
|
|
}
|
|
return ret == kEventResult::Consumed;
|
|
}
|
|
bool App::mouse_scroll(float x, float y, float delta)
|
|
{
|
|
redraw = true;
|
|
MouseEvent e;
|
|
e.m_type = kEventType::MouseScroll;
|
|
e.m_pos = { x / zoom, y / zoom };
|
|
e.m_scroll_delta = delta;
|
|
kEventResult ret = kEventResult::Available;
|
|
if (auto* main = layout[main_id])
|
|
{
|
|
ret = main->on_event(&e);
|
|
main->update();
|
|
}
|
|
return ret == kEventResult::Consumed;
|
|
}
|
|
bool App::mouse_cancel(int button)
|
|
{
|
|
redraw = true;
|
|
MouseEvent e;
|
|
e.m_type = kEventType::MouseCancel;
|
|
kEventResult ret = kEventResult::Available;
|
|
if (auto* main = layout[main_id])
|
|
{
|
|
ret = main->on_event(&e);
|
|
main->update();
|
|
}
|
|
return ret == kEventResult::Consumed;
|
|
}
|
|
bool App::gesture_start(const glm::vec2& p0, const glm::vec2& p1)
|
|
{
|
|
redraw = true;
|
|
GestureEvent e;
|
|
glm::vec2 p = glm::lerp(p0, p1, 0.5f);
|
|
e.m_type = kEventType::GestureStart;
|
|
e.m_pos = p / glm::vec2(zoom);
|
|
e.m_distance = glm::distance(p0, p1);
|
|
gesture_p0 = p0;
|
|
gesture_p1 = p1;
|
|
kEventResult ret = kEventResult::Available;
|
|
if (auto* main = layout[main_id])
|
|
{
|
|
ret = main->on_event(&e);
|
|
main->update();
|
|
}
|
|
return ret == kEventResult::Consumed;
|
|
}
|
|
bool App::gesture_move(const glm::vec2& p0, const glm::vec2& p1)
|
|
{
|
|
redraw = true;
|
|
GestureEvent e;
|
|
glm::vec2 p = glm::lerp(p0, p1, 0.5f);
|
|
e.m_type = kEventType::GestureMove;
|
|
e.m_pos = p / glm::vec2(zoom);
|
|
e.m_distance = glm::distance(p0, p1);
|
|
e.m_distance_delta = e.m_distance - glm::distance(gesture_p0, gesture_p1);
|
|
e.m_pos_delta = p - glm::lerp(gesture_p0, gesture_p1, 0.5f);
|
|
kEventResult ret = kEventResult::Available;
|
|
if (auto* main = layout[main_id])
|
|
{
|
|
ret = main->on_event(&e);
|
|
main->update();
|
|
}
|
|
return ret == kEventResult::Consumed;
|
|
}
|
|
bool App::gesture_end()
|
|
{
|
|
redraw = true;
|
|
GestureEvent e;
|
|
e.m_type = kEventType::GestureEnd;
|
|
kEventResult ret = kEventResult::Available;
|
|
if (auto* main = layout[main_id])
|
|
{
|
|
ret = main->on_event(&e);
|
|
main->update();
|
|
}
|
|
return ret == kEventResult::Consumed;
|
|
}
|
|
bool App::key_down(kKey key)
|
|
{
|
|
if (key == kKey::KeySpacebar && vr_active)
|
|
canvas->m_canvas->m_cam_rot = vr_rot;
|
|
redraw = true;
|
|
keys[(int)key] = true;
|
|
KeyEvent e;
|
|
e.m_type = kEventType::KeyDown;
|
|
e.m_key = key;
|
|
kEventResult ret = kEventResult::Available;
|
|
if (auto* main = layout[main_id])
|
|
{
|
|
ret = main->on_event(&e);
|
|
main->update();
|
|
}
|
|
return ret == kEventResult::Consumed;
|
|
}
|
|
bool App::key_up(kKey key)
|
|
{
|
|
redraw = true;
|
|
keys[(int)key] = false;
|
|
KeyEvent e;
|
|
e.m_type = kEventType::KeyUp;
|
|
e.m_key = key;
|
|
kEventResult ret = kEventResult::Available;
|
|
if (auto* main = layout[main_id])
|
|
{
|
|
ret = main->on_event(&e);
|
|
main->update();
|
|
}
|
|
return ret == kEventResult::Consumed;
|
|
}
|
|
bool App::key_char(char key)
|
|
{
|
|
redraw = true;
|
|
KeyEvent e;
|
|
e.m_type = kEventType::KeyChar;
|
|
e.m_char = key;
|
|
kEventResult ret = kEventResult::Available;
|
|
if (auto* main = layout[main_id])
|
|
{
|
|
ret = main->on_event(&e);
|
|
main->update();
|
|
}
|
|
return ret == kEventResult::Consumed;
|
|
}
|
|
|
|
void App::toggle_ui()
|
|
{
|
|
auto m = layout[main_id]->m_children[1];
|
|
ui_visible = !ui_visible;
|
|
for (int i = 1; i < m->m_children.size(); i++)
|
|
m->m_children[i]->m_display = ui_visible;
|
|
}
|
|
|
|
void App::set_stylus()
|
|
{
|
|
has_stylus = true;
|
|
if (canvas)
|
|
canvas->m_canvas->m_touch_lock = true;
|
|
}
|