1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
|
#include "markdown_helper.h"
#include "core/style.h"
#include "logger.h"
#include "imgui/imgui_image.h"
#include "resources.h"
#include "common/image/image.h"
#include "common/image/io.h"
#include <filesystem>
#if defined(_WIN32)
#include <windows.h>
#elif defined(__ANDROID__)
#include <android_native_app_glue.h>
extern struct android_app *g_App;
#endif
namespace widgets
{
void MarkdownHelper::link_callback(ImGui::MarkdownLinkCallbackData data_)
{
std::string url(data_.link, data_.linkLength);
if (!data_.isImage)
{
logger->info("Opening URL " + url);
#if defined(_WIN32)
ShellExecuteA(0, 0, url.c_str(), 0, 0, SW_SHOW);
#elif defined(__APPLE__)
system(std::string("open " + url).c_str());
#elif defined(__ANDROID__)
JavaVM *java_vm = g_App->activity->vm;
JNIEnv *java_env = NULL;
jint jni_return = java_vm->GetEnv((void **)&java_env, JNI_VERSION_1_6);
if (jni_return == JNI_ERR)
throw std::runtime_error("Could not get JNI environement");
jni_return = java_vm->AttachCurrentThread(&java_env, NULL);
if (jni_return != JNI_OK)
throw std::runtime_error("Could not attach to thread");
jclass native_activity_clazz = java_env->GetObjectClass(g_App->activity->clazz);
if (native_activity_clazz == NULL)
throw std::runtime_error("Could not get MainActivity class");
jmethodID method_id = java_env->GetMethodID(native_activity_clazz, "openURL", "(Ljava/lang/String;)V");
if (method_id == NULL)
throw std::runtime_error("Could not get methode ID");
jstring jurl = java_env->NewStringUTF(url.c_str());
java_env->CallVoidMethod(g_App->activity->clazz, method_id, jurl);
jni_return = java_vm->DetachCurrentThread();
if (jni_return != JNI_OK)
throw std::runtime_error("Could not detach from thread");
#else
if (system(std::string("xdg-open " + url).c_str()) != 0)
logger->error("Error opening URL!");
#endif
}
}
ImGui::MarkdownImageData MarkdownHelper::image_callback(ImGui::MarkdownLinkCallbackData data_)
{
MarkdownHelper *tthis = (MarkdownHelper *)data_.userData;
std::string image_path(data_.link, data_.linkLength);
ImGui::MarkdownImageData imageData;
if (tthis->texture_buffer.count(image_path))
{
imageData = tthis->texture_buffer[image_path];
}
else
{
imageData.isValid = false;
if (std::filesystem::exists(resources::getResourcePath(image_path)))
{
logger->trace("Loading image for markdown : " + image_path);
image::Image img;
image::load_img(img, resources::getResourcePath(image_path));
unsigned int text_id = makeImageTexture();
uint32_t *output_buffer = new uint32_t[img.width() * img.height()];
image::image_to_rgba(img, output_buffer);
updateImageTexture(text_id, output_buffer, img.width(), img.height());
delete[] output_buffer;
imageData.isValid = true;
imageData.useLinkCallback = false;
imageData.user_texture_id = (ImTextureID)(intptr_t)text_id;
imageData.size = ImVec2(img.width(), img.height());
}
tthis->texture_buffer.emplace(image_path, imageData);
}
// For image resize when available size.x > image width, add
ImVec2 const contentSize = ImGui::GetContentRegionAvail();
if (imageData.size.x > contentSize.x)
{
float const ratio = imageData.size.y / imageData.size.x;
imageData.size.x = contentSize.x;
imageData.size.y = contentSize.x * ratio;
}
return imageData;
}
MarkdownHelper::MarkdownHelper()
{
mdConfig.linkCallback = link_callback;
mdConfig.imageCallback = image_callback;
}
void MarkdownHelper::render()
{
mdConfig.headingFormats[0] = {style::bigFont, true};
mdConfig.headingFormats[1] = {style::bigFont, true};
mdConfig.headingFormats[2] = {style::baseFont, true};
mdConfig.userData = (void *)this;
ImGui::Markdown(markdown_.c_str(), markdown_.length(), mdConfig);
}
void MarkdownHelper::set_md(std::string md)
{
markdown_ = md;
texture_buffer.clear();
}
}
|