├── .clang-format ├── .gitignore ├── .gitmodules ├── CMakeLists.txt ├── LICENSE ├── Readme.md ├── src ├── .gitignore ├── CMakeLists.txt ├── HyperlinkHelper.cpp ├── HyperlinkHelper.h ├── ImGuiExt.cpp ├── ImGuiExt.h ├── ImplotDemo.main.cpp ├── JsClipboardTricks.cpp ├── JsClipboardTricks.h ├── LibrarySources.cpp ├── LibrarySources.h ├── MarkdownHelper.cpp ├── MarkdownHelper.h └── populate_assets.sh └── tools ├── deploy_implot.sh └── emscripten_build.sh /.clang-format: -------------------------------------------------------------------------------- 1 | # Generated from CLion C/C++ Code Style settings 2 | BasedOnStyle: LLVM 3 | AccessModifierOffset: -4 4 | AlignAfterOpenBracket: Align 5 | AlignConsecutiveAssignments: false 6 | AlignOperands: true 7 | AllowAllArgumentsOnNextLine: false 8 | AllowAllConstructorInitializersOnNextLine: false 9 | AllowAllParametersOfDeclarationOnNextLine: false 10 | AllowShortBlocksOnASingleLine: Always 11 | AllowShortCaseLabelsOnASingleLine: false 12 | AllowShortFunctionsOnASingleLine: All 13 | AllowShortIfStatementsOnASingleLine: Always 14 | AllowShortLambdasOnASingleLine: All 15 | AllowShortLoopsOnASingleLine: true 16 | AlwaysBreakAfterReturnType: None 17 | AlwaysBreakTemplateDeclarations: Yes 18 | BreakBeforeBraces: Custom 19 | BraceWrapping: 20 | AfterCaseLabel: false 21 | AfterClass: false 22 | AfterControlStatement: Never 23 | AfterEnum: false 24 | AfterFunction: false 25 | AfterNamespace: false 26 | AfterUnion: false 27 | BeforeCatch: false 28 | BeforeElse: false 29 | IndentBraces: false 30 | SplitEmptyFunction: false 31 | SplitEmptyRecord: true 32 | BreakBeforeBinaryOperators: None 33 | BreakBeforeTernaryOperators: true 34 | BreakConstructorInitializers: BeforeColon 35 | BreakInheritanceList: BeforeColon 36 | ColumnLimit: 0 37 | CompactNamespaces: false 38 | ContinuationIndentWidth: 4 39 | IndentCaseLabels: true 40 | IndentPPDirectives: None 41 | IndentWidth: 4 42 | KeepEmptyLinesAtTheStartOfBlocks: true 43 | MaxEmptyLinesToKeep: 2 44 | NamespaceIndentation: All 45 | ObjCSpaceAfterProperty: false 46 | ObjCSpaceBeforeProtocolList: true 47 | PointerAlignment: Right 48 | ReflowComments: false 49 | SpaceAfterCStyleCast: true 50 | SpaceAfterLogicalNot: false 51 | SpaceAfterTemplateKeyword: false 52 | SpaceBeforeAssignmentOperators: true 53 | SpaceBeforeCpp11BracedList: false 54 | SpaceBeforeCtorInitializerColon: true 55 | SpaceBeforeInheritanceColon: true 56 | SpaceBeforeParens: ControlStatements 57 | SpaceBeforeRangeBasedForLoopColon: true 58 | SpaceInEmptyParentheses: false 59 | SpacesBeforeTrailingComments: 0 60 | SpacesInAngles: false 61 | SpacesInCStyleCastParentheses: false 62 | SpacesInContainerLiterals: false 63 | SpacesInParentheses: false 64 | SpacesInSquareBrackets: false 65 | TabWidth: 4 66 | UseTab: Never 67 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | build_*/ 3 | cmake-build*/ 4 | .idea/ 5 | external/imgui/ 6 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "external/hello_imgui"] 2 | path = external/hello_imgui 3 | url = https://github.com/pthom/hello_imgui.git 4 | [submodule "external/implot"] 5 | path = external/implot 6 | url = https://github.com/epezent/implot.git 7 | [submodule "external/ImGuiColorTextEdit"] 8 | path = external/ImGuiColorTextEdit 9 | url = https://github.com/pthom/ImGuiColorTextEdit.git 10 | [submodule "external/FunctionalPlus"] 11 | path = external/FunctionalPlus 12 | url = https://github.com/Dobiasd/FunctionalPlus.git 13 | [submodule "external/imgui_markdown"] 14 | path = external/imgui_markdown 15 | url = https://github.com/juliettef/imgui_markdown.git 16 | [submodule "external/implot3d"] 17 | path = external/implot3d 18 | url = https://github.com/brenocq/implot3d.git 19 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | project(implot_demo LANGUAGES C CXX) 3 | set(CMAKE_CXX_STANDARD 17) 4 | 5 | # Force ImDrawIdx=unsigned int (performance option for ImPlot) 6 | add_compile_definitions("ImDrawIdx=unsigned int") 7 | 8 | # add hello_imgui + options 9 | set(HELLOIMGUI_USE_SDL2 ON CACHE BOOL "" FORCE) 10 | set(HELLOIMGUI_HAS_OPENGL3 ON CACHE BOOL "" FORCE) 11 | add_subdirectory(external/hello_imgui) 12 | 13 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${HELLOIMGUI_BASEPATH}/hello_imgui_cmake) 14 | if (EMSCRIPTEN) 15 | include(${HELLOIMGUI_BASEPATH}/hello_imgui_cmake/emscripten/hello_imgui_emscripten_global_options.cmake) 16 | endif() 17 | add_subdirectory(src) 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2019-2020 Pascal Thomet 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # implot demo 2 | 3 | Source for an online emscripten demo of [implot](https://github.com/epezent/implot) 4 | 5 | [Online demo here](https://traineq.org/implot_demo/src/implot_demo.html) 6 | 7 | ## Build instructions 8 | 9 | First, init the submodules: 10 | ```` 11 | git submodule update --init --recursive 12 | ```` 13 | 14 | ### Build instructions for emscripten 15 | 16 | Install emscripten if not present 17 | 18 | ```` 19 | ./external/hello_imgui/tools/emscripten/install_emscripten.sh 20 | ```` 21 | 22 | Build for emscripten using [tools/emscripten_build.sh](tools/emscripten_build.sh) 23 | ```` 24 | ./tools/emscripten_build.sh 25 | ```` 26 | 27 | Launch a web server 28 | ```` 29 | python3 -m http.server 30 | ```` 31 | 32 | Then, browse to http://localhost:8000/build_emscripten/src/implot_demo.html 33 | 34 | ### Build instructions on desktop (linux, MacOS, Windows) 35 | 36 | Install third parties via vcpkg (SDL) 37 | ```` 38 | python external/hello_imgui/tools/vcpkg_install_third_parties.py 39 | ```` 40 | 41 | Run cmake, using vcpkg toolchain 42 | ```` 43 | mkdir build 44 | cd build 45 | cmake .. -DCMAKE_TOOLCHAIN_FILE=../external/hello_imgui/vcpkg/scripts/buildsystems/vcpkg.cmake 46 | ```` 47 | 48 | Build and run 49 | ```` 50 | make -j 4 51 | ./src/implot_demo 52 | ```` 53 | 54 | 55 | ### Note 56 | This demo is based on [Hello ImGui](https://github.com/pthom/hello_imgui). 57 | -------------------------------------------------------------------------------- /src/.gitignore: -------------------------------------------------------------------------------- 1 | assets/ 2 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(HELLOIMGUI_MACOS_NO_BUNDLE ON CACHE BOOL "" FORCE) 2 | include(hello_imgui_add_app) 3 | 4 | execute_process(COMMAND bash -c ${CMAKE_CURRENT_LIST_DIR}/populate_assets.sh) 5 | 6 | set(implot_dir ${CMAKE_CURRENT_LIST_DIR}/../external/implot) 7 | set(implot3d_dir ${CMAKE_CURRENT_LIST_DIR}/../external/implot3d) 8 | set(textedit_dir ${CMAKE_CURRENT_LIST_DIR}/../external/ImGuiColorTextEdit) 9 | set(fplus_dir ${CMAKE_CURRENT_LIST_DIR}/../external/FunctionalPlus/include) 10 | set(imgui_markdown_dir ${CMAKE_CURRENT_LIST_DIR}/../external/imgui_markdown) 11 | 12 | hello_imgui_add_app(implot_demo 13 | ImplotDemo.main.cpp 14 | LibrarySources.cpp 15 | LibrarySources.h 16 | ImGuiExt.cpp 17 | ImGuiExt.h 18 | MarkdownHelper.cpp 19 | MarkdownHelper.h 20 | HyperlinkHelper.cpp 21 | HyperlinkHelper.h 22 | JsClipboardTricks.cpp 23 | JsClipboardTricks.h 24 | ${textedit_dir}/TextEditor.h 25 | ${textedit_dir}/TextEditor.cpp 26 | # 27 | ${implot_dir}/implot.h 28 | ${implot_dir}/implot_internal.h 29 | ${implot_dir}/implot.cpp 30 | ${implot_dir}/implot_demo.cpp 31 | ${implot_dir}/implot_items.cpp 32 | # 33 | ${implot3d_dir}/implot3d.h 34 | ${implot3d_dir}/implot3d_internal.h 35 | ${implot3d_dir}/implot3d.cpp 36 | ${implot3d_dir}/implot3d_demo.cpp 37 | ${implot3d_dir}/implot3d_items.cpp 38 | ${implot3d_dir}/implot3d_meshes.cpp 39 | ) 40 | 41 | target_include_directories(implot_demo PRIVATE 42 | ${implot_dir} ${implot3d_dir} ${textedit_dir} ${fplus_dir} ${imgui_markdown_dir} 43 | ) 44 | -------------------------------------------------------------------------------- /src/HyperlinkHelper.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #if defined(__EMSCRIPTEN__) 4 | #include 5 | #elif defined(_WIN32) 6 | #include 7 | #include 8 | #elif defined(__APPLE__) 9 | #include 10 | #include 11 | #endif 12 | 13 | #include "HyperlinkHelper.h" 14 | 15 | 16 | namespace HyperlinkHelper 17 | { 18 | void OpenUrl(const std::string &url) 19 | { 20 | bool isAbsoluteUrl = fplus::is_prefix_of(std::string("http"), url); 21 | if (!isAbsoluteUrl) 22 | return; 23 | #if defined(__EMSCRIPTEN__) 24 | std::string js_command = "window.open(\"" + url + "\");"; 25 | emscripten_run_script(js_command.c_str()); 26 | #elif defined(_WIN32) 27 | ShellExecuteA( NULL, "open", url.c_str(), NULL, NULL, SW_SHOWNORMAL ); 28 | #elif defined(TARGET_OS_MAC) 29 | std::string cmd = std::string("open ") + url.c_str(); 30 | system(cmd.c_str()); 31 | #endif 32 | 33 | } 34 | 35 | } -------------------------------------------------------------------------------- /src/HyperlinkHelper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | namespace HyperlinkHelper 4 | { 5 | void OpenUrl(const std::string &url); 6 | } 7 | -------------------------------------------------------------------------------- /src/ImGuiExt.cpp: -------------------------------------------------------------------------------- 1 | #include "ImGuiExt.h" 2 | #include "imgui.h" 3 | #include "hello_imgui/hello_imgui.h" 4 | #include "hello_imgui/icons_font_awesome_4.h" 5 | #include "HyperlinkHelper.h" 6 | 7 | namespace ImGuiExt 8 | { 9 | void Hyperlink(const std::string &url) 10 | { 11 | std::string linkLabel = std::string(ICON_FA_LINK) + " ##" + url; 12 | if (ImGui::Button(linkLabel.c_str())) 13 | HyperlinkHelper::OpenUrl(url); 14 | ImGui::SameLine(); 15 | auto blue = ImVec4(0.3f, 0.5f, 1.f, 1.f); 16 | ImGui::TextColored(blue, "%s", url.c_str()); 17 | } 18 | 19 | void SameLine_IfPossible(float minRightMargin) 20 | { 21 | auto lastXPos = ImGui::GetItemRectMax().x; 22 | //ImGui::Pos 23 | auto windowWidth = ImGui::GetWindowSize().x; 24 | if (lastXPos < windowWidth - minRightMargin ) 25 | ImGui::SameLine(); 26 | } 27 | } -------------------------------------------------------------------------------- /src/ImGuiExt.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace ImGuiExt 5 | { 6 | void Hyperlink(const std::string &url); 7 | void SameLine_IfPossible(float minRightMargin = 60.f); 8 | } 9 | -------------------------------------------------------------------------------- /src/ImplotDemo.main.cpp: -------------------------------------------------------------------------------- 1 | #include "hello_imgui/hello_imgui.h" 2 | #include "hello_imgui/icons_font_awesome_4.h" 3 | #include "implot.h" 4 | #include "implot3d.h" 5 | #include "ImGuiExt.h" 6 | #include "TextEditor.h" 7 | #include "LibrarySources.h" 8 | #include "MarkdownHelper.h" 9 | #include "JsClipboardTricks.h" 10 | #include 11 | 12 | #include "HyperlinkHelper.h" 13 | 14 | 15 | void guiCodeRegions(const LinesWithNotes &linesWithNotes, TextEditor &editor) 16 | { 17 | for (const auto & lineWithNote : linesWithNotes) { 18 | if (ImGui::Button(lineWithNote.second.c_str())) 19 | editor.SetCursorPosition({lineWithNote.first, 0}, 3); 20 | ImGuiExt::SameLine_IfPossible(); 21 | } 22 | ImGui::NewLine(); 23 | } 24 | 25 | 26 | void setEditorAnnotatedSource(const AnnotatedSourceCode& annotatedSourceCode, TextEditor& editor) 27 | { 28 | editor.SetText(annotatedSourceCode.sourceCode); 29 | std::unordered_set lineNumbers; 30 | for (auto kv : annotatedSourceCode.linesWithNotes) 31 | lineNumbers.insert(kv.first); 32 | editor.SetBreakpoints(lineNumbers); 33 | } 34 | 35 | #ifdef __EMSCRIPTEN__ 36 | void handleJsClipboardShortcuts(TextEditor& textEditor) 37 | { 38 | ImGuiIO& io = ImGui::GetIO(); 39 | auto shift = io.KeyShift; 40 | auto ctrl = io.ConfigMacOSXBehaviors ? io.KeySuper : io.KeyCtrl; 41 | auto alt = io.ConfigMacOSXBehaviors ? io.KeyCtrl : io.KeyAlt; 42 | 43 | bool shallFillBrowserClipboard = false; 44 | if (ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGuiKey_Insert)) 45 | shallFillBrowserClipboard = true; 46 | else if (ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGuiKey_C)) 47 | shallFillBrowserClipboard = true; 48 | else if (ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGuiKey_X)) 49 | shallFillBrowserClipboard = true; 50 | else if (!ctrl && shift && !alt && ImGui::IsKeyPressed(ImGuiKey_Delete)) 51 | shallFillBrowserClipboard = true; 52 | 53 | #ifdef IMGUIMANUAL_CLIPBOARD_EXPORT_TO_BROWSER 54 | if (shallFillBrowserClipboard) 55 | { 56 | std::cout << "Should copy!!!" << "\n"; 57 | JsClipboard_SetClipboardText(textEditor.GetSelectedText().c_str()); 58 | } 59 | #endif 60 | } 61 | #endif // #ifdef __EMSCRIPTEN__ 62 | 63 | 64 | 65 | struct TextEditorAnnotatedSource 66 | { 67 | AnnotatedSourceCode annotatedSource; 68 | TextEditor editor; 69 | 70 | TextEditorAnnotatedSource(const char *source_path) 71 | { 72 | annotatedSource = ReadSelectedLibrarySource(source_path); 73 | 74 | editor.SetPalette(TextEditor::GetLightPalette()); 75 | 76 | bool isPython = fplus::is_suffix_of(".py", source_path); 77 | auto lang = 78 | isPython ? TextEditor::LanguageDefinition::Lua() :TextEditor::LanguageDefinition::CPlusPlus(); 79 | editor.SetLanguageDefinition(lang); 80 | setEditorAnnotatedSource(annotatedSource, editor); 81 | } 82 | 83 | void Gui() 84 | { 85 | guiCodeRegions(annotatedSource.linesWithNotes, editor); 86 | 87 | #ifdef __EMSCRIPTEN__ 88 | if (ImGui::SmallButton("Copy " ICON_FA_COPY)) 89 | JsClipboard_SetClipboardText(editor.GetSelectedText().c_str()); 90 | #endif 91 | 92 | editor.Render(annotatedSource.sourcePath.c_str()); 93 | 94 | #ifdef __EMSCRIPTEN__ 95 | handleJsClipboardShortcuts(editor); 96 | #endif 97 | } 98 | }; 99 | 100 | 101 | 102 | int main(int, char **) 103 | { 104 | TextEditorAnnotatedSource implotEditorAnnotatedSource("implot/implot_demo.cpp"); 105 | TextEditorAnnotatedSource implot3dEditorAnnotatedSource("implot3d/implot3d_demo.cpp"); 106 | 107 | HelloImGui::RunnerParams runnerParams; 108 | 109 | // App window params 110 | runnerParams.appWindowParams.windowTitle = "implot demo - implot3d demo"; 111 | runnerParams.appWindowParams.windowGeometry.size = { 1200, 800}; 112 | 113 | // ImGui window params 114 | runnerParams.imGuiWindowParams.defaultImGuiWindowType = 115 | HelloImGui::DefaultImGuiWindowType::ProvideFullScreenDockSpace; 116 | runnerParams.imGuiWindowParams.showMenuBar = false; 117 | runnerParams.imGuiWindowParams.showStatusBar = true; 118 | 119 | // Split the screen in two parts 120 | runnerParams.dockingParams.dockingSplits = { 121 | //{ "MainDockSpace", "CodeSpace", ImGuiDir_Up, 0.5 }, 122 | }; 123 | 124 | // Dockable windows definitions 125 | HelloImGui::DockableWindow implotDock; 126 | { 127 | implotDock.label = "ImPlot Demo"; 128 | implotDock.dockSpaceName = "MainDockSpace"; 129 | implotDock.GuiFunction = [&implotDock] { 130 | if (implotDock.isVisible) 131 | ImPlot::ShowDemoWindow(nullptr); 132 | }; 133 | implotDock.callBeginEnd = false; 134 | }; 135 | 136 | HelloImGui::DockableWindow implot3dDock; 137 | { 138 | implot3dDock.label = "ImPlot3D Demo"; 139 | implot3dDock.dockSpaceName = "MainDockSpace"; 140 | implot3dDock.GuiFunction = [&implot3dDock] { 141 | if (implot3dDock.isVisible) 142 | ImPlot3D::ShowDemoWindow(nullptr); 143 | }; 144 | implot3dDock.callBeginEnd = false; 145 | }; 146 | 147 | 148 | HelloImGui::DockableWindow implotDemoCodeDock; 149 | { 150 | implotDemoCodeDock.label = "Implot Demo - Code"; 151 | implotDemoCodeDock.dockSpaceName = "MainDockSpace"; 152 | implotDemoCodeDock.GuiFunction = [&implotEditorAnnotatedSource] { 153 | ImGui::Text("View on GitHub:"); 154 | ImGui::SameLine(); 155 | if (ImGui::Button("C++ demo code")) 156 | HyperlinkHelper::OpenUrl("https://github.com/epezent/implot/blob/master/implot_demo.cpp"); 157 | ImGui::SameLine(); 158 | if (ImGui::Button("Python demo code")) 159 | HyperlinkHelper::OpenUrl("https://github.com/pthom/imgui_bundle/blob/main/bindings/imgui_bundle/demos_python/demos_implot/implot_demo.py"); 160 | 161 | implotEditorAnnotatedSource.Gui(); 162 | }; 163 | } 164 | 165 | HelloImGui::DockableWindow implot3dDemoCodeDock; 166 | { 167 | implot3dDemoCodeDock.label = "Implot3d Demo - Code"; 168 | implot3dDemoCodeDock.dockSpaceName = "MainDockSpace"; 169 | implot3dDemoCodeDock.GuiFunction = [&implot3dEditorAnnotatedSource] { 170 | ImGui::Text("View on GitHub:"); 171 | ImGui::SameLine(); 172 | if (ImGui::Button("C++ demo code")) 173 | HyperlinkHelper::OpenUrl("https://github.com/brenocq/implot3d/blob/main/implot3d_demo.cpp"); 174 | ImGui::SameLine(); 175 | if (ImGui::Button("Python demo code")) 176 | HyperlinkHelper::OpenUrl("https://github.com/pthom/imgui_bundle/blob/main/bindings/imgui_bundle/demos_python/demos_implot3d/implot3d_demo.py"); 177 | 178 | implot3dEditorAnnotatedSource.Gui(); 179 | }; 180 | } 181 | 182 | // Fonts 183 | runnerParams.callbacks.LoadAdditionalFonts = MarkdownHelper::LoadFonts; 184 | 185 | // Set app dockable windows 186 | runnerParams.dockingParams.dockableWindows = { 187 | implotDock, implot3dDock, implotDemoCodeDock, implot3dDemoCodeDock }; 188 | 189 | auto implotContext = ImPlot::CreateContext(); 190 | auto implot3dContext = ImPlot3D::CreateContext(); 191 | 192 | HelloImGui::Run(runnerParams); 193 | 194 | ImPlot::DestroyContext(implotContext); 195 | ImPlot3D::DestroyContext(implot3dContext); 196 | 197 | return 0; 198 | } 199 | -------------------------------------------------------------------------------- /src/JsClipboardTricks.cpp: -------------------------------------------------------------------------------- 1 | #include "imgui.h" 2 | #include "JsClipboardTricks.h" 3 | #ifdef __EMSCRIPTEN__ 4 | #include 5 | 6 | // The clipboard handling features take inspiration from sokol 7 | // https://github.com/floooh/sokol 8 | 9 | #ifdef __cplusplus 10 | extern "C" 11 | { 12 | #endif 13 | 14 | #ifdef IMGUIMANUAL_CLIPBOARD_IMPORT_FROM_BROWSER 15 | 16 | EM_JS(void, sapp_add_js_hook_clipboard, (void), { 17 | // See also https://whatwebcando.today/clipboard.html 18 | // for the new async api with user permissions dialog 19 | Module.sokol_paste = function(event) { 20 | // console.log("Got paste event "); 21 | var pasted_str = event.clipboardData.getData('text'); 22 | ccall('_sapp_emsc_onpaste', 'void', ['string'], [pasted_str]); 23 | }; 24 | // console.log("sapp_add_js_hook_clipboard 4"); 25 | window.addEventListener('paste', Module.sokol_paste); 26 | }); 27 | 28 | EM_JS(void, sapp_remove_js_hook_clipboard, (void), { 29 | window.removeEventListener('paste', Module.sokol_paste); 30 | }); 31 | 32 | void EMSCRIPTEN_KEEPALIVE _sapp_emsc_onpaste(const char *str) 33 | { 34 | // std::cout << "_sapp_emsc_onpaste " << str << std::endl; 35 | ImGui::SetClipboardText(str); 36 | } 37 | 38 | #endif // #ifdef IMGUIMANUAL_CLIPBOARD_IMPORT_FROM_BROWSER 39 | 40 | 41 | #ifdef IMGUIMANUAL_CLIPBOARD_EXPORT_TO_BROWSER 42 | 43 | EM_JS(void, sapp_js_write_clipboard, (const char* c_str), { 44 | var str = UTF8ToString(c_str); 45 | var ta = document.createElement('textarea'); 46 | ta.setAttribute('autocomplete', 'off'); 47 | ta.setAttribute('autocorrect', 'off'); 48 | ta.setAttribute('autocapitalize', 'off'); 49 | ta.setAttribute('spellcheck', 'false'); 50 | ta.style.left = -100 + 'px'; 51 | ta.style.top = -100 + 'px'; 52 | ta.style.height = 1; 53 | ta.style.width = 1; 54 | ta.value = str; 55 | document.body.appendChild(ta); 56 | ta.select(); 57 | document.execCommand('copy'); 58 | document.body.removeChild(ta); 59 | // console.log("Set clipboard to " + str); 60 | }); 61 | 62 | #endif // #ifdef IMGUIMANUAL_CLIPBOARD_EXPORT_TO_BROWSER 63 | 64 | #ifdef __cplusplus 65 | } 66 | #endif 67 | 68 | #ifdef IMGUIMANUAL_CLIPBOARD_EXPORT_TO_BROWSER 69 | void JsClipboard_SetClipboardText(const char* str) 70 | { 71 | sapp_js_write_clipboard(str); 72 | } 73 | #endif 74 | 75 | #ifdef IMGUIMANUAL_CLIPBOARD_IMPORT_FROM_BROWSER 76 | void JsClipboard_AddJsHook() 77 | { 78 | sapp_add_js_hook_clipboard(); 79 | } 80 | #endif 81 | 82 | #endif // __EMSCRIPTEN__ 83 | -------------------------------------------------------------------------------- /src/JsClipboardTricks.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // The clipboard handling features take inspiration from sokol 4 | // https://github.com/floooh/sokol 5 | 6 | #ifdef __EMSCRIPTEN__ 7 | #define IMGUIMANUAL_CLIPBOARD_EXPORT_TO_BROWSER 8 | // #define IMGUIMANUAL_CLIPBOARD_IMPORT_FROM_BROWSER # This still needs work... 9 | #endif 10 | 11 | 12 | #ifdef IMGUIMANUAL_CLIPBOARD_EXPORT_TO_BROWSER 13 | void JsClipboard_SetClipboardText(const char* str); 14 | #endif 15 | 16 | #ifdef IMGUIMANUAL_CLIPBOARD_IMPORT_FROM_BROWSER 17 | void JsClipboard_AddJsHook(); 18 | #endif 19 | -------------------------------------------------------------------------------- /src/LibrarySources.cpp: -------------------------------------------------------------------------------- 1 | #include "hello_imgui/hello_imgui_assets.h" 2 | #include 3 | #include "LibrarySources.h" 4 | 5 | 6 | 7 | LinesWithNotes findDemoRegions(const std::string &sourceCode) 8 | { 9 | LinesWithNotes r; 10 | 11 | // for example, a demo line resemble to: void Demo_DragRects() { 12 | static std::string demoToken = "void Demo"; 13 | 14 | auto extractDemoName = [](const std::string &codeLine) { 15 | std::string r = codeLine; 16 | r= fplus::replace_tokens("void ShowDemo_", "", codeLine); 17 | r = fplus::replace_tokens("()", "", r); 18 | r = fplus::replace_tokens("{", "", r); 19 | r = fplus::replace_tokens(demoToken + "_", "", r); 20 | r = fplus::replace_tokens(demoToken, "", r); 21 | r = fplus::trim_whitespace(r); 22 | return r; 23 | }; 24 | 25 | auto lines = fplus::split('\n', true, sourceCode); 26 | for (size_t line_number = 0; line_number < lines.size(); line_number++) 27 | { 28 | const std::string& line = lines[line_number]; 29 | 30 | bool lineContainsDemoToken = line.find(demoToken) != std::string::npos; 31 | bool lineDefinesZeroParamFunction = (line.find("()") != std::string::npos); 32 | 33 | if (lineContainsDemoToken && lineDefinesZeroParamFunction) 34 | r[(int)(line_number + 1)] = extractDemoName(line); 35 | } 36 | return r; 37 | } 38 | 39 | AnnotatedSourceCode ReadSelectedLibrarySource(const std::string sourcePath) 40 | { 41 | std::string assetPath = std::string("code/") + sourcePath; 42 | auto assetData = HelloImGui::LoadAssetFileData(assetPath.c_str()); 43 | assert(assetData.data != nullptr); 44 | 45 | AnnotatedSourceCode r; 46 | r.sourcePath = sourcePath; 47 | r.sourceCode = std::string((const char *) assetData.data); 48 | r.linesWithNotes = findDemoRegions(r.sourceCode); 49 | HelloImGui::FreeAssetFileData(&assetData); 50 | return r; 51 | } 52 | -------------------------------------------------------------------------------- /src/LibrarySources.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | 7 | 8 | using LinesWithNotes = std::map; 9 | 10 | struct AnnotatedSourceCode 11 | { 12 | std::string sourcePath; 13 | std::string sourceCode; 14 | LinesWithNotes linesWithNotes; 15 | }; 16 | 17 | 18 | // (private) LinesWithNotes findCollapsingHeaderRegions(const std::string &sourceCode); 19 | AnnotatedSourceCode ReadSelectedLibrarySource(const std::string sourcePath); 20 | -------------------------------------------------------------------------------- /src/MarkdownHelper.cpp: -------------------------------------------------------------------------------- 1 | #include "hello_imgui/hello_imgui.h" 2 | #include "hello_imgui/icons_font_awesome_4.h" 3 | 4 | #include "imgui_markdown.h" // https://github.com/juliettef/imgui_markdown 5 | #include "MarkdownHelper.h" 6 | #include "HyperlinkHelper.h" 7 | #include 8 | 9 | namespace MarkdownHelper 10 | { 11 | 12 | ImFont *fontH1, *fontH2, *fontH3; 13 | 14 | void LoadFonts() 15 | { 16 | HelloImGui::ImGuiDefaultSettings::LoadDefaultFont_WithFontAwesomeIcons(); 17 | std::string fontFilename = "fonts/DroidSans.ttf"; 18 | float fontSizeStep = 4.; 19 | fontH3 = HelloImGui::LoadFontTTF_WithFontAwesomeIcons(fontFilename, 14.f + fontSizeStep * 1.f); 20 | fontH2 = HelloImGui::LoadFontTTF_WithFontAwesomeIcons(fontFilename, 14.f + fontSizeStep * 2.f); 21 | fontH1 = HelloImGui::LoadFontTTF_WithFontAwesomeIcons(fontFilename, 14.f + fontSizeStep * 3.f); 22 | } 23 | 24 | 25 | void LinkCallback(ImGui::MarkdownLinkCallbackData data_) 26 | { 27 | (void) data_; 28 | std::string url(data_.link, data_.linkLength); 29 | if (!data_.isImage) 30 | HyperlinkHelper::OpenUrl(url); 31 | } 32 | 33 | inline ImGui::MarkdownImageData ImageCallback(ImGui::MarkdownLinkCallbackData data_) 34 | { 35 | // In your application you would load an image based on data_ input. Here we just use the imgui font texture. 36 | ImTextureID image = ImGui::GetIO().Fonts->TexID; 37 | ImGui::MarkdownImageData imageData{true, false, image, ImVec2(40.0f, 20.0f)}; 38 | return imageData; 39 | } 40 | 41 | // You can make your own Markdown function with your prefered string container and markdown config. 42 | ImGui::MarkdownConfig factorMarkdownConfig() 43 | { 44 | return { 45 | LinkCallback, 46 | ImageCallback, 47 | ICON_FA_LINK, 48 | { 49 | {fontH1, true}, 50 | {fontH2, true}, 51 | {fontH3, false} 52 | } 53 | }; 54 | } 55 | 56 | 57 | void Markdown(const std::string &markdown_) 58 | { 59 | static ImGui::MarkdownConfig markdownConfig = factorMarkdownConfig(); 60 | ImGui::Markdown(markdown_.c_str(), markdown_.length(), markdownConfig); 61 | } 62 | 63 | 64 | } // namespace MarkdownHelper 65 | -------------------------------------------------------------------------------- /src/MarkdownHelper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace MarkdownHelper 4 | { 5 | void LoadFonts(); 6 | void Markdown(const std::string &markdown_); 7 | } -------------------------------------------------------------------------------- /src/populate_assets.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | echo "Populating assets" 4 | 5 | THIS_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" 6 | cd $THIS_DIR/../external || exit 1 7 | SRC_DIR=$THIS_DIR 8 | EXTERNAL_DIR=$THIS_DIR/../external 9 | 10 | echo "THIS_DIR=$THIS_DIR" 11 | #exit 0 12 | 13 | cd $THIS_DIR 14 | mkdir -p assets/code/implot 15 | cp -f $EXTERNAL_DIR/implot/implot_demo.cpp assets/code/implot/implot_demo.cpp 16 | 17 | mkdir -p assets/code/implot3d 18 | cp -f $EXTERNAL_DIR/implot3d/implot3d_demo.cpp assets/code/implot3d/implot3d_demo.cpp 19 | 20 | -------------------------------------------------------------------------------- /tools/deploy_implot.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | THIS_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" 4 | REPO_DIR=$THIS_DIR/.. 5 | cd $REPO_DIR 6 | 7 | ./tools/emscripten_build.sh 8 | cd build_emscripten 9 | rsync -vaz src pascal@traineq.org:HTML/implot_demo 10 | -------------------------------------------------------------------------------- /tools/emscripten_build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | THIS_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" 4 | REPO_DIR=$THIS_DIR/.. 5 | cd $REPO_DIR 6 | 7 | if [ ! -d build_emscripten ]; then 8 | mkdir build_emscripten 9 | fi 10 | 11 | cd build_emscripten 12 | source ~/emsdk/emsdk_env.sh 13 | emcmake cmake .. -DCMAKE_BUILD_TYPE=Release 14 | make -j 4 15 | --------------------------------------------------------------------------------