This commit is contained in:
jeanlemotan
2024-07-03 13:14:02 +02:00
commit 1b674c3e64
55 changed files with 96031 additions and 0 deletions
+55
View File
@@ -0,0 +1,55 @@
#pragma once
#include <tl/ptr.h>
#include <tl/flag_set.h>
#include <fs/IFilesystem.h>
#include <fs/AbsPath.h>
#include "IUI/ImGui/imgui.h"
#include "Kit/EngineManager.h"
namespace kit
{
namespace icons
{
enum class Placement : uint8_t
{
HCenter = 1 << 0,
VCenter = 1 << 1,
Left = 1 << 2,
Right = 1 << 3,
Top = 1 << 4,
Bottom = 1 << 5,
Center = HCenter | VCenter,
TopLeft = Left | Top,
BottomRight = Right | Bottom
};
using PlacementSet = tl::flag_set<Placement>;
void init(tl::lent_ref<kit::EngineManager> engineManager, tl::lent_ref<fs::IFilesystem> filesystem, fs::AbsPath folderPath);
void shutdown();
struct Icon
{
tl::lent_ptr<filament::Texture> texture;
math::vec2f uv0;
math::vec2f uv1;
};
struct FontIcon
{
const char* icon = nullptr;
explicit operator bool() const
{
return icon != nullptr;
}
};
const Icon& getIcon(const tl::string& name);
const Icon& getIcon(const char* name);
}
}
+145
View File
@@ -0,0 +1,145 @@
//-----------------------------------------------------------------------------
// DEAR IMGUI COMPILE-TIME OPTIONS
// Runtime options (clipboard callbacks, enabling various features, etc.) can generally be set via the ImGuiIO structure.
// You can use ImGui::SetAllocatorFunctions() before calling ImGui::CreateContext() to rewire memory allocation functions.
//-----------------------------------------------------------------------------
// A) You may edit imconfig.h (and not overwrite it when updating Dear ImGui, or maintain a patch/rebased branch with your modifications to it)
// B) or '#define IMGUI_USER_CONFIG "my_imgui_config.h"' in your project and then add directives in your own file without touching this template.
//-----------------------------------------------------------------------------
// You need to make sure that configuration settings are defined consistently _everywhere_ Dear ImGui is used, which include the imgui*.cpp
// files but also _any_ of your code that uses Dear ImGui. This is because some compile-time options have an affect on data structures.
// Defining those options in imconfig.h will ensure every compilation unit gets to see the same data structure layouts.
// Call IMGUI_CHECKVERSION() from your .cpp file to verify that the data structures your files are using are matching the ones imgui.cpp is using.
//-----------------------------------------------------------------------------
#pragma once
//---- Define assertion handler. Defaults to calling assert().
// If your macro uses multiple statements, make sure is enclosed in a 'do { .. } while (0)' block so it can be used as a single statement.
//#define IM_ASSERT(_EXPR) MyAssert(_EXPR)
//#define IM_ASSERT(_EXPR) ((void)(_EXPR)) // Disable asserts
//---- Define attributes of all API symbols declarations, e.g. for DLL under Windows
// Using Dear ImGui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility.
// DLL users: heaps and globals are not shared across DLL boundaries! You will need to call SetCurrentContext() + SetAllocatorFunctions()
// for each static/DLL boundary you are calling from. Read "Context and Memory Allocators" section of imgui.cpp for more details.
//#define IMGUI_API __declspec( dllexport )
//#define IMGUI_API __declspec( dllimport )
//---- Don't define obsolete functions/enums/behaviors. Consider enabling from time to time after updating to clean your code of obsolete function/names.
//#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS
//#define IMGUI_DISABLE_OBSOLETE_KEYIO // 1.87+ disable legacy io.KeyMap[]+io.KeysDown[] in favor io.AddKeyEvent(). This is automatically done by IMGUI_DISABLE_OBSOLETE_FUNCTIONS.
//---- Disable all of Dear ImGui or don't implement standard windows/tools.
// It is very strongly recommended to NOT disable the demo windows and debug tool during development. They are extremely useful in day to day work. Please read comments in imgui_demo.cpp.
//#define IMGUI_DISABLE // Disable everything: all headers and source files will be empty.
//#define IMGUI_DISABLE_DEMO_WINDOWS // Disable demo windows: ShowDemoWindow()/ShowStyleEditor() will be empty.
//#define IMGUI_DISABLE_DEBUG_TOOLS // Disable metrics/debugger and other debug tools: ShowMetricsWindow(), ShowDebugLogWindow() and ShowIDStackToolWindow() will be empty.
//---- Don't implement some functions to reduce linkage requirements.
//#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc. (user32.lib/.a, kernel32.lib/.a)
//#define IMGUI_ENABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with Visual Studio] Implement default IME handler (require imm32.lib/.a, auto-link for Visual Studio, -limm32 on command-line for MinGW)
//#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with non-Visual Studio compilers] Don't implement default IME handler (won't require imm32.lib/.a)
//#define IMGUI_DISABLE_WIN32_FUNCTIONS // [Win32] Won't use and link with any Win32 function (clipboard, IME).
//#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS // [OSX] Implement default OSX clipboard handler (need to link with '-framework ApplicationServices', this is why this is not the default).
//#define IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself (e.g. if you don't want to link with vsnprintf)
//#define IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS // Don't implement ImFabs/ImSqrt/ImPow/ImFmod/ImCos/ImSin/ImAcos/ImAtan2 so you can implement them yourself.
//#define IMGUI_DISABLE_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle at all (replace them with dummies)
//#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle so you can implement them yourself if you don't want to link with fopen/fclose/fread/fwrite. This will also disable the LogToTTY() function.
//#define IMGUI_DISABLE_DEFAULT_ALLOCATORS // Don't implement default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions().
//#define IMGUI_DISABLE_SSE // Disable use of SSE intrinsics even if available
//---- Include imgui_user.h at the end of imgui.h as a convenience
// May be convenient for some users to only explicitly include vanilla imgui.h and have extra stuff included.
//#define IMGUI_INCLUDE_IMGUI_USER_H
//#define IMGUI_USER_H_FILENAME "my_folder/my_imgui_user.h"
//---- Pack colors to BGRA8 instead of RGBA8 (to avoid converting from one to another)
//#define IMGUI_USE_BGRA_PACKED_COLOR
//---- Use 32-bit for ImWchar (default is 16-bit) to support unicode planes 1-16. (e.g. point beyond 0xFFFF like emoticons, dingbats, symbols, shapes, ancient languages, etc...)
#define IMGUI_USE_WCHAR32
//---- Avoid multiple STB libraries implementations, or redefine path/filenames to prioritize another version
// By default the embedded implementations are declared static and not available outside of Dear ImGui sources files.
//#define IMGUI_STB_TRUETYPE_FILENAME "my_folder/stb_truetype.h"
//#define IMGUI_STB_RECT_PACK_FILENAME "my_folder/stb_rect_pack.h"
//#define IMGUI_STB_SPRINTF_FILENAME "my_folder/stb_sprintf.h" // only used if IMGUI_USE_STB_SPRINTF is defined.
//#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION
//#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION
//#define IMGUI_DISABLE_STB_SPRINTF_IMPLEMENTATION // only disabled if IMGUI_USE_STB_SPRINTF is defined.
//---- Use stb_sprintf.h for a faster implementation of vsnprintf instead of the one from libc (unless IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS is defined)
// Compatibility checks of arguments and formats done by clang and GCC will be disabled in order to support the extra formats provided by stb_sprintf.h.
//#define IMGUI_USE_STB_SPRINTF
//---- Use FreeType to build and rasterize the font atlas (instead of stb_truetype which is embedded by default in Dear ImGui)
// Requires FreeType headers to be available in the include path. Requires program to be compiled with 'misc/freetype/imgui_freetype.cpp' (in this repository) + the FreeType library (not provided).
// On Windows you may use vcpkg with 'vcpkg install freetype --triplet=x64-windows' + 'vcpkg integrate install'.
#define IMGUI_ENABLE_FREETYPE
//---- Use FreeType+lunasvg library to render OpenType SVG fonts (SVGinOT)
// Requires lunasvg headers to be available in the include path + program to be linked with the lunasvg library (not provided).
// Only works in combination with IMGUI_ENABLE_FREETYPE.
// (implementation is based on Freetype's rsvg-port.c which is licensed under CeCILL-C Free Software License Agreement)
//#define IMGUI_ENABLE_FREETYPE_LUNASVG
//---- Use stb_truetype to build and rasterize the font atlas (default)
// The only purpose of this define is if you want force compilation of the stb_truetype backend ALONG with the FreeType backend.
//#define IMGUI_ENABLE_STB_TRUETYPE
//---- Define constructor and implicit cast operators to convert back<>forth between your math types and ImVec2/ImVec4.
// This will be inlined as part of ImVec2 and ImVec4 class declarations.
/*
#define IM_VEC2_CLASS_EXTRA \
constexpr ImVec2(const MyVec2& f) : x(f.x), y(f.y) {} \
operator MyVec2() const { return MyVec2(x,y); }
#define IM_VEC4_CLASS_EXTRA \
constexpr ImVec4(const MyVec4& f) : x(f.x), y(f.y), z(f.z), w(f.w) {} \
operator MyVec4() const { return MyVec4(x,y,z,w); }
*/
//---- ...Or use Dear ImGui's own very basic math operators.
#define IMGUI_DEFINE_MATH_OPERATORS
//---- Use 32-bit vertex indices (default is 16-bit) is one way to allow large meshes with more than 64K vertices.
// Your renderer backend will need to support it (most example renderer backends support both 16/32-bit indices).
// Another way to allow large meshes while keeping 16-bit indices is to handle ImDrawCmd::VtxOffset in your renderer.
// Read about ImGuiBackendFlags_RendererHasVtxOffset for details.
#define ImDrawIdx unsigned int
//---- Override ImDrawCallback signature (will need to modify renderer backends accordingly)
//struct ImDrawList;
//struct ImDrawCmd;
//typedef void (*MyImDrawCallback)(const ImDrawList* draw_list, const ImDrawCmd* cmd, void* my_renderer_user_data);
//#define ImDrawCallback MyImDrawCallback
//---- Debug Tools: Macro to break in Debugger (we provide a default implementation of this in the codebase)
// (use 'Metrics->Tools->Item Picker' to pick widgets with the mouse and break into them for easy debugging.)
//#define IM_DEBUG_BREAK IM_ASSERT(0)
//#define IM_DEBUG_BREAK __debugbreak()
//---- Debug Tools: Enable slower asserts
//#define IMGUI_DEBUG_PARANOID
//---- Tip: You can add extra functions within the ImGui:: namespace from anywhere (e.g. your own sources/header files)
/*
namespace ImGui
{
void MyFunction(const char* name, MyMatrix44* mtx);
}
*/
//#define IMGUI_USER_CONFIG "VMath.h"
#include "VMath.h"
#define IM_VEC2_CLASS_EXTRA \
template<typename T> \
ImVec2(math::vec2<T> v) noexcept { x = v.x; y = v.y; } \
operator math::vec2f() const noexcept { return math::vec2f(x, y); }
#define IM_VEC4_CLASS_EXTRA \
template<typename T> \
ImVec4(math::vec4<T> v) noexcept { x = v.x; y = v.y; z = v.z; w = v.w; }\
operator math::vec4f() const noexcept { return math::vec4f(x, y, z, w); }
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+212
View File
@@ -0,0 +1,212 @@
#pragma once
/*
Color definitions in ImGui are a good starting point,
but do not cover all the intricacies of Spectrum's possible colors
in controls and widgets.
One big difference is that ImGui communicates widget activity
(hover, pressed) with their background, while spectrum uses a mix
of background and border, with border being the most common choice.
Because of this, we reference extra colors in spectrum from
imgui.cpp and imgui_widgets.cpp directly, and to make that work,
we need to have them defined at here at compile time.
*/
/// Pick one, or have one defined already.
#if !defined(SPECTRUM_USE_LIGHT_THEME) && !defined(SPECTRUM_USE_DARK_THEME)
//#define SPECTRUM_USE_LIGHT_THEME
#define SPECTRUM_USE_DARK_THEME
#endif
namespace ImGui {
namespace Spectrum {
// a list of changes introduced to change the look of the widgets.
// Collected here as const rather than being magic numbers spread
// around imgui.cpp and imgui_widgets.cpp.
const float CHECKBOX_BORDER_SIZE = 2.0f;
const float CHECKBOX_ROUNDING = 2.0f;
// Load SourceSansProRegular and sets it as a default font.
// You may want to call ImGui::GetIO().Fonts->Clear() before this
void LoadFont(float size = 16.0f);
// Sets the ImGui style to Spectrum
void StyleColorsSpectrum();
namespace { // Unnamed namespace, since we only use this here.
unsigned int Color(unsigned int c) {
// add alpha.
// also swap red and blue channel for some reason.
// todo: figure out why, and fix it.
const short a = 0xFF;
const short r = (c >> 16) & 0xFF;
const short g = (c >> 8) & 0xFF;
const short b = (c >> 0) & 0xFF;
return(a << 24)
| (r << 0)
| (g << 8)
| (b << 16);
}
}
// all colors are from http://spectrum.corp.adobe.com/color.html
inline unsigned int color_alpha(unsigned int alpha, unsigned int c) {
return ((alpha & 0xFF) << 24) | (c & 0x00FFFFFF);
}
namespace Static { // static colors
const unsigned int NONE = 0x00000000; // transparent
const unsigned int WHITE = Color(0xFFFFFF);
const unsigned int BLACK = Color(0x000000);
const unsigned int GRAY200 = Color(0xF4F4F4);
const unsigned int GRAY300 = Color(0xEAEAEA);
const unsigned int GRAY400 = Color(0xD3D3D3);
const unsigned int GRAY500 = Color(0xBCBCBC);
const unsigned int GRAY600 = Color(0x959595);
const unsigned int GRAY700 = Color(0x767676);
const unsigned int GRAY800 = Color(0x505050);
const unsigned int GRAY900 = Color(0x323232);
const unsigned int BLUE400 = Color(0x378EF0);
const unsigned int BLUE500 = Color(0x2680EB);
const unsigned int BLUE600 = Color(0x1473E6);
const unsigned int BLUE700 = Color(0x0D66D0);
const unsigned int RED400 = Color(0xEC5B62);
const unsigned int RED500 = Color(0xE34850);
const unsigned int RED600 = Color(0xD7373F);
const unsigned int RED700 = Color(0xC9252D);
const unsigned int ORANGE400 = Color(0xF29423);
const unsigned int ORANGE500 = Color(0xE68619);
const unsigned int ORANGE600 = Color(0xDA7B11);
const unsigned int ORANGE700 = Color(0xCB6F10);
const unsigned int GREEN400 = Color(0x33AB84);
const unsigned int GREEN500 = Color(0x2D9D78);
const unsigned int GREEN600 = Color(0x268E6C);
const unsigned int GREEN700 = Color(0x12805C);
}
#ifdef SPECTRUM_USE_LIGHT_THEME
const unsigned int GRAY50 = Color(0xFFFFFF);
const unsigned int GRAY75 = Color(0xFAFAFA);
const unsigned int GRAY100 = Color(0xF5F5F5);
const unsigned int GRAY200 = Color(0xEAEAEA);
const unsigned int GRAY300 = Color(0xE1E1E1);
const unsigned int GRAY400 = Color(0xCACACA);
const unsigned int GRAY500 = Color(0xB3B3B3);
const unsigned int GRAY600 = Color(0x8E8E8E);
const unsigned int GRAY700 = Color(0x707070);
const unsigned int GRAY800 = Color(0x4B4B4B);
const unsigned int GRAY900 = Color(0x2C2C2C);
const unsigned int BLUE400 = Color(0x2680EB);
const unsigned int BLUE500 = Color(0x1473E6);
const unsigned int BLUE600 = Color(0x0D66D0);
const unsigned int BLUE700 = Color(0x095ABA);
const unsigned int RED400 = Color(0xE34850);
const unsigned int RED500 = Color(0xD7373F);
const unsigned int RED600 = Color(0xC9252D);
const unsigned int RED700 = Color(0xBB121A);
const unsigned int ORANGE400 = Color(0xE68619);
const unsigned int ORANGE500 = Color(0xDA7B11);
const unsigned int ORANGE600 = Color(0xCB6F10);
const unsigned int ORANGE700 = Color(0xBD640D);
const unsigned int GREEN400 = Color(0x2D9D78);
const unsigned int GREEN500 = Color(0x268E6C);
const unsigned int GREEN600 = Color(0x12805C);
const unsigned int GREEN700 = Color(0x107154);
const unsigned int INDIGO400 = Color(0x6767EC);
const unsigned int INDIGO500 = Color(0x5C5CE0);
const unsigned int INDIGO600 = Color(0x5151D3);
const unsigned int INDIGO700 = Color(0x4646C6);
const unsigned int CELERY400 = Color(0x44B556);
const unsigned int CELERY500 = Color(0x3DA74E);
const unsigned int CELERY600 = Color(0x379947);
const unsigned int CELERY700 = Color(0x318B40);
const unsigned int MAGENTA400 = Color(0xD83790);
const unsigned int MAGENTA500 = Color(0xCE2783);
const unsigned int MAGENTA600 = Color(0xBC1C74);
const unsigned int MAGENTA700 = Color(0xAE0E66);
const unsigned int YELLOW400 = Color(0xDFBF00);
const unsigned int YELLOW500 = Color(0xD2B200);
const unsigned int YELLOW600 = Color(0xC4A600);
const unsigned int YELLOW700 = Color(0xB79900);
const unsigned int FUCHSIA400 = Color(0xC038CC);
const unsigned int FUCHSIA500 = Color(0xB130BD);
const unsigned int FUCHSIA600 = Color(0xA228AD);
const unsigned int FUCHSIA700 = Color(0x93219E);
const unsigned int SEAFOAM400 = Color(0x1B959A);
const unsigned int SEAFOAM500 = Color(0x16878C);
const unsigned int SEAFOAM600 = Color(0x0F797D);
const unsigned int SEAFOAM700 = Color(0x096C6F);
const unsigned int CHARTREUSE400 = Color(0x85D044);
const unsigned int CHARTREUSE500 = Color(0x7CC33F);
const unsigned int CHARTREUSE600 = Color(0x73B53A);
const unsigned int CHARTREUSE700 = Color(0x6AA834);
const unsigned int PURPLE400 = Color(0x9256D9);
const unsigned int PURPLE500 = Color(0x864CCC);
const unsigned int PURPLE600 = Color(0x7A42BF);
const unsigned int PURPLE700 = Color(0x6F38B1);
#endif
#ifdef SPECTRUM_USE_DARK_THEME
const unsigned int GRAY50 = Color(0x252525);
const unsigned int GRAY75 = Color(0x2F2F2F);
const unsigned int GRAY100 = Color(0x323232);
const unsigned int GRAY200 = Color(0x393939);
const unsigned int GRAY300 = Color(0x3E3E3E);
const unsigned int GRAY400 = Color(0x4D4D4D);
const unsigned int GRAY500 = Color(0x5C5C5C);
const unsigned int GRAY600 = Color(0x7B7B7B);
const unsigned int GRAY700 = Color(0x999999);
const unsigned int GRAY800 = Color(0xCDCDCD);
const unsigned int GRAY900 = Color(0xFFFFFF);
const unsigned int BLUE400 = Color(0x2680EB);
const unsigned int BLUE500 = Color(0x378EF0);
const unsigned int BLUE600 = Color(0x4B9CF5);
const unsigned int BLUE700 = Color(0x5AA9FA);
const unsigned int RED400 = Color(0xE34850);
const unsigned int RED500 = Color(0xEC5B62);
const unsigned int RED600 = Color(0xF76D74);
const unsigned int RED700 = Color(0xFF7B82);
const unsigned int ORANGE400 = Color(0xE68619);
const unsigned int ORANGE500 = Color(0xF29423);
const unsigned int ORANGE600 = Color(0xF9A43F);
const unsigned int ORANGE700 = Color(0xFFB55B);
const unsigned int GREEN400 = Color(0x2D9D78);
const unsigned int GREEN500 = Color(0x33AB84);
const unsigned int GREEN600 = Color(0x39B990);
const unsigned int GREEN700 = Color(0x3FC89C);
const unsigned int INDIGO400 = Color(0x6767EC);
const unsigned int INDIGO500 = Color(0x7575F1);
const unsigned int INDIGO600 = Color(0x8282F6);
const unsigned int INDIGO700 = Color(0x9090FA);
const unsigned int CELERY400 = Color(0x44B556);
const unsigned int CELERY500 = Color(0x4BC35F);
const unsigned int CELERY600 = Color(0x51D267);
const unsigned int CELERY700 = Color(0x58E06F);
const unsigned int MAGENTA400 = Color(0xD83790);
const unsigned int MAGENTA500 = Color(0xE2499D);
const unsigned int MAGENTA600 = Color(0xEC5AAA);
const unsigned int MAGENTA700 = Color(0xF56BB7);
const unsigned int YELLOW400 = Color(0xDFBF00);
const unsigned int YELLOW500 = Color(0xEDCC00);
const unsigned int YELLOW600 = Color(0xFAD900);
const unsigned int YELLOW700 = Color(0xFFE22E);
const unsigned int FUCHSIA400 = Color(0xC038CC);
const unsigned int FUCHSIA500 = Color(0xCF3EDC);
const unsigned int FUCHSIA600 = Color(0xD951E5);
const unsigned int FUCHSIA700 = Color(0xE366EF);
const unsigned int SEAFOAM400 = Color(0x1B959A);
const unsigned int SEAFOAM500 = Color(0x20A3A8);
const unsigned int SEAFOAM600 = Color(0x23B2B8);
const unsigned int SEAFOAM700 = Color(0x26C0C7);
const unsigned int CHARTREUSE400 = Color(0x85D044);
const unsigned int CHARTREUSE500 = Color(0x8EDE49);
const unsigned int CHARTREUSE600 = Color(0x9BEC54);
const unsigned int CHARTREUSE700 = Color(0xA3F858);
const unsigned int PURPLE400 = Color(0x9256D9);
const unsigned int PURPLE500 = Color(0x9D64E1);
const unsigned int PURPLE600 = Color(0xA873E9);
const unsigned int PURPLE700 = Color(0xB483F0);
#endif
}
}
+38
View File
@@ -0,0 +1,38 @@
// dear imgui, v1.86 WIP
// (stack layout headers)
/*
Index of this file:
// [SECTION] Stack Layout API
*/
#pragma once
#include "imgui.h"
#ifndef IMGUI_DISABLE
//-----------------------------------------------------------------------------
// [SECTION] Stack Layout API
//-----------------------------------------------------------------------------
namespace ImGui
{
IMGUI_API void BeginHorizontal(const char* str_id, const ImVec2& size = ImVec2(0, 0), float align = -1.0f);
IMGUI_API void BeginHorizontal(const void* ptr_id, const ImVec2& size = ImVec2(0, 0), float align = -1.0f);
IMGUI_API void BeginHorizontal(int id, const ImVec2& size = ImVec2(0, 0), float align = -1);
IMGUI_API void EndHorizontal();
IMGUI_API void BeginVertical(const char* str_id, const ImVec2& size = ImVec2(0, 0), float align = -1.0f);
IMGUI_API void BeginVertical(const void* ptr_id, const ImVec2& size = ImVec2(0, 0), float align = -1.0f);
IMGUI_API void BeginVertical(int id, const ImVec2& size = ImVec2(0, 0), float align = -1);
IMGUI_API void EndVertical();
IMGUI_API void Spring(float weight = 1.0f, float spacing = -1.0f);
IMGUI_API void SuspendLayout();
IMGUI_API void ResumeLayout();
} // namespace ImGui
#endif // #ifndef IMGUI_DISABLE
@@ -0,0 +1,30 @@
// dear imgui, v1.86 WIP
// (stack layout headers)
/*
Index of this file:
// [SECTION] Stack Layout Internal API
*/
#pragma once
#include "imgui_internal.h"
#include "imgui_stacklayout.h"
#ifndef IMGUI_DISABLE
//-----------------------------------------------------------------------------
// [SECTION] Stack Layout Internal API
//-----------------------------------------------------------------------------
namespace ImGuiInternal
{
IMGUI_API ImGuiLayoutType GetCurrentLayoutType(ImGuiID window_id);
IMGUI_API void UpdateItemRect(ImGuiID window_id, const ImVec2& min, const ImVec2& max);
} // namespace ImGuiInternal
#endif // #ifndef IMGUI_DISABLE
+627
View File
@@ -0,0 +1,627 @@
// [DEAR IMGUI]
// This is a slightly modified version of stb_rect_pack.h 1.01.
// Grep for [DEAR IMGUI] to find the changes.
//
// stb_rect_pack.h - v1.01 - public domain - rectangle packing
// Sean Barrett 2014
//
// Useful for e.g. packing rectangular textures into an atlas.
// Does not do rotation.
//
// Before #including,
//
// #define STB_RECT_PACK_IMPLEMENTATION
//
// in the file that you want to have the implementation.
//
// Not necessarily the awesomest packing method, but better than
// the totally naive one in stb_truetype (which is primarily what
// this is meant to replace).
//
// Has only had a few tests run, may have issues.
//
// More docs to come.
//
// No memory allocations; uses qsort() and assert() from stdlib.
// Can override those by defining STBRP_SORT and STBRP_ASSERT.
//
// This library currently uses the Skyline Bottom-Left algorithm.
//
// Please note: better rectangle packers are welcome! Please
// implement them to the same API, but with a different init
// function.
//
// Credits
//
// Library
// Sean Barrett
// Minor features
// Martins Mozeiko
// github:IntellectualKitty
//
// Bugfixes / warning fixes
// Jeremy Jaussaud
// Fabian Giesen
//
// Version history:
//
// 1.01 (2021-07-11) always use large rect mode, expose STBRP__MAXVAL in public section
// 1.00 (2019-02-25) avoid small space waste; gracefully fail too-wide rectangles
// 0.99 (2019-02-07) warning fixes
// 0.11 (2017-03-03) return packing success/fail result
// 0.10 (2016-10-25) remove cast-away-const to avoid warnings
// 0.09 (2016-08-27) fix compiler warnings
// 0.08 (2015-09-13) really fix bug with empty rects (w=0 or h=0)
// 0.07 (2015-09-13) fix bug with empty rects (w=0 or h=0)
// 0.06 (2015-04-15) added STBRP_SORT to allow replacing qsort
// 0.05: added STBRP_ASSERT to allow replacing assert
// 0.04: fixed minor bug in STBRP_LARGE_RECTS support
// 0.01: initial release
//
// LICENSE
//
// See end of file for license information.
//////////////////////////////////////////////////////////////////////////////
//
// INCLUDE SECTION
//
#ifndef STB_INCLUDE_STB_RECT_PACK_H
#define STB_INCLUDE_STB_RECT_PACK_H
#define STB_RECT_PACK_VERSION 1
#ifdef STBRP_STATIC
#define STBRP_DEF static
#else
#define STBRP_DEF extern
#endif
#ifdef __cplusplus
extern "C" {
#endif
typedef struct stbrp_context stbrp_context;
typedef struct stbrp_node stbrp_node;
typedef struct stbrp_rect stbrp_rect;
typedef int stbrp_coord;
#define STBRP__MAXVAL 0x7fffffff
// Mostly for internal use, but this is the maximum supported coordinate value.
STBRP_DEF int stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects);
// Assign packed locations to rectangles. The rectangles are of type
// 'stbrp_rect' defined below, stored in the array 'rects', and there
// are 'num_rects' many of them.
//
// Rectangles which are successfully packed have the 'was_packed' flag
// set to a non-zero value and 'x' and 'y' store the minimum location
// on each axis (i.e. bottom-left in cartesian coordinates, top-left
// if you imagine y increasing downwards). Rectangles which do not fit
// have the 'was_packed' flag set to 0.
//
// You should not try to access the 'rects' array from another thread
// while this function is running, as the function temporarily reorders
// the array while it executes.
//
// To pack into another rectangle, you need to call stbrp_init_target
// again. To continue packing into the same rectangle, you can call
// this function again. Calling this multiple times with multiple rect
// arrays will probably produce worse packing results than calling it
// a single time with the full rectangle array, but the option is
// available.
//
// The function returns 1 if all of the rectangles were successfully
// packed and 0 otherwise.
struct stbrp_rect
{
// reserved for your use:
int id;
// input:
stbrp_coord w, h;
// output:
stbrp_coord x, y;
int was_packed; // non-zero if valid packing
}; // 16 bytes, nominally
STBRP_DEF void stbrp_init_target (stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes);
// Initialize a rectangle packer to:
// pack a rectangle that is 'width' by 'height' in dimensions
// using temporary storage provided by the array 'nodes', which is 'num_nodes' long
//
// You must call this function every time you start packing into a new target.
//
// There is no "shutdown" function. The 'nodes' memory must stay valid for
// the following stbrp_pack_rects() call (or calls), but can be freed after
// the call (or calls) finish.
//
// Note: to guarantee best results, either:
// 1. make sure 'num_nodes' >= 'width'
// or 2. call stbrp_allow_out_of_mem() defined below with 'allow_out_of_mem = 1'
//
// If you don't do either of the above things, widths will be quantized to multiples
// of small integers to guarantee the algorithm doesn't run out of temporary storage.
//
// If you do #2, then the non-quantized algorithm will be used, but the algorithm
// may run out of temporary storage and be unable to pack some rectangles.
STBRP_DEF void stbrp_setup_allow_out_of_mem (stbrp_context *context, int allow_out_of_mem);
// Optionally call this function after init but before doing any packing to
// change the handling of the out-of-temp-memory scenario, described above.
// If you call init again, this will be reset to the default (false).
STBRP_DEF void stbrp_setup_heuristic (stbrp_context *context, int heuristic);
// Optionally select which packing heuristic the library should use. Different
// heuristics will produce better/worse results for different data sets.
// If you call init again, this will be reset to the default.
enum
{
STBRP_HEURISTIC_Skyline_default=0,
STBRP_HEURISTIC_Skyline_BL_sortHeight = STBRP_HEURISTIC_Skyline_default,
STBRP_HEURISTIC_Skyline_BF_sortHeight
};
//////////////////////////////////////////////////////////////////////////////
//
// the details of the following structures don't matter to you, but they must
// be visible so you can handle the memory allocations for them
struct stbrp_node
{
stbrp_coord x,y;
stbrp_node *next;
};
struct stbrp_context
{
int width;
int height;
int align;
int init_mode;
int heuristic;
int num_nodes;
stbrp_node *active_head;
stbrp_node *free_head;
stbrp_node extra[2]; // we allocate two extra nodes so optimal user-node-count is 'width' not 'width+2'
};
#ifdef __cplusplus
}
#endif
#endif
//////////////////////////////////////////////////////////////////////////////
//
// IMPLEMENTATION SECTION
//
#ifdef STB_RECT_PACK_IMPLEMENTATION
#ifndef STBRP_SORT
#include <stdlib.h>
#define STBRP_SORT qsort
#endif
#ifndef STBRP_ASSERT
#include <assert.h>
#define STBRP_ASSERT assert
#endif
#ifdef _MSC_VER
#define STBRP__NOTUSED(v) (void)(v)
#define STBRP__CDECL __cdecl
#else
#define STBRP__NOTUSED(v) (void)sizeof(v)
#define STBRP__CDECL
#endif
enum
{
STBRP__INIT_skyline = 1
};
STBRP_DEF void stbrp_setup_heuristic(stbrp_context *context, int heuristic)
{
switch (context->init_mode) {
case STBRP__INIT_skyline:
STBRP_ASSERT(heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight || heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight);
context->heuristic = heuristic;
break;
default:
STBRP_ASSERT(0);
}
}
STBRP_DEF void stbrp_setup_allow_out_of_mem(stbrp_context *context, int allow_out_of_mem)
{
if (allow_out_of_mem)
// if it's ok to run out of memory, then don't bother aligning them;
// this gives better packing, but may fail due to OOM (even though
// the rectangles easily fit). @TODO a smarter approach would be to only
// quantize once we've hit OOM, then we could get rid of this parameter.
context->align = 1;
else {
// if it's not ok to run out of memory, then quantize the widths
// so that num_nodes is always enough nodes.
//
// I.e. num_nodes * align >= width
// align >= width / num_nodes
// align = ceil(width/num_nodes)
context->align = (context->width + context->num_nodes-1) / context->num_nodes;
}
}
STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes)
{
int i;
for (i=0; i < num_nodes-1; ++i)
nodes[i].next = &nodes[i+1];
nodes[i].next = NULL;
context->init_mode = STBRP__INIT_skyline;
context->heuristic = STBRP_HEURISTIC_Skyline_default;
context->free_head = &nodes[0];
context->active_head = &context->extra[0];
context->width = width;
context->height = height;
context->num_nodes = num_nodes;
stbrp_setup_allow_out_of_mem(context, 0);
// node 0 is the full width, node 1 is the sentinel (lets us not store width explicitly)
context->extra[0].x = 0;
context->extra[0].y = 0;
context->extra[0].next = &context->extra[1];
context->extra[1].x = (stbrp_coord) width;
context->extra[1].y = (1<<30);
context->extra[1].next = NULL;
}
// find minimum y position if it starts at x1
static int stbrp__skyline_find_min_y(stbrp_context *c, stbrp_node *first, int x0, int width, int *pwaste)
{
stbrp_node *node = first;
int x1 = x0 + width;
int min_y, visited_width, waste_area;
STBRP__NOTUSED(c);
STBRP_ASSERT(first->x <= x0);
#if 0
// skip in case we're past the node
while (node->next->x <= x0)
++node;
#else
STBRP_ASSERT(node->next->x > x0); // we ended up handling this in the caller for efficiency
#endif
STBRP_ASSERT(node->x <= x0);
min_y = 0;
waste_area = 0;
visited_width = 0;
while (node->x < x1) {
if (node->y > min_y) {
// raise min_y higher.
// we've accounted for all waste up to min_y,
// but we'll now add more waste for everything we've visted
waste_area += visited_width * (node->y - min_y);
min_y = node->y;
// the first time through, visited_width might be reduced
if (node->x < x0)
visited_width += node->next->x - x0;
else
visited_width += node->next->x - node->x;
} else {
// add waste area
int under_width = node->next->x - node->x;
if (under_width + visited_width > width)
under_width = width - visited_width;
waste_area += under_width * (min_y - node->y);
visited_width += under_width;
}
node = node->next;
}
*pwaste = waste_area;
return min_y;
}
typedef struct
{
int x,y;
stbrp_node **prev_link;
} stbrp__findresult;
static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int width, int height)
{
int best_waste = (1<<30), best_x, best_y = (1 << 30);
stbrp__findresult fr;
stbrp_node **prev, *node, *tail, **best = NULL;
// align to multiple of c->align
width = (width + c->align - 1);
width -= width % c->align;
STBRP_ASSERT(width % c->align == 0);
// if it can't possibly fit, bail immediately
if (width > c->width || height > c->height) {
fr.prev_link = NULL;
fr.x = fr.y = 0;
return fr;
}
node = c->active_head;
prev = &c->active_head;
while (node->x + width <= c->width) {
int y,waste;
y = stbrp__skyline_find_min_y(c, node, node->x, width, &waste);
if (c->heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight) { // actually just want to test BL
// bottom left
if (y < best_y) {
best_y = y;
best = prev;
}
} else {
// best-fit
if (y + height <= c->height) {
// can only use it if it first vertically
if (y < best_y || (y == best_y && waste < best_waste)) {
best_y = y;
best_waste = waste;
best = prev;
}
}
}
prev = &node->next;
node = node->next;
}
best_x = (best == NULL) ? 0 : (*best)->x;
// if doing best-fit (BF), we also have to try aligning right edge to each node position
//
// e.g, if fitting
//
// ____________________
// |____________________|
//
// into
//
// | |
// | ____________|
// |____________|
//
// then right-aligned reduces waste, but bottom-left BL is always chooses left-aligned
//
// This makes BF take about 2x the time
if (c->heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight) {
tail = c->active_head;
node = c->active_head;
prev = &c->active_head;
// find first node that's admissible
while (tail->x < width)
tail = tail->next;
while (tail) {
int xpos = tail->x - width;
int y,waste;
STBRP_ASSERT(xpos >= 0);
// find the left position that matches this
while (node->next->x <= xpos) {
prev = &node->next;
node = node->next;
}
STBRP_ASSERT(node->next->x > xpos && node->x <= xpos);
y = stbrp__skyline_find_min_y(c, node, xpos, width, &waste);
if (y + height <= c->height) {
if (y <= best_y) {
if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) {
best_x = xpos;
//STBRP_ASSERT(y <= best_y); [DEAR IMGUI]
best_y = y;
best_waste = waste;
best = prev;
}
}
}
tail = tail->next;
}
}
fr.prev_link = best;
fr.x = best_x;
fr.y = best_y;
return fr;
}
static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, int width, int height)
{
// find best position according to heuristic
stbrp__findresult res = stbrp__skyline_find_best_pos(context, width, height);
stbrp_node *node, *cur;
// bail if:
// 1. it failed
// 2. the best node doesn't fit (we don't always check this)
// 3. we're out of memory
if (res.prev_link == NULL || res.y + height > context->height || context->free_head == NULL) {
res.prev_link = NULL;
return res;
}
// on success, create new node
node = context->free_head;
node->x = (stbrp_coord) res.x;
node->y = (stbrp_coord) (res.y + height);
context->free_head = node->next;
// insert the new node into the right starting point, and
// let 'cur' point to the remaining nodes needing to be
// stiched back in
cur = *res.prev_link;
if (cur->x < res.x) {
// preserve the existing one, so start testing with the next one
stbrp_node *next = cur->next;
cur->next = node;
cur = next;
} else {
*res.prev_link = node;
}
// from here, traverse cur and free the nodes, until we get to one
// that shouldn't be freed
while (cur->next && cur->next->x <= res.x + width) {
stbrp_node *next = cur->next;
// move the current node to the free list
cur->next = context->free_head;
context->free_head = cur;
cur = next;
}
// stitch the list back in
node->next = cur;
if (cur->x < res.x + width)
cur->x = (stbrp_coord) (res.x + width);
#ifdef _DEBUG
cur = context->active_head;
while (cur->x < context->width) {
STBRP_ASSERT(cur->x < cur->next->x);
cur = cur->next;
}
STBRP_ASSERT(cur->next == NULL);
{
int count=0;
cur = context->active_head;
while (cur) {
cur = cur->next;
++count;
}
cur = context->free_head;
while (cur) {
cur = cur->next;
++count;
}
STBRP_ASSERT(count == context->num_nodes+2);
}
#endif
return res;
}
static int STBRP__CDECL rect_height_compare(const void *a, const void *b)
{
const stbrp_rect *p = (const stbrp_rect *) a;
const stbrp_rect *q = (const stbrp_rect *) b;
if (p->h > q->h)
return -1;
if (p->h < q->h)
return 1;
return (p->w > q->w) ? -1 : (p->w < q->w);
}
static int STBRP__CDECL rect_original_order(const void *a, const void *b)
{
const stbrp_rect *p = (const stbrp_rect *) a;
const stbrp_rect *q = (const stbrp_rect *) b;
return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed);
}
STBRP_DEF int stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects)
{
int i, all_rects_packed = 1;
// we use the 'was_packed' field internally to allow sorting/unsorting
for (i=0; i < num_rects; ++i) {
rects[i].was_packed = i;
}
// sort according to heuristic
STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_height_compare);
for (i=0; i < num_rects; ++i) {
if (rects[i].w == 0 || rects[i].h == 0) {
rects[i].x = rects[i].y = 0; // empty rect needs no space
} else {
stbrp__findresult fr = stbrp__skyline_pack_rectangle(context, rects[i].w, rects[i].h);
if (fr.prev_link) {
rects[i].x = (stbrp_coord) fr.x;
rects[i].y = (stbrp_coord) fr.y;
} else {
rects[i].x = rects[i].y = STBRP__MAXVAL;
}
}
}
// unsort
STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_original_order);
// set was_packed flags and all_rects_packed status
for (i=0; i < num_rects; ++i) {
rects[i].was_packed = !(rects[i].x == STBRP__MAXVAL && rects[i].y == STBRP__MAXVAL);
if (!rects[i].was_packed)
all_rects_packed = 0;
}
// return the all_rects_packed status
return all_rects_packed;
}
#endif
/*
------------------------------------------------------------------------------
This software is available under 2 licenses -- choose whichever you prefer.
------------------------------------------------------------------------------
ALTERNATIVE A - MIT License
Copyright (c) 2017 Sean Barrett
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
------------------------------------------------------------------------------
ALTERNATIVE B - Public Domain (www.unlicense.org)
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
software, either in source code form or as a compiled binary, for any purpose,
commercial or non-commercial, and by any means.
In jurisdictions that recognize copyright laws, the author or authors of this
software dedicate any and all copyright interest in the software to the public
domain. We make this dedication for the benefit of the public at large and to
the detriment of our heirs and successors. We intend this dedication to be an
overt act of relinquishment in perpetuity of all present and future rights to
this software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
------------------------------------------------------------------------------
*/
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+21
View File
@@ -0,0 +1,21 @@
// dear imgui: wrappers for C++ standard library (STL) types (std::string, etc.)
// This is also an example of how you may wrap your own similar types.
// Changelog:
// - v0.10: Initial version. Added InputText() / InputTextMultiline() calls with std::string
// See more C++ related extension (fmt, RAII, syntaxis sugar) on Wiki:
// https://github.com/ocornut/imgui/wiki/Useful-Extensions#cness
#pragma once
#include <tl/string.h>
namespace ImGui
{
// ImGui::InputText() with std::string
// Because text input needs dynamic resizing, we need to setup a callback to grow the capacity
IMGUI_API bool InputText(const char* label, eastl::string* str, ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = NULL, void* user_data = NULL);
IMGUI_API bool InputTextMultiline(const char* label, eastl::string* str, const ImVec2& size = ImVec2(0, 0), ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = NULL, void* user_data = NULL);
IMGUI_API bool InputTextWithHint(const char* label, const char* hint, eastl::string* str, ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = NULL, void* user_data = NULL);
}
@@ -0,0 +1,50 @@
// dear imgui: FreeType font builder (used as a replacement for the stb_truetype builder)
// (headers)
#pragma once
#include "IUI/ImGui/imgui.h" // IMGUI_API
// Forward declarations
struct ImFontAtlas;
struct ImFontBuilderIO;
// Hinting greatly impacts visuals (and glyph sizes).
// - By default, hinting is enabled and the font's native hinter is preferred over the auto-hinter.
// - When disabled, FreeType generates blurrier glyphs, more or less matches the stb_truetype.h
// - The Default hinting mode usually looks good, but may distort glyphs in an unusual way.
// - The Light hinting mode generates fuzzier glyphs but better matches Microsoft's rasterizer.
// You can set those flags globaly in ImFontAtlas::FontBuilderFlags
// You can set those flags on a per font basis in ImFontConfig::FontBuilderFlags
enum ImGuiFreeTypeBuilderFlags
{
ImGuiFreeTypeBuilderFlags_NoHinting = 1 << 0, // Disable hinting. This generally generates 'blurrier' bitmap glyphs when the glyph are rendered in any of the anti-aliased modes.
ImGuiFreeTypeBuilderFlags_NoAutoHint = 1 << 1, // Disable auto-hinter.
ImGuiFreeTypeBuilderFlags_ForceAutoHint = 1 << 2, // Indicates that the auto-hinter is preferred over the font's native hinter.
ImGuiFreeTypeBuilderFlags_LightHinting = 1 << 3, // A lighter hinting algorithm for gray-level modes. Many generated glyphs are fuzzier but better resemble their original shape. This is achieved by snapping glyphs to the pixel grid only vertically (Y-axis), as is done by Microsoft's ClearType and Adobe's proprietary font renderer. This preserves inter-glyph spacing in horizontal text.
ImGuiFreeTypeBuilderFlags_MonoHinting = 1 << 4, // Strong hinting algorithm that should only be used for monochrome output.
ImGuiFreeTypeBuilderFlags_Bold = 1 << 5, // Styling: Should we artificially embolden the font?
ImGuiFreeTypeBuilderFlags_Oblique = 1 << 6, // Styling: Should we slant the font, emulating italic style?
ImGuiFreeTypeBuilderFlags_Monochrome = 1 << 7, // Disable anti-aliasing. Combine this with MonoHinting for best results!
ImGuiFreeTypeBuilderFlags_LoadColor = 1 << 8, // Enable FreeType color-layered glyphs
ImGuiFreeTypeBuilderFlags_Bitmap = 1 << 9 // Enable FreeType bitmap glyphs
};
namespace ImGuiFreeType
{
// This is automatically assigned when using '#define IMGUI_ENABLE_FREETYPE'.
// If you need to dynamically select between multiple builders:
// - you can manually assign this builder with 'atlas->FontBuilderIO = ImGuiFreeType::GetBuilderForFreeType()'
// - prefer deep-copying this into your own ImFontBuilderIO instance if you use hot-reloading that messes up static data.
IMGUI_API const ImFontBuilderIO* GetBuilderForFreeType();
// Override allocators. By default ImGuiFreeType will use IM_ALLOC()/IM_FREE()
// However, as FreeType does lots of allocations we provide a way for the user to redirect it to a separate memory heap if desired.
IMGUI_API void SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* user_data), void (*free_func)(void* ptr, void* user_data), void* user_data = nullptr);
// Obsolete names (will be removed soon)
// Prefer using '#define IMGUI_ENABLE_FREETYPE'
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
//static inline bool BuildFontAtlas(ImFontAtlas* atlas, unsigned int flags = 0) { atlas->FontBuilderIO = GetBuilderForFreeType(); atlas->FontBuilderFlags = flags; return atlas->Build(); } // Prefer using '#define IMGUI_ENABLE_FREETYPE'
#endif
}
+78
View File
@@ -0,0 +1,78 @@
#pragma once
#include "IUI/ImGui/imgui.h"
#include "tl/narrow_cast.h"
#include "Kit/util/Color.h"
#include "IUI/Icons.h"
#include "Kit/util/IdentifierUtils.h"
#include "extras/imguiwrap.dear.h"
#include "tl/enum.h"
#include "tl/variant.h"
namespace ImGui
{
inline void PushID(size_t id) { PushID(static_cast<int>(id)); }
ImU32 ColorU32(kit::color::sRGBAi c);
ImU32 ColorU32(kit::color::sRGBi c);
void AddDottedLine(ImDrawList& list, ImVec2 p1, ImVec2 p2, ImU32 col, float dotLength, float thickness = 1.0f);
ImVec2 GetWindowContentPos();
ImVec2 GetWindowContentSize();
ImVec2 GetWindowContentBottomRightSide();
int8_t GetMouseButtonClicked();
int8_t GetMouseButtonDown();
int8_t GetMouseButtonReleased();
bool ColorEditor(kit::color::lRGBAhdr& io_color, bool& saveUndo, bool isHDR, bool hasAlpha, const tl::string& label, float alignNameX) noexcept;
bool CheckBoxTristate(const char* label, int* v_tristate);
bool BeginIconMenu(kit::icons::Icon icon, const char* label);
bool BeginIconMenu(kit::icons::FontIcon icon, const char* label);
bool MenuIconItem(kit::icons::Icon icon, const char* label, bool* selected = nullptr);
bool MenuIconItem(kit::icons::FontIcon icon, const char* label, bool* selected = nullptr);
void Icon(kit::icons::Icon icon, ImVec2 frameSize, ImVec2 size = ImVec2(0, 0), ImVec4 tint_col = ImVec4(1,1,1,1), ImVec4 border_col = ImVec4(0,0,0,0));
void Icon(kit::icons::FontIcon icon, ImVec2 frameSize, ImVec2 size = ImVec2(0, 0), ImVec4 tint_col = ImVec4(1,1,1,1), ImVec4 border_col = ImVec4(0,0,0,0));
bool IconButton(const char* str_id, kit::icons::Icon icon, ImVec2 size, bool active = false, ImVec4 bg_col = ImVec4(0,0,0,0), ImVec4 tint_col = ImVec4(1,1,1,1)); // <0 frame_padding uses default frame padding settings. 0 for no padding
bool IconButton(const char* str_id, kit::icons::FontIcon icon, const char* label, bool active = false);
bool ToggleButton(const char* str_id, bool* v);
bool Splitter(bool split_vertically, float thickness, float* size1, float* size2, float min_size1, float min_size2, float splitter_long_axis_size = -1.0f);
void BeginGroupPanel(const char* name, const ImVec2& size);
void EndGroupPanel();
template<typename Enum>
bool EnumCombo(const char* str_id, Enum& crtValue, bool humanReadable)
{
bool changed = false;
const tl::string preview = humanReadable ? kit::util::identifierToHumanReadableString(tl::string(tl::enum_name(crtValue))) : tl::string(tl::enum_name(crtValue));
if (const dear::Combo combo(str_id, preview.c_str(), ImGuiComboFlags_None); combo)
{
for (auto e: tl::enum_entries<Enum>())
{
tl::string label = humanReadable ? kit::util::identifierToHumanReadableString(tl::string(e.second)) : tl::string(e.second);
//int32_t value = static_cast<int32_t>(e.first);
PushID(tl::narrow<int>(e.first));
const bool itemSelected = crtValue == e.first;
if (Selectable(label.c_str(), itemSelected))
{
crtValue = e.first;
changed = true;
}
if (itemSelected)
SetItemDefaultFocus();
PopID();
}
}
return changed;
}
void AddUnderLine(ImColor col);
void TextURL(const char* name, const char* url);
}
+61
View File
@@ -0,0 +1,61 @@
#pragma once
#include "Kit/EngineManager.h"
#include <tl/vector.h>
#include <filament/IndexBuffer.h>
#include <filament/Material.h>
#include <filament/MaterialInstance.h>
#include <filament/Texture.h>
#include <filament/VertexBuffer.h>
#include <utils/Entity.h>
#include "IUI/ImGui/imgui.h"
struct ImDrawData;
struct ImGuiIO;
struct ImGuiContext;
namespace kit
{
// Translates ImGui's draw commands into Filament primitives, textures, vertex buffers, etc.
// Creates a UI-specific Scene object and populates it with a Renderable. Does not handle
// event processing; clients can simply call ImGui::GetIO() directly and set the mouse state.
class ImGuiFilamentBridge
{
public:
// The constructor creates its own Scene and places it in the given View.
ImGuiFilamentBridge(tl::lent_ref<EngineManager> engineManager, tl::lent_ref<filament::Scene> flmScene);
~ImGuiFilamentBridge();
// Low-level alternative to render() that consumes an ImGui command list and translates it into
// various Filament calls. This includes updating the vertex buffer, setting up material
// instances, and rebuilding the Renderable component that encompasses the entire UI. Since this
// makes Filament calls, it must be called from the main thread.
void processImGuiCommands(ImDrawData& commands, const ImGuiIO& io);
// Helper method called after resolving fontPath; public so fonts can be added by caller.
ImTextureID createAtlasTexture();
private:
void createBuffers(int numRequiredBuffers);
void populateVertexData(size_t bufferIndex,
size_t vbSizeInBytes,
void* vbData,
size_t ibSizeInBytes,
void* ibData);
tl::unique_ref<filament::VertexBuffer> createVertexBuffer(size_t capacity) const;
tl::unique_ref<filament::IndexBuffer> createIndexBuffer(size_t capacity) const;
tl::lent_ref<EngineManager> m_engineManager;
tl::lent_ref<filament::Scene> m_scene;
tl::unique_ptr<filament::Material> m_material;
tl::unique_ptr<filament::Texture> m_texture;
tl::vector<tl::unique_ref<filament::VertexBuffer>> m_vertexBuffers;
tl::vector<tl::unique_ref<filament::IndexBuffer>> m_indexBuffers;
tl::vector<tl::unique_ref<filament::MaterialInstance>> m_materialInstances;
utils::Entity m_renderable;
};
}
+30
View File
@@ -0,0 +1,30 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FILAGUI_IMGUIMATH_H_
#define FILAGUI_IMGUIMATH_H_
#include <imgui.h>
static ImVec2 operator+(const ImVec2& lhs, const ImVec2& rhs) {
return { lhs.x+rhs.x, lhs.y+rhs.y };
}
static ImVec2 operator-(const ImVec2& lhs, const ImVec2& rhs) {
return { lhs.x-rhs.x, lhs.y-rhs.y };
}
#endif /* FILAGUI_IMGUIMATH_H_ */
+451
View File
@@ -0,0 +1,451 @@
#pragma once
#include <utility> // std::forward etc
#include "IUI/ImGui/imgui.h"
#include <tl/string.h>
#include "imguiwrap.helpers.h"
namespace dear
{
static const ImVec2 Zero(0.0f, 0.0f);
// EditTableFlags provides a window with checkboxes/selects for all of the
// ImGuiTableFlags options so that a flags property can be edited in real-time.
extern void
EditTableFlags(const char* editWindowTitle, bool* showing, ImGuiTableFlags* flags) noexcept;
// EditWindowFlags presents a window for selecting text input field flags.
extern void
EditInputTextFlags(const char* title, bool* showing, ImGuiInputTextFlags* flags) noexcept;
// EditWindowFlags provides a window which checkboxes for all of the
// ImGuiWindowFlags options so that a flags property can be edited in real-time.
extern void
EditWindowFlags(const char* editWindowTitle, bool* showing, ImGuiWindowFlags* flags) noexcept;
// SetHostWindowSize lets you alter the native window dimensions from within your `imgui_main`
// callback. Change is applied after control returns to the imgui_main function, and the
// sizing from the last call within a frame is used.
extern void SetHostWindowSize(int x, int y) noexcept;
// scoped_effect is a helper that uses automatic object lifetime to control
// the invocation of a callable after potentially calling additional code,
// allowing for easy inline creation of scope guards.
//
// On its own, it does nothing but call the supplied function when it is
// destroyed;
template<typename Base, bool ForceDtor = false>
struct ScopeWrapper
{
using wrapped_type = Base;
using self_type = ScopeWrapper<Base>;
static constexpr bool force_dtor = ForceDtor;
protected:
const bool ok_;
public:
// constructor takes a predicate that may be used to determine if
// additional calls can be made, and a function/lambda/callable to
// be invoked from the destructor.
constexpr ScopeWrapper(bool ok) noexcept : ok_{ok} {}
// destructor always invokes the supplied destructor function.
~ScopeWrapper() noexcept
{
if constexpr (!force_dtor) {
if (!ok_)
return;
}
Base::dtor();
}
// operator&& will excute 'code' if the predicate supplied during
// construction was true.
template<typename PassthruFn>
constexpr bool operator&&(PassthruFn passthru) const noexcept
{
if (ok_)
passthru();
return ok_;
}
constexpr operator bool() const noexcept { return ok_; }
protected:
ScopeWrapper(const ScopeWrapper&) = delete;
ScopeWrapper& operator=(const ScopeWrapper&) = delete;
};
// Wrapper for ImGui::Begin ... End, which will always call End.
struct Begin : public ScopeWrapper<Begin, true>
{
// Invoke Begin and guarantee that 'End' will be called.
Begin(const char* title, bool* open = nullptr, ImGuiWindowFlags flags = 0) noexcept
: ScopeWrapper(ImGui::Begin(title, open, flags))
{}
static void dtor() noexcept { ImGui::End(); }
};
// Wrapper for ImGui::BeginChild ... EndChild, which will always call EndChild.
struct Child : public ScopeWrapper<Child, true>
{
Child(const char* title, const ImVec2& size = Zero, bool border = false,
ImGuiWindowFlags flags = 0) noexcept
: ScopeWrapper(ImGui::BeginChild(title, size, border, flags))
{}
Child(ImGuiID id, const ImVec2& size = Zero, bool border = false,
ImGuiWindowFlags flags = 0) noexcept
: ScopeWrapper(ImGui::BeginChild(id, size, border, flags))
{}
static void dtor() noexcept { ImGui::EndChild(); }
};
// Wrapper for ImGui::BeginChildFrame ... EndChildFrame, which will always call EndChildFrame.
struct ChildFrame : public ScopeWrapper<ChildFrame, true>
{
template<typename... Args>
ChildFrame(Args&&... args) noexcept
: ScopeWrapper(ImGui::BeginChildFrame(std::forward<Args>(args)...))
{}
static void dtor() noexcept { ImGui::EndChildFrame(); }
};
// Wrapper for ImGui::BeginGroup ... EndGroup which will always call EndGroup.
struct Group : public ScopeWrapper<Group, true>
{
Group() noexcept : ScopeWrapper(true) { ImGui::BeginGroup(); }
static void dtor() noexcept { ImGui::EndGroup(); }
};
// Wrapper for ImGui::Begin...EndCombo.
struct Combo : public ScopeWrapper<Combo>
{
Combo(const char* label, const char* preview, ImGuiComboFlags flags = 0) noexcept
: ScopeWrapper(ImGui::BeginCombo(label, preview, flags))
{}
static void dtor() noexcept { ImGui::EndCombo(); }
};
// Wrapper for ImGui::Begin...EndListBox.
struct ListBox : public ScopeWrapper<ListBox>
{
ListBox(const char* label, const ImVec2& size = Zero) noexcept
: ScopeWrapper(ImGui::BeginListBox(label, size))
{}
static void dtor() noexcept { ImGui::EndListBox(); }
};
struct ContextMenuWindow : public ScopeWrapper<ContextMenuWindow>
{
ContextMenuWindow(const char* str_id, ImGuiPopupFlags popup_flags = ImGuiPopupFlags_MouseButtonRight) noexcept
: ScopeWrapper(ImGui::BeginPopupContextWindow(str_id, popup_flags))
{
if (ok_)
{
auto spacing = ImGui::GetStyle().ItemSpacing;
spacing.y *= 2.f;
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, spacing);
}
}
static void dtor() noexcept
{
ImGui::PopStyleVar();
ImGui::EndPopup();
}
};
struct ContextMenu : public ScopeWrapper<ContextMenu>
{
ContextMenu(bool windowOrItem, const char* str_id, ImGuiPopupFlags popup_flags = ImGuiPopupFlags_MouseButtonRight) noexcept
: ScopeWrapper(windowOrItem ? ImGui::BeginPopupContextWindow(str_id, popup_flags) : ImGui::BeginPopupContextItem(str_id, popup_flags))
{
if (ok_)
{
auto spacing = ImGui::GetStyle().ItemSpacing;
spacing.y *= 2.f;
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, spacing);
}
}
static void dtor() noexcept
{
ImGui::PopStyleVar();
ImGui::EndPopup();
}
};
// Wrapper for ImGui::Begin...EndMenuBar.
struct MenuBar : public ScopeWrapper<MenuBar>
{
MenuBar() noexcept : ScopeWrapper(ImGui::BeginMenuBar()) {}
static void dtor() noexcept { ImGui::EndMenuBar(); }
};
// Wrapper for ImGui::Begin...EndMainMenuBar.
struct MainMenuBar : public ScopeWrapper<MainMenuBar>
{
MainMenuBar() noexcept : ScopeWrapper(ImGui::BeginMainMenuBar()) {}
static void dtor() noexcept { ImGui::EndMainMenuBar(); }
};
// Wrapper for ImGui::BeginMenu...ImGui::EndMenu.
struct Menu : public ScopeWrapper<Menu>
{
Menu(const char* label, bool enabled = true) noexcept
: ScopeWrapper(ImGui::BeginMenu(label, enabled))
{}
static void dtor() noexcept { ImGui::EndMenu(); }
};
// Wrapper for ImGui::BeginTable...ImGui::EndTable.
// See also EditTableFlags.
struct Table : public ScopeWrapper<Table>
{
Table(const char* str_id, int column, ImGuiTableFlags flags = 0,
const ImVec2& outer_size = Zero, float inner_width = 0.0f) noexcept
: ScopeWrapper(ImGui::BeginTable(str_id, column, flags, outer_size, inner_width))
{}
static void dtor() noexcept { ImGui::EndTable(); }
};
// Wrapper for ImGui::Begin...EndToolTip.
struct Tooltip : public ScopeWrapper<Tooltip>
{
Tooltip() noexcept : ScopeWrapper(true) { ImGui::BeginTooltip(); }
static void dtor() noexcept { ImGui::EndTooltip(); }
};
// Wrapper around ImGui::CollapsingHeader to allow consistent code styling.
struct CollapsingHeader : public ScopeWrapper<CollapsingHeader>
{
CollapsingHeader(const char* label, ImGuiTreeNodeFlags flags = 0) noexcept
: ScopeWrapper(ImGui::CollapsingHeader(label, flags))
{}
inline static void dtor() noexcept {}
};
// Wrapper for ImGui::TreeNode...ImGui::TreePop.
// See also SeparatedTreeNode.
struct TreeNode : public ScopeWrapper<TreeNode>
{
TreeNode(const char* label) noexcept : ScopeWrapper(ImGui::TreeNode(label)) {}
template<typename... Args>
TreeNode(const char* str_id, const char* fmt, Args&&... args) noexcept : ScopeWrapper(ImGui::TreeNode(str_id, fmt, std::forward<Args>(args)...)) {}
template<typename... Args>
TreeNode(const void* ptr_id, const char* fmt, Args&&... args) noexcept : ScopeWrapper(ImGui::TreeNode(ptr_id, fmt, std::forward<Args>(args)...)) {}
TreeNode(const char* label, ImGuiTreeNodeFlags flags) noexcept : ScopeWrapper(ImGui::TreeNodeEx(label, flags)) {}
template<typename... Args>
TreeNode(const char* str_id, ImGuiTreeNodeFlags flags, const char* fmt, Args&&... args) noexcept : ScopeWrapper(ImGui::TreeNodeEx(str_id, flags, fmt, std::forward<Args>(args)...)) {}
template<typename... Args>
TreeNode(const void* ptr_id, ImGuiTreeNodeFlags flags, const char* fmt, Args&&... args) noexcept : ScopeWrapper(ImGui::TreeNodeEx(ptr_id, flags, fmt, std::forward<Args>(args)...)) {}
template<typename... Args>
TreeNode(const char* str_id, ImGuiTreeNodeFlags flags, const char* label) noexcept : ScopeWrapper(ImGui::TreeNode(str_id, flags, label)) {}
template<typename... Args>
TreeNode(const void* ptr_id, ImGuiTreeNodeFlags flags, const char* label) noexcept : ScopeWrapper(ImGui::TreeNode(ptr_id, flags, label)) {}
static void dtor() noexcept { ImGui::TreePop(); }
};
// Wrapper around a TreeNode followed by a Separator (it's a fairly common sequence).
struct SeparatedTreeNode : public ScopeWrapper<SeparatedTreeNode>
{
template<typename... Args>
SeparatedTreeNode(Args&&... args) noexcept
: ScopeWrapper(ImGui::TreeNode(std::forward<Args>(args)...))
{}
static void dtor() noexcept
{
ImGui::TreePop();
ImGui::Separator();
}
};
// Popup provides the stock wrapper around ImGui::BeginPopup...ImGui::EndPopup as well as two
// methods of instantiating a modal, for those who want modality to be a property fo Popup
// rather than a discrete type.
struct Popup : public ScopeWrapper<Popup>
{
// Non-modal Popup.
Popup(const char* str_id, ImGuiWindowFlags flags = 0) noexcept
: ScopeWrapper(ImGui::BeginPopup(str_id, flags))
{}
// Modal popups.
// imguiwrap provides 3 ways to construct a modal popup:
// - Use the PopupModal class,
// - Use Popup(modal{}, ...)
// - Use the static method Popup::Modal(...)
struct modal
{
};
Popup(modal, const char* name, bool* p_open = nullptr, ImGuiWindowFlags flags = 0) noexcept
: ScopeWrapper(ImGui::BeginPopupModal(name, p_open, flags))
{}
static Popup
Modal(const char* name, bool* p_open = nullptr, ImGuiWindowFlags flags = 0) noexcept
{
return Popup(modal{}, name, p_open, flags);
}
static void dtor() noexcept { ImGui::EndPopup(); }
};
// Wrapper around ImGui's BeginPopupModal ... EndPopup sequence.
struct PopupModal : public ScopeWrapper<PopupModal>
{
PopupModal(const char* name, bool* p_open = nullptr, ImGuiWindowFlags flags = 0) noexcept
: ScopeWrapper(ImGui::BeginPopupModal(name, p_open, flags))
{}
static void dtor() noexcept { ImGui::EndPopup(); }
};
// Wrapper for ImGui::BeginTabBar ... EndTabBar
struct TabBar : public ScopeWrapper<TabBar>
{
TabBar(const char* name, ImGuiTabBarFlags flags = 0) noexcept
: ScopeWrapper(ImGui::BeginTabBar(name, flags))
{}
static void dtor() noexcept { ImGui::EndTabBar(); }
};
// Wrapper for ImGui::BeginTabItem ... EndTabItem
struct TabItem : public ScopeWrapper<TabItem>
{
TabItem(const char* name, bool* open = nullptr, ImGuiTabItemFlags flags = 0) noexcept
: ScopeWrapper(ImGui::BeginTabItem(name, open, flags))
{}
static void dtor() noexcept { ImGui::EndTabItem(); }
};
// Wrapper around pushing a style var onto ImGui's stack and popping it back off.
/// TODO: Support nesting so we can do a single pop operation.
struct WithStyleVar : public ScopeWrapper<WithStyleVar>
{
WithStyleVar(ImGuiStyleVar idx, const ImVec2& val) noexcept : ScopeWrapper(true)
{
ImGui::PushStyleVar(idx, val);
}
WithStyleVar(ImGuiStyleVar idx, float val = 0.0f) noexcept : ScopeWrapper(true)
{
ImGui::PushStyleVar(idx, val);
}
static void dtor() noexcept { ImGui::PopStyleVar(); }
};
/// TODO: WithStyleColor
// Wrapper for BeginTooltip predicated on the previous item being hovered.
struct ItemTooltip : public ScopeWrapper<ItemTooltip>
{
ItemTooltip(ImGuiHoveredFlags flags = 0) noexcept
: ScopeWrapper(ImGui::IsItemHovered(flags))
{
if (ok_)
ImGui::BeginTooltip();
}
static void dtor() noexcept { ImGui::EndTooltip(); }
};
// Wrapper for BeginTooltip predicated on the previous item being hovered.
struct ScopedItemWidth : public ScopeWrapper<ScopedItemWidth, true>
{
ScopedItemWidth(float item_width) noexcept
: ScopeWrapper(true)
{
ImGui::PushItemWidth(item_width);
}
static void dtor() noexcept { ImGui::PopItemWidth(); }
};
struct ScopedDisabled
{
ScopedDisabled(bool disabled)
: disabled(disabled)
{
if (disabled)
ImGui::BeginDisabled(disabled);
}
~ScopedDisabled()
{
if (disabled)
ImGui::EndDisabled();
}
bool disabled;
};
//// Text helpers
// std::string helpers.
#ifndef DEAR_NO_STRING
static inline void Text(const tl::string& str) noexcept
{
ImGui::TextUnformatted(str.c_str(), str.c_str() + str.length());
}
inline void TextUnformatted(const tl::string& str) noexcept
{
ImGui::TextUnformatted(str.c_str(), str.c_str() + str.length());
}
#endif
static inline bool
MenuItem(const char* text, bool selected = false, bool enabled = true) noexcept
{
return ImGui::MenuItem(text, nullptr, selected, enabled);
}
static inline bool MenuItem(const char* text, bool* selected, bool enabled = true) noexcept
{
return ImGui::MenuItem(text, nullptr, selected, enabled);
}
#ifndef DEAR_NO_STRING
static inline bool MenuItem(const tl::string& str, const char* shortcut = nullptr,
bool selected = false, bool enabled = true) noexcept
{
return ImGui::MenuItem(str.c_str(), shortcut, selected, enabled);
}
static inline bool
MenuItem(const tl::string& text, bool* selected, bool enabled = true) noexcept
{
return ImGui::MenuItem(text.c_str(), nullptr, selected, enabled);
}
#endif
// static inline bool Selectable(const char *text) noexcept { return imgui::Selectable(text); }
static inline bool
Selectable(const char* label, bool selected = false, ImGuiSelectableFlags flags = 0,
const ImVec2& size = Zero) noexcept
{
return ImGui::Selectable(label, selected, flags, size);
}
static inline bool
Selectable(const char* label, bool* p_selected, ImGuiSelectableFlags flags = 0,
const ImVec2& size = Zero) noexcept
{
return ImGui::Selectable(label, p_selected, flags, size);
}
#ifndef DEAR_NO_STRING
static inline bool
Selectable(const tl::string& label, bool selected = false, ImGuiSelectableFlags flags = 0,
const ImVec2& size = Zero) noexcept
{
return ImGui::Selectable(label.c_str(), selected, flags, size);
}
static inline bool
Selectable(const tl::string& label, bool* p_selected, ImGuiSelectableFlags flags = 0,
const ImVec2& size = Zero) noexcept
{
return ImGui::Selectable(label.c_str(), p_selected, flags, size);
}
#endif
} // namespace dear
+25
View File
@@ -0,0 +1,25 @@
#pragma once
// "DEFER" macro "DEFER", for scheduling a function call for the end of the scope.
// E.g.
// DEFER(ImGui::End(););
// if (!ImGui::Begin("window"))
// return;
//
#define IMH_CONCAT_IMPL(s1, s2) s1##s2
#define IMH_CONCAT(s1, s2) IMH_CONCAT_IMPL(s1, s2)
#define DEFER(op) \
Deferral IMH_CONCAT(__deferral__, __LINE__) \
{ \
[]() { \
op \
} \
}
class Deferral
{
void (*mFn)();
public:
constexpr Deferral(void (*fn)()) noexcept : mFn(fn) {}
~Deferral() noexcept { mFn(); }
};
+47
View File
@@ -0,0 +1,47 @@
#pragma once
// define IMGUI_NOEXCEPT as 'noexcept' to enable noexcept behavior (requires compatible imgui.h)
#ifndef IMGUI_NOEXCEPT
# define IMGUI_NOEXCEPT
#endif
#include "IUI/ImGui/imgui.h"
#include <tl/functional.h>
#include <tl/optional.h>
using ImGuiWrapperReturnType = tl::optional<int>;
using ImGuiWrapperFn = tl::function<ImGuiWrapperReturnType()>;
// ImGuiWrapConfig describes the parameters of the main window created by imgui_main.
struct ImGuiWrapConfig
{
// windowTitle_ sets the initial name given to the main window.
const char* windowTitle_{"Application"};
// width_ and height_ control the initial dimensions of the main window.
template<typename T>
static constexpr T DefaultWidth = 1280;
template<typename T>
static constexpr T DefaultHeight = 720;
int width_{DefaultWidth<int>}, height_{DefaultHeight<int>};
// clearColor_ determines the clear/background color for the window.
// NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers)
ImVec4 clearColor_{0.45F, 0.55F, 0.60F, 1.00F};
// enableVsync_ enables vsync for the window.
bool enableVsync_;
// keyboardNav_ enables keyboard controls per ImGuiConfigFlags_NavEnableKeyboard;
bool keyboardNav_{true};
// startDark_ enables StyleColorsDark after creating the window.
bool startDark_{true};
};
// imgui_main implements a main-loop that constructs a GL window and calls the supplied
// mainFn every frame until the app is closed.
// See dear::SetHostWindowSize if your callback needs to change the GL window size.
extern int imgui_main(const ImGuiWrapConfig& config, const ImGuiWrapperFn& mainFn) noexcept;
+9
View File
@@ -0,0 +1,9 @@
#pragma once
#include "imguiwrap.h"
// DEPRECATED: I'm going to remove this in future.
#include "imguiwrap.defermacro.h"
// ImGui fails to provide these useful constants
constexpr int ImGuiTableFlags_SizingShift = 13;
constexpr int ImGuiTableFlags_SizingBits = 4;
File diff suppressed because it is too large Load Diff
+250
View File
@@ -0,0 +1,250 @@
// Crude implementation of JSON value object and parser.
//
// VERSION 0.1
//
// LICENSE
// This software is dual-licensed to the public domain and under the following
// license: you are granted a perpetual, irrevocable license to copy, modify,
// publish, and distribute this file as you see fit.
//
// CREDITS
// Written by Michal Cichon
# ifndef __CRUDE_JSON_H__
# define __CRUDE_JSON_H__
# pragma once
# include <type_traits>
# include <string>
# include <vector>
# include <map>
# include <cstddef>
# include <algorithm>
# include <sstream>
# ifndef CRUDE_ASSERT
# include <cassert>
# define CRUDE_ASSERT(expr) assert(expr)
# endif
# ifndef CRUDE_JSON_IO
# define CRUDE_JSON_IO 1
# endif
namespace crude_json {
struct value;
using string = std::string;
using object = std::map<string, value>;
using array = std::vector<value>;
using number = double;
using boolean = bool;
using null = std::nullptr_t;
enum class type_t
{
null,
object,
array,
string,
boolean,
number,
discarded
};
struct value
{
value(type_t type = type_t::null): m_Type(construct(m_Storage, type)) {}
value(value&& other);
value(const value& other);
value( null) : m_Type(construct(m_Storage, null())) {}
value( object&& v): m_Type(construct(m_Storage, std::move(v))) {}
value(const object& v): m_Type(construct(m_Storage, v)) {}
value( array&& v): m_Type(construct(m_Storage, std::move(v))) {}
value(const array& v): m_Type(construct(m_Storage, v)) {}
value( string&& v): m_Type(construct(m_Storage, std::move(v))) {}
value(const string& v): m_Type(construct(m_Storage, v)) {}
value(const char* v): m_Type(construct(m_Storage, v)) {}
value( boolean v): m_Type(construct(m_Storage, v)) {}
value( number v): m_Type(construct(m_Storage, v)) {}
~value() { destruct(m_Storage, m_Type); }
value& operator=(value&& other) { if (this != &other) { value(std::move(other)).swap(*this); } return *this; }
value& operator=(const value& other) { if (this != &other) { value( other).swap(*this); } return *this; }
value& operator=( null) { auto other = value( ); swap(other); return *this; }
value& operator=( object&& v) { auto other = value(std::move(v)); swap(other); return *this; }
value& operator=(const object& v) { auto other = value( v); swap(other); return *this; }
value& operator=( array&& v) { auto other = value(std::move(v)); swap(other); return *this; }
value& operator=(const array& v) { auto other = value( v); swap(other); return *this; }
value& operator=( string&& v) { auto other = value(std::move(v)); swap(other); return *this; }
value& operator=(const string& v) { auto other = value( v); swap(other); return *this; }
value& operator=(const char* v) { auto other = value( v); swap(other); return *this; }
value& operator=( boolean v) { auto other = value( v); swap(other); return *this; }
value& operator=( number v) { auto other = value( v); swap(other); return *this; }
type_t type() const { return m_Type; }
operator type_t() const { return m_Type; }
value& operator[](size_t index);
const value& operator[](size_t index) const;
value& operator[](const string& key);
const value& operator[](const string& key) const;
bool contains(const string& key) const;
void push_back(const value& value);
void push_back(value&& value);
size_t erase(const string& key);
bool is_primitive() const { return is_string() || is_number() || is_boolean() || is_null(); }
bool is_structured() const { return is_object() || is_array(); }
bool is_null() const { return m_Type == type_t::null; }
bool is_object() const { return m_Type == type_t::object; }
bool is_array() const { return m_Type == type_t::array; }
bool is_string() const { return m_Type == type_t::string; }
bool is_boolean() const { return m_Type == type_t::boolean; }
bool is_number() const { return m_Type == type_t::number; }
bool is_discarded() const { return m_Type == type_t::discarded; }
template <typename T> const T& get() const;
template <typename T> T& get();
template <typename T> const T* get_ptr() const;
template <typename T> T* get_ptr();
string dump(const int indent = -1, const char indent_char = ' ') const;
void swap(value& other);
inline friend void swap(value& lhs, value& rhs) { lhs.swap(rhs); }
// Returns discarded value for invalid inputs.
static value parse(const string& data);
# if CRUDE_JSON_IO
static std::pair<value, bool> load(const string& path);
bool save(const string& path, const int indent = -1, const char indent_char = ' ') const;
# endif
private:
struct parser;
// VS2015: std::max() is not constexpr yet.
# define CRUDE_MAX2(a, b) ((a) < (b) ? (b) : (a))
# define CRUDE_MAX3(a, b, c) CRUDE_MAX2(CRUDE_MAX2(a, b), c)
# define CRUDE_MAX4(a, b, c, d) CRUDE_MAX2(CRUDE_MAX3(a, b, c), d)
# define CRUDE_MAX5(a, b, c, d, e) CRUDE_MAX2(CRUDE_MAX4(a, b, c, d), e)
enum
{
max_size = CRUDE_MAX5( sizeof(string), sizeof(object), sizeof(array), sizeof(number), sizeof(boolean)),
max_align = CRUDE_MAX5(alignof(string), alignof(object), alignof(array), alignof(number), alignof(boolean))
};
# undef CRUDE_MAX5
# undef CRUDE_MAX4
# undef CRUDE_MAX3
# undef CRUDE_MAX2
using storage_t = std::aligned_storage<max_size, max_align>::type;
static object* object_ptr( storage_t& storage) { return reinterpret_cast< object*>(&storage); }
static const object* object_ptr(const storage_t& storage) { return reinterpret_cast<const object*>(&storage); }
static array* array_ptr( storage_t& storage) { return reinterpret_cast< array*>(&storage); }
static const array* array_ptr(const storage_t& storage) { return reinterpret_cast<const array*>(&storage); }
static string* string_ptr( storage_t& storage) { return reinterpret_cast< string*>(&storage); }
static const string* string_ptr(const storage_t& storage) { return reinterpret_cast<const string*>(&storage); }
static boolean* boolean_ptr( storage_t& storage) { return reinterpret_cast< boolean*>(&storage); }
static const boolean* boolean_ptr(const storage_t& storage) { return reinterpret_cast<const boolean*>(&storage); }
static number* number_ptr( storage_t& storage) { return reinterpret_cast< number*>(&storage); }
static const number* number_ptr(const storage_t& storage) { return reinterpret_cast<const number*>(&storage); }
static type_t construct(storage_t& storage, type_t type)
{
switch (type)
{
case type_t::object: new (&storage) object(); break;
case type_t::array: new (&storage) array(); break;
case type_t::string: new (&storage) string(); break;
case type_t::boolean: new (&storage) boolean(); break;
case type_t::number: new (&storage) number(); break;
default: break;
}
return type;
}
static type_t construct(storage_t& storage, null) { (void)storage; return type_t::null; }
static type_t construct(storage_t& storage, object&& value) { new (&storage) object(std::forward<object>(value)); return type_t::object; }
static type_t construct(storage_t& storage, const object& value) { new (&storage) object(value); return type_t::object; }
static type_t construct(storage_t& storage, array&& value) { new (&storage) array(std::forward<array>(value)); return type_t::array; }
static type_t construct(storage_t& storage, const array& value) { new (&storage) array(value); return type_t::array; }
static type_t construct(storage_t& storage, string&& value) { new (&storage) string(std::forward<string>(value)); return type_t::string; }
static type_t construct(storage_t& storage, const string& value) { new (&storage) string(value); return type_t::string; }
static type_t construct(storage_t& storage, const char* value) { new (&storage) string(value); return type_t::string; }
static type_t construct(storage_t& storage, boolean value) { new (&storage) boolean(value); return type_t::boolean; }
static type_t construct(storage_t& storage, number value) { new (&storage) number(value); return type_t::number; }
static void destruct(storage_t& storage, type_t type)
{
switch (type)
{
case type_t::object: object_ptr(storage)->~object(); break;
case type_t::array: array_ptr(storage)->~array(); break;
case type_t::string: string_ptr(storage)->~string(); break;
default: break;
}
}
struct dump_context_t
{
std::ostringstream out;
const int indent = -1;
const char indent_char = ' ';
// VS2015: Aggregate initialization isn't a thing yet.
dump_context_t(const int indent, const char indent_char)
: indent(indent)
, indent_char(indent_char)
{
}
void write_indent(int level);
void write_separator();
void write_newline();
};
void dump(dump_context_t& context, int level) const;
storage_t m_Storage;
type_t m_Type;
};
template <> inline const object& value::get<object>() const { CRUDE_ASSERT(m_Type == type_t::object); return *object_ptr(m_Storage); }
template <> inline const array& value::get<array>() const { CRUDE_ASSERT(m_Type == type_t::array); return *array_ptr(m_Storage); }
template <> inline const string& value::get<string>() const { CRUDE_ASSERT(m_Type == type_t::string); return *string_ptr(m_Storage); }
template <> inline const boolean& value::get<boolean>() const { CRUDE_ASSERT(m_Type == type_t::boolean); return *boolean_ptr(m_Storage); }
template <> inline const number& value::get<number>() const { CRUDE_ASSERT(m_Type == type_t::number); return *number_ptr(m_Storage); }
template <> inline object& value::get<object>() { CRUDE_ASSERT(m_Type == type_t::object); return *object_ptr(m_Storage); }
template <> inline array& value::get<array>() { CRUDE_ASSERT(m_Type == type_t::array); return *array_ptr(m_Storage); }
template <> inline string& value::get<string>() { CRUDE_ASSERT(m_Type == type_t::string); return *string_ptr(m_Storage); }
template <> inline boolean& value::get<boolean>() { CRUDE_ASSERT(m_Type == type_t::boolean); return *boolean_ptr(m_Storage); }
template <> inline number& value::get<number>() { CRUDE_ASSERT(m_Type == type_t::number); return *number_ptr(m_Storage); }
template <> inline const object* value::get_ptr<object>() const { if (m_Type == type_t::object) return object_ptr(m_Storage); else return nullptr; }
template <> inline const array* value::get_ptr<array>() const { if (m_Type == type_t::array) return array_ptr(m_Storage); else return nullptr; }
template <> inline const string* value::get_ptr<string>() const { if (m_Type == type_t::string) return string_ptr(m_Storage); else return nullptr; }
template <> inline const boolean* value::get_ptr<boolean>() const { if (m_Type == type_t::boolean) return boolean_ptr(m_Storage); else return nullptr; }
template <> inline const number* value::get_ptr<number>() const { if (m_Type == type_t::number) return number_ptr(m_Storage); else return nullptr; }
template <> inline object* value::get_ptr<object>() { if (m_Type == type_t::object) return object_ptr(m_Storage); else return nullptr; }
template <> inline array* value::get_ptr<array>() { if (m_Type == type_t::array) return array_ptr(m_Storage); else return nullptr; }
template <> inline string* value::get_ptr<string>() { if (m_Type == type_t::string) return string_ptr(m_Storage); else return nullptr; }
template <> inline boolean* value::get_ptr<boolean>() { if (m_Type == type_t::boolean) return boolean_ptr(m_Storage); else return nullptr; }
template <> inline number* value::get_ptr<number>() { if (m_Type == type_t::number) return number_ptr(m_Storage); else return nullptr; }
} // namespace crude_json
# endif // __CRUDE_JSON_H__
+144
View File
@@ -0,0 +1,144 @@
//------------------------------------------------------------------------------
// VERSION 0.1
//
// LICENSE
// This software is dual-licensed to the public domain and under the following
// license: you are granted a perpetual, irrevocable license to copy, modify,
// publish, and distribute this file as you see fit.
//
// CREDITS
// Written by Michal Cichon
//------------------------------------------------------------------------------
# ifndef __IMGUI_BEZIER_MATH_H__
# define __IMGUI_BEZIER_MATH_H__
# pragma once
//------------------------------------------------------------------------------
# include "imgui_extra_math.h"
//------------------------------------------------------------------------------
template <typename T>
struct ImCubicBezierPointsT
{
T P0;
T P1;
T P2;
T P3;
};
using ImCubicBezierPoints = ImCubicBezierPointsT<ImVec2>;
//------------------------------------------------------------------------------
// Low-level Bezier curve sampling.
template <typename T> inline T ImLinearBezier(const T& p0, const T& p1, float t);
template <typename T> inline T ImLinearBezierDt(const T& p0, const T& p1, float t);
template <typename T> inline T ImQuadraticBezier(const T& p0, const T& p1, const T& p2, float t);
template <typename T> inline T ImQuadraticBezierDt(const T& p0, const T& p1, const T& p2, float t);
template <typename T> inline T ImCubicBezier(const T& p0, const T& p1, const T& p2, const T& p3, float t);
template <typename T> inline T ImCubicBezierDt(const T& p0, const T& p1, const T& p2, const T& p3, float t);
// High-level Bezier sampling, automatically collapse to lower level Bezier curves if control points overlap.
template <typename T> inline T ImCubicBezierSample(const T& p0, const T& p1, const T& p2, const T& p3, float t);
template <typename T> inline T ImCubicBezierSample(const ImCubicBezierPointsT<T>& curve, float t);
template <typename T> inline T ImCubicBezierTangent(const T& p0, const T& p1, const T& p2, const T& p3, float t);
template <typename T> inline T ImCubicBezierTangent(const ImCubicBezierPointsT<T>& curve, float t);
// Calculate approximate length of Cubic Bezier curve.
template <typename T> inline float ImCubicBezierLength(const T& p0, const T& p1, const T& p2, const T& p3);
template <typename T> inline float ImCubicBezierLength(const ImCubicBezierPointsT<T>& curve);
// Splits Cubic Bezier curve into two curves.
template <typename T>
struct ImCubicBezierSplitResultT
{
ImCubicBezierPointsT<T> Left;
ImCubicBezierPointsT<T> Right;
};
using ImCubicBezierSplitResult = ImCubicBezierSplitResultT<ImVec2>;
template <typename T> inline ImCubicBezierSplitResultT<T> ImCubicBezierSplit(const T& p0, const T& p1, const T& p2, const T& p3, float t);
template <typename T> inline ImCubicBezierSplitResultT<T> ImCubicBezierSplit(const ImCubicBezierPointsT<T>& curve, float t);
// Returns bounding rectangle of Cubic Bezier curve.
inline ImRect ImCubicBezierBoundingRect(const ImVec2& p0, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3);
inline ImRect ImCubicBezierBoundingRect(const ImCubicBezierPoints& curve);
// Project point on Cubic Bezier curve.
struct ImProjectResult
{
ImVec2 Point; // Point on curve
float Time; // [0 - 1]
float Distance; // Distance to curve
};
inline ImProjectResult ImProjectOnCubicBezier(const ImVec2& p, const ImVec2& p0, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const int subdivisions = 100);
inline ImProjectResult ImProjectOnCubicBezier(const ImVec2& p, const ImCubicBezierPoints& curve, const int subdivisions = 100);
// Calculate intersection between line and a Cubic Bezier curve.
struct ImCubicBezierIntersectResult
{
int Count;
ImVec2 Points[3];
};
inline ImCubicBezierIntersectResult ImCubicBezierLineIntersect(const ImVec2& p0, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& a0, const ImVec2& a1);
inline ImCubicBezierIntersectResult ImCubicBezierLineIntersect(const ImCubicBezierPoints& curve, const ImLine& line);
// Adaptive Cubic Bezier subdivision.
enum ImCubicBezierSubdivideFlags
{
ImCubicBezierSubdivide_None = 0,
ImCubicBezierSubdivide_SkipFirst = 1
};
struct ImCubicBezierSubdivideSample
{
ImVec2 Point;
ImVec2 Tangent;
};
using ImCubicBezierSubdivideCallback = void (*)(const ImCubicBezierSubdivideSample& p, void* user_pointer);
inline void ImCubicBezierSubdivide(ImCubicBezierSubdivideCallback callback, void* user_pointer, const ImVec2& p0, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, float tess_tol = -1.0f, ImCubicBezierSubdivideFlags flags = ImCubicBezierSubdivide_None);
inline void ImCubicBezierSubdivide(ImCubicBezierSubdivideCallback callback, void* user_pointer, const ImCubicBezierPoints& curve, float tess_tol = -1.0f, ImCubicBezierSubdivideFlags flags = ImCubicBezierSubdivide_None);
// F has signature void(const ImCubicBezierSubdivideSample& p)
template <typename F> inline void ImCubicBezierSubdivide(F& callback, const ImVec2& p0, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, float tess_tol = -1.0f, ImCubicBezierSubdivideFlags flags = ImCubicBezierSubdivide_None);
template <typename F> inline void ImCubicBezierSubdivide(F& callback, const ImCubicBezierPoints& curve, float tess_tol = -1.0f, ImCubicBezierSubdivideFlags flags = ImCubicBezierSubdivide_None);
// Fixed step Cubic Bezier subdivision.
struct ImCubicBezierFixedStepSample
{
float T;
float Length;
ImVec2 Point;
bool BreakSearch;
};
using ImCubicBezierFixedStepCallback = void (*)(ImCubicBezierFixedStepSample& sample, void* user_pointer);
inline void ImCubicBezierFixedStep(ImCubicBezierFixedStepCallback callback, void* user_pointer, const ImVec2& p0, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, float step, bool overshoot = false, float max_value_error = 1e-3f, float max_t_error = 1e-5f);
inline void ImCubicBezierFixedStep(ImCubicBezierFixedStepCallback callback, void* user_pointer, const ImCubicBezierPoints& curve, float step, bool overshoot = false, float max_value_error = 1e-3f, float max_t_error = 1e-5f);
// F has signature void(const ImCubicBezierFixedStepSample& p)
template <typename F> inline void ImCubicBezierFixedStep(F& callback, const ImVec2& p0, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, float step, bool overshoot = false, float max_value_error = 1e-3f, float max_t_error = 1e-5f);
template <typename F> inline void ImCubicBezierFixedStep(F& callback, const ImCubicBezierPoints& curve, float step, bool overshoot = false, float max_value_error = 1e-3f, float max_t_error = 1e-5f);
//------------------------------------------------------------------------------
# include "imgui_bezier_math.inl"
//------------------------------------------------------------------------------
# endif // __IMGUI_BEZIER_MATH_H__
+677
View File
@@ -0,0 +1,677 @@
//------------------------------------------------------------------------------
// VERSION 0.1
//
// LICENSE
// This software is dual-licensed to the public domain and under the following
// license: you are granted a perpetual, irrevocable license to copy, modify,
// publish, and distribute this file as you see fit.
//
// CREDITS
// Written by Michal Cichon
//------------------------------------------------------------------------------
# ifndef __IMGUI_BEZIER_MATH_INL__
# define __IMGUI_BEZIER_MATH_INL__
# pragma once
//------------------------------------------------------------------------------
# include "imgui_bezier_math.h"
# include <map> // used in ImCubicBezierFixedStep
#include "tl/narrow_cast.h"
//------------------------------------------------------------------------------
template <typename T>
inline T ImLinearBezier(const T& p0, const T& p1, float t)
{
return p0 + t * (p1 - p0);
}
template <typename T>
inline T ImLinearBezierDt(const T& p0, const T& p1, float t)
{
IM_UNUSED(t);
return p1 - p0;
}
template <typename T>
inline T ImQuadraticBezier(const T& p0, const T& p1, const T& p2, float t)
{
const auto a = 1 - t;
return a * a * p0 + 2 * t * a * p1 + t * t * p2;
}
template <typename T>
inline T ImQuadraticBezierDt(const T& p0, const T& p1, const T& p2, float t)
{
return 2 * (1 - t) * (p1 - p0) + 2 * t * (p2 - p1);
}
template <typename T>
inline T ImCubicBezier(const T& p0, const T& p1, const T& p2, const T& p3, float t)
{
const auto a = 1 - t;
const auto b = a * a * a;
const auto c = t * t * t;
return b * p0 + 3 * t * a * a * p1 + 3 * t * t * a * p2 + c * p3;
}
template <typename T>
inline T ImCubicBezierDt(const T& p0, const T& p1, const T& p2, const T& p3, float t)
{
const auto a = 1 - t;
const auto b = a * a;
const auto c = t * t;
const auto d = 2 * t * a;
return -3 * p0 * b + 3 * p1 * (b - d) + 3 * p2 * (d - c) + 3 * p3 * c;
}
template <typename T>
inline T ImCubicBezierSample(const T& p0, const T& p1, const T& p2, const T& p3, float t)
{
const auto cp0_zero = ImLengthSqr(p1 - p0) < 1e-5f;
const auto cp1_zero = ImLengthSqr(p3 - p2) < 1e-5f;
if (cp0_zero && cp1_zero)
return ImLinearBezier(p0, p3, t);
else if (cp0_zero)
return ImQuadraticBezier(p0, p2, p3, t);
else if (cp1_zero)
return ImQuadraticBezier(p0, p1, p3, t);
else
return ImCubicBezier(p0, p1, p2, p3, t);
}
template <typename T>
inline T ImCubicBezierSample(const ImCubicBezierPointsT<T>& curve, float t)
{
return ImCubicBezierSample(curve.P0, curve.P1, curve.P2, curve.P3, t);
}
template <typename T>
inline T ImCubicBezierTangent(const T& p0, const T& p1, const T& p2, const T& p3, float t)
{
const auto cp0_zero = ImLengthSqr(p1 - p0) < 1e-5f;
const auto cp1_zero = ImLengthSqr(p3 - p2) < 1e-5f;
if (cp0_zero && cp1_zero)
return ImLinearBezierDt(p0, p3, t);
else if (cp0_zero)
return ImQuadraticBezierDt(p0, p2, p3, t);
else if (cp1_zero)
return ImQuadraticBezierDt(p0, p1, p3, t);
else
return ImCubicBezierDt(p0, p1, p2, p3, t);
}
template <typename T>
inline T ImCubicBezierTangent(const ImCubicBezierPointsT<T>& curve, float t)
{
return ImCubicBezierTangent(curve.P0, curve.P1, curve.P2, curve.P3, t);
}
template <typename T>
inline float ImCubicBezierLength(const T& p0, const T& p1, const T& p2, const T& p3)
{
// Legendre-Gauss abscissae with n=24 (x_i values, defined at i=n as the roots of the nth order Legendre polynomial Pn(x))
static const float t_values[] =
{
-0.0640568928626056260850430826247450385909f,
0.0640568928626056260850430826247450385909f,
-0.1911188674736163091586398207570696318404f,
0.1911188674736163091586398207570696318404f,
-0.3150426796961633743867932913198102407864f,
0.3150426796961633743867932913198102407864f,
-0.4337935076260451384870842319133497124524f,
0.4337935076260451384870842319133497124524f,
-0.5454214713888395356583756172183723700107f,
0.5454214713888395356583756172183723700107f,
-0.6480936519369755692524957869107476266696f,
0.6480936519369755692524957869107476266696f,
-0.7401241915785543642438281030999784255232f,
0.7401241915785543642438281030999784255232f,
-0.8200019859739029219539498726697452080761f,
0.8200019859739029219539498726697452080761f,
-0.8864155270044010342131543419821967550873f,
0.8864155270044010342131543419821967550873f,
-0.9382745520027327585236490017087214496548f,
0.9382745520027327585236490017087214496548f,
-0.9747285559713094981983919930081690617411f,
0.9747285559713094981983919930081690617411f,
-0.9951872199970213601799974097007368118745f,
0.9951872199970213601799974097007368118745f
};
// Legendre-Gauss weights with n=24 (w_i values, defined by a function linked to in the Bezier primer article)
static const float c_values[] =
{
0.1279381953467521569740561652246953718517f,
0.1279381953467521569740561652246953718517f,
0.1258374563468282961213753825111836887264f,
0.1258374563468282961213753825111836887264f,
0.1216704729278033912044631534762624256070f,
0.1216704729278033912044631534762624256070f,
0.1155056680537256013533444839067835598622f,
0.1155056680537256013533444839067835598622f,
0.1074442701159656347825773424466062227946f,
0.1074442701159656347825773424466062227946f,
0.0976186521041138882698806644642471544279f,
0.0976186521041138882698806644642471544279f,
0.0861901615319532759171852029837426671850f,
0.0861901615319532759171852029837426671850f,
0.0733464814110803057340336152531165181193f,
0.0733464814110803057340336152531165181193f,
0.0592985849154367807463677585001085845412f,
0.0592985849154367807463677585001085845412f,
0.0442774388174198061686027482113382288593f,
0.0442774388174198061686027482113382288593f,
0.0285313886289336631813078159518782864491f,
0.0285313886289336631813078159518782864491f,
0.0123412297999871995468056670700372915759f,
0.0123412297999871995468056670700372915759f
};
static_assert(sizeof(t_values) / sizeof(*t_values) == sizeof(c_values) / sizeof(*c_values), "");
auto arc = [p0, p1, p2, p3](float t)
{
const auto p = ImCubicBezierDt(p0, p1, p2, p3, t);
const auto l = ImLength(p);
return l;
};
const auto z = 0.5f;
const auto n = sizeof(t_values) / sizeof(*t_values);
auto accumulator = 0.0f;
for (size_t i = 0; i < n; ++i)
{
const auto t = z * t_values[i] + z;
accumulator += c_values[i] * arc(t);
}
return z * accumulator;
}
template <typename T>
inline float ImCubicBezierLength(const ImCubicBezierPointsT<T>& curve)
{
return ImCubicBezierLength(curve.P0, curve.P1, curve.P2, curve.P3);
}
template <typename T>
inline ImCubicBezierSplitResultT<T> ImCubicBezierSplit(const T& p0, const T& p1, const T& p2, const T& p3, float t)
{
const auto z1 = t;
const auto z2 = z1 * z1;
const auto z3 = z1 * z1 * z1;
const auto s1 = z1 - 1;
const auto s2 = s1 * s1;
const auto s3 = s1 * s1 * s1;
return ImCubicBezierSplitResultT<T>
{
ImCubicBezierPointsT<T>
{
p0,
z1 * p1 - s1 * p0,
z2 * p2 - 2 * z1 * s1 * p1 + s2 * p0,
z3 * p3 - 3 * z2 * s1 * p2 + 3 * z1 * s2 * p1 - s3 * p0
},
ImCubicBezierPointsT<T>
{
z3 * p0 - 3 * z2 * s1 * p1 + 3 * z1 * s2 * p2 - s3 * p3,
z2 * p1 - 2 * z1 * s1 * p2 + s2 * p3,
z1 * p2 - s1 * p3,
p3,
}
};
}
template <typename T>
inline ImCubicBezierSplitResultT<T> ImCubicBezierSplit(const ImCubicBezierPointsT<T>& curve, float t)
{
return ImCubicBezierSplit(curve.P0, curve.P1, curve.P2, curve.P3, t);
}
inline ImRect ImCubicBezierBoundingRect(const ImVec2& p0, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3)
{
auto a = 3 * p3 - 9 * p2 + 9 * p1 - 3 * p0;
auto b = 6 * p0 - 12 * p1 + 6 * p2;
auto c = 3 * p1 - 3 * p0;
auto delta_squared = ImMul(b, b) - 4 * ImMul(a, c);
auto tl = ImMin(p0, p3);
auto rb = ImMax(p0, p3);
# define IM_VEC2_INDEX(v, i) *(&v.x + i)
for (int i = 0; i < 2; ++i)
{
if (IM_VEC2_INDEX(a, i) == 0.0f)
continue;
if (IM_VEC2_INDEX(delta_squared, i) >= 0)
{
auto delta = ImSqrt(IM_VEC2_INDEX(delta_squared, i));
auto t0 = (-IM_VEC2_INDEX(b, i) + delta) / (2 * IM_VEC2_INDEX(a, i));
if (t0 > 0 && t0 < 1)
{
auto p = ImCubicBezier(IM_VEC2_INDEX(p0, i), IM_VEC2_INDEX(p1, i), IM_VEC2_INDEX(p2, i), IM_VEC2_INDEX(p3, i), t0);
IM_VEC2_INDEX(tl, i) = ImMin(IM_VEC2_INDEX(tl, i), p);
IM_VEC2_INDEX(rb, i) = ImMax(IM_VEC2_INDEX(rb, i), p);
}
auto t1 = (-IM_VEC2_INDEX(b, i) - delta) / (2 * IM_VEC2_INDEX(a, i));
if (t1 > 0 && t1 < 1)
{
auto p = ImCubicBezier(IM_VEC2_INDEX(p0, i), IM_VEC2_INDEX(p1, i), IM_VEC2_INDEX(p2, i), IM_VEC2_INDEX(p3, i), t1);
IM_VEC2_INDEX(tl, i) = ImMin(IM_VEC2_INDEX(tl, i), p);
IM_VEC2_INDEX(rb, i) = ImMax(IM_VEC2_INDEX(rb, i), p);
}
}
}
# undef IM_VEC2_INDEX
return ImRect(tl, rb);
}
inline ImRect ImCubicBezierBoundingRect(const ImCubicBezierPoints& curve)
{
return ImCubicBezierBoundingRect(curve.P0, curve.P1, curve.P2, curve.P3);
}
inline ImProjectResult ImProjectOnCubicBezier(const ImVec2& point, const ImVec2& p0, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const int subdivisions)
{
// http://pomax.github.io/bezierinfo/#projections
const float epsilon = 1e-5f;
const float fixed_step = 1.0f / static_cast<float>(subdivisions - 1);
ImProjectResult result;
result.Point = point;
result.Time = 0.0f;
result.Distance = FLT_MAX;
// Step 1: Coarse check
for (int i = 0; i < subdivisions; ++i)
{
auto t = i * fixed_step;
auto p = ImCubicBezier(p0, p1, p2, p3, t);
auto s = point - p;
auto d = ImDot(s, s);
if (d < result.Distance)
{
result.Point = p;
result.Time = t;
result.Distance = d;
}
}
if (result.Time == 0.0f || ImFabs(result.Time - 1.0f) <= epsilon)
{
result.Distance = ImSqrt(result.Distance);
return result;
}
// Step 2: Fine check
auto left = result.Time - fixed_step;
auto right = result.Time + fixed_step;
auto step = fixed_step * 0.1f;
for (auto t = left; t < right + step; t += step)
{
auto p = ImCubicBezier(p0, p1, p2, p3, t);
auto s = point - p;
auto d = ImDot(s, s);
if (d < result.Distance)
{
result.Point = p;
result.Time = t;
result.Distance = d;
}
}
result.Distance = ImSqrt(result.Distance);
return result;
}
inline ImProjectResult ImProjectOnCubicBezier(const ImVec2& p, const ImCubicBezierPoints& curve, const int subdivisions)
{
return ImProjectOnCubicBezier(p, curve.P0, curve.P1, curve.P2, curve.P3, subdivisions);
}
inline ImCubicBezierIntersectResult ImCubicBezierLineIntersect(const ImVec2& p0, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& a0, const ImVec2& a1)
{
auto cubic_roots = [](float a, float b, float c, float d, float* roots) -> int
{
int count = 0;
auto sign = [](float x) -> float { return x < 0 ? -1.0f : 1.0f; };
auto A = b / a;
auto B = c / a;
auto C = d / a;
auto Q = (3 * B - ImPow(A, 2)) / 9;
auto R = (9 * A * B - 27 * C - 2 * ImPow(A, 3)) / 54;
auto D = ImPow(Q, 3) + ImPow(R, 2); // polynomial discriminant
if (D >= 0) // complex or duplicate roots
{
auto S = sign(R + ImSqrt(D)) * ImPow(ImFabs(R + ImSqrt(D)), (1.0f / 3.0f));
auto T = sign(R - ImSqrt(D)) * ImPow(ImFabs(R - ImSqrt(D)), (1.0f / 3.0f));
roots[0] = -A / 3 + (S + T); // real root
roots[1] = -A / 3 - (S + T) / 2; // real part of complex root
roots[2] = -A / 3 - (S + T) / 2; // real part of complex root
auto Im = ImFabs(ImSqrt(3) * (S - T) / 2); // complex part of root pair
// discard complex roots
if (Im != 0)
count = 1;
else
count = 3;
}
else // distinct real roots
{
auto th = ImAcos(R / ImSqrt(-ImPow(Q, 3)));
roots[0] = 2 * ImSqrt(-Q) * ImCos(th / 3) - A / 3;
roots[1] = 2 * ImSqrt(-Q) * ImCos((th + 2 * IM_PI) / 3) - A / 3;
roots[2] = 2 * ImSqrt(-Q) * ImCos((th + 4 * IM_PI) / 3) - A / 3;
count = 3;
}
return count;
};
// https://github.com/kaishiqi/Geometric-Bezier/blob/master/GeometricBezier/src/kaishiqi/geometric/intersection/Intersection.as
//
// Start with Bezier using Bernstein polynomials for weighting functions:
// (1-t^3)P0 + 3t(1-t)^2P1 + 3t^2(1-t)P2 + t^3P3
//
// Expand and collect terms to form linear combinations of original Bezier
// controls. This ends up with a vector cubic in t:
// (-P0+3P1-3P2+P3)t^3 + (3P0-6P1+3P2)t^2 + (-3P0+3P1)t + P0
// /\ /\ /\ /\
// || || || ||
// c3 c2 c1 c0
// Calculate the coefficients
auto c3 = -p0 + 3 * p1 - 3 * p2 + p3;
auto c2 = 3 * p0 - 6 * p1 + 3 * p2;
auto c1 = -3 * p0 + 3 * p1;
auto c0 = p0;
// Convert line to normal form: ax + by + c = 0
auto a = a1.y - a0.y;
auto b = a0.x - a1.x;
auto c = a0.x * (a0.y - a1.y) + a0.y * (a1.x - a0.x);
// Rotate each cubic coefficient using line for new coordinate system?
// Find roots of rotated cubic
float roots[3];
auto rootCount = cubic_roots(
a * c3.x + b * c3.y,
a * c2.x + b * c2.y,
a * c1.x + b * c1.y,
a * c0.x + b * c0.y + c,
roots);
// Any roots in closed interval [0,1] are intersections on Bezier, but
// might not be on the line segment.
// Find intersections and calculate point coordinates
auto min = ImMin(a0, a1);
auto max = ImMax(a0, a1);
ImCubicBezierIntersectResult result;
auto points = result.Points;
for (int i = 0; i < rootCount; ++i)
{
auto root = roots[i];
if (0 <= root && root <= 1)
{
// We're within the Bezier curve
// Find point on Bezier
auto p = ImCubicBezier(p0, p1, p2, p3, root);
// See if point is on line segment
// Had to make special cases for vertical and horizontal lines due
// to slight errors in calculation of p00
if (a0.x == a1.x)
{
if (min.y <= p.y && p.y <= max.y)
*points++ = p;
}
else if (a0.y == a1.y)
{
if (min.x <= p.x && p.x <= max.x)
*points++ = p;
}
else if (p.x >= min.x && p.y >= min.y && p.x <= max.x && p.y <= max.y)
{
*points++ = p;
}
}
}
result.Count = tl::narrow<int>(points - result.Points);
return result;
}
inline ImCubicBezierIntersectResult ImCubicBezierLineIntersect(const ImCubicBezierPoints& curve, const ImLine& line)
{
return ImCubicBezierLineIntersect(curve.P0, curve.P1, curve.P2, curve.P3, line.A, line.B);
}
inline void ImCubicBezierSubdivide(ImCubicBezierSubdivideCallback callback, void* user_pointer, const ImVec2& p0, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, float tess_tol, ImCubicBezierSubdivideFlags flags)
{
return ImCubicBezierSubdivide(callback, user_pointer, ImCubicBezierPoints{ p0, p1, p2, p3 }, tess_tol, flags);
}
inline void ImCubicBezierSubdivide(ImCubicBezierSubdivideCallback callback, void* user_pointer, const ImCubicBezierPoints& curve, float tess_tol, ImCubicBezierSubdivideFlags flags)
{
struct Tesselator
{
ImCubicBezierSubdivideCallback Callback;
void* UserPointer;
float TesselationTollerance;
ImCubicBezierSubdivideFlags Flags;
void Commit(const ImVec2& p, const ImVec2& t)
{
ImCubicBezierSubdivideSample sample;
sample.Point = p;
sample.Tangent = t;
Callback(sample, UserPointer);
}
void Subdivide(const ImCubicBezierPoints& curve, int level = 0)
{
float dx = curve.P3.x - curve.P0.x;
float dy = curve.P3.y - curve.P0.y;
float d2 = ((curve.P1.x - curve.P3.x) * dy - (curve.P1.y - curve.P3.y) * dx);
float d3 = ((curve.P2.x - curve.P3.x) * dy - (curve.P2.y - curve.P3.y) * dx);
d2 = (d2 >= 0) ? d2 : -d2;
d3 = (d3 >= 0) ? d3 : -d3;
if ((d2 + d3) * (d2 + d3) < TesselationTollerance * (dx * dx + dy * dy))
{
Commit(curve.P3, ImCubicBezierTangent(curve, 1.0f));
}
else if (level < 10)
{
const auto p12 = (curve.P0 + curve.P1) * 0.5f;
const auto p23 = (curve.P1 + curve.P2) * 0.5f;
const auto p34 = (curve.P2 + curve.P3) * 0.5f;
const auto p123 = (p12 + p23) * 0.5f;
const auto p234 = (p23 + p34) * 0.5f;
const auto p1234 = (p123 + p234) * 0.5f;
Subdivide(ImCubicBezierPoints { curve.P0, p12, p123, p1234 }, level + 1);
Subdivide(ImCubicBezierPoints { p1234, p234, p34, curve.P3 }, level + 1);
}
}
};
if (tess_tol < 0)
tess_tol = 1.118f; // sqrtf(1.25f)
Tesselator tesselator;
tesselator.Callback = callback;
tesselator.UserPointer = user_pointer;
tesselator.TesselationTollerance = tess_tol * tess_tol;
tesselator.Flags = flags;
if (!(tesselator.Flags & ImCubicBezierSubdivide_SkipFirst))
tesselator.Commit(curve.P0, ImCubicBezierTangent(curve, 0.0f));
tesselator.Subdivide(curve, 0);
}
template <typename F> inline void ImCubicBezierSubdivide(F& callback, const ImVec2& p0, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, float tess_tol, ImCubicBezierSubdivideFlags flags)
{
auto handler = [](const ImCubicBezierSubdivideSample& p, void* user_pointer)
{
auto& callback = *reinterpret_cast<F*>(user_pointer);
callback(p);
};
ImCubicBezierSubdivide(handler, &callback, ImCubicBezierPoints{ p0, p1, p2, p3 }, tess_tol, flags);
}
template <typename F> inline void ImCubicBezierSubdivide(F& callback, const ImCubicBezierPoints& curve, float tess_tol, ImCubicBezierSubdivideFlags flags)
{
auto handler = [](const ImCubicBezierSubdivideSample& p, void* user_pointer)
{
auto& callback = *reinterpret_cast<F*>(user_pointer);
callback(p);
};
ImCubicBezierSubdivide(handler, &callback, curve, tess_tol, flags);
}
inline void ImCubicBezierFixedStep(ImCubicBezierFixedStepCallback callback, void* user_pointer, const ImVec2& p0, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, float step, bool overshoot, float max_value_error, float max_t_error)
{
if (step <= 0.0f || !callback || max_value_error <= 0 || max_t_error <= 0)
return;
ImCubicBezierFixedStepSample sample;
sample.T = 0.0f;
sample.Length = 0.0f;
sample.Point = p0;
sample.BreakSearch = false;
callback(sample, user_pointer);
if (sample.BreakSearch)
return;
const auto total_length = ImCubicBezierLength(p0, p1, p2, p3);
const auto point_count = tl::narrow<int>(total_length / step) + (overshoot ? 2 : 1);
const auto t_min = 0.0f;
const auto t_max = step * point_count / total_length;
const auto t_0 = (t_min + t_max) * 0.5f;
// #todo: replace map with ImVector + binary search
std::map<float, float> cache;
for (int point_index = 1; point_index < point_count; ++point_index)
{
const auto targetLength = point_index * step;
float t_start = t_min;
float t_end = t_max;
float t = t_0;
float t_best = t;
float error_best = total_length;
while (true)
{
auto cacheIt = cache.find(t);
if (cacheIt == cache.end())
{
const auto front = ImCubicBezierSplit(p0, p1, p2, p3, t).Left;
const auto split_length = ImCubicBezierLength(front);
cacheIt = cache.emplace(t, split_length).first;
}
const auto length = cacheIt->second;
const auto error = targetLength - length;
if (error < error_best)
{
error_best = error;
t_best = t;
}
if (ImFabs(error) <= max_value_error || ImFabs(t_start - t_end) <= max_t_error)
{
sample.T = t;
sample.Length = length;
sample.Point = ImCubicBezier(p0, p1, p2, p3, t);
callback(sample, user_pointer);
if (sample.BreakSearch)
return;
break;
}
else if (error < 0.0f)
t_end = t;
else // if (error > 0.0f)
t_start = t;
t = (t_start + t_end) * 0.5f;
}
}
}
inline void ImCubicBezierFixedStep(ImCubicBezierFixedStepCallback callback, void* user_pointer, const ImCubicBezierPoints& curve, float step, bool overshoot, float max_value_error, float max_t_error)
{
ImCubicBezierFixedStep(callback, user_pointer, curve.P0, curve.P1, curve.P2, curve.P3, step, overshoot, max_value_error, max_t_error);
}
// F has signature void(const ImCubicBezierFixedStepSample& p)
template <typename F>
inline void ImCubicBezierFixedStep(F& callback, const ImVec2& p0, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, float step, bool overshoot, float max_value_error, float max_t_error)
{
auto handler = [](ImCubicBezierFixedStepSample& sample, void* user_pointer)
{
auto& callback = *reinterpret_cast<F*>(user_pointer);
callback(sample);
};
ImCubicBezierFixedStep(handler, &callback, p0, p1, p2, p3, step, overshoot, max_value_error, max_t_error);
}
template <typename F>
inline void ImCubicBezierFixedStep(F& callback, const ImCubicBezierPoints& curve, float step, bool overshoot, float max_value_error, float max_t_error)
{
auto handler = [](ImCubicBezierFixedStepSample& sample, void* user_pointer)
{
auto& callback = *reinterpret_cast<F*>(user_pointer);
callback(sample);
};
ImCubicBezierFixedStep(handler, &callback, curve.P0, curve.P1, curve.P2, curve.P3, step, overshoot, max_value_error, max_t_error);
}
//------------------------------------------------------------------------------
# endif // __IMGUI_BEZIER_MATH_INL__
+268
View File
@@ -0,0 +1,268 @@
// Canvas widget - view over infinite virtual space.
//
// Canvas allows you to draw your widgets anywhere over infinite space and provide
// view over it with support for panning and scaling.
//
// When you enter a canvas ImGui is moved to virtual space which mean:
// - ImGui::GetCursorScreenPos() return (0, 0) and which correspond to top left corner
// of the canvas on the screen (this can be changed using CanvasView()).
// - Mouse input is brought to canvas space, so widgets works as usual.
// - Everything you draw with ImDrawList will be in virtual space.
//
// By default origin point is on top left corner of canvas widget. It can be
// changed with call to CanvasView() where you can specify what part of space
// should be viewed by setting viewport origin point and scale. Current state
// can be queried with CanvasViewOrigin() and CanvasViewScale().
//
// Viewport size is controlled by 'size' parameter in BeginCanvas(). You can query
// it using CanvasContentMin/Max/Size functions. They are useful if you to not specify
// canvas size in which case all free space is used.
//
// Bounds of visible region of infinite space can be queried using CanvasViewMin/Max/Size
// functions. Everything that is drawn outside of this region will be clipped
// as usual in ImGui.
//
// While drawing inside canvas you can translate position from world (usual ImGui space)
// to virtual space and back using CanvasFromWorld()/CanvasToWorld().
//
// Canvas can be nested in each other (they are regular widgets after all). There
// is a way to transform position between current and parent canvas with
// CanvasFromParent()/CanvasToParent().
//
// Sometimes in more elaborate scenarios you want to move out canvas virtual space,
// do something and came back. You can do that with SuspendCanvas() and ResumeCanvas().
//
// Note:
// It is not valid to call canvas API outside of BeginCanvas() / EndCanvas() scope.
//
// VERSION 0.1
//
// LICENSE
// This software is dual-licensed to the public domain and under the following
// license: you are granted a perpetual, irrevocable license to copy, modify,
// publish, and distribute this file as you see fit.
//
// CREDITS
// Written by Michal Cichon
# ifndef __IMGUI_EX_CANVAS_H__
# define __IMGUI_EX_CANVAS_H__
# pragma once
# include <IUI/ImGui/imgui.h>
# include <IUI/ImGui/imgui_internal.h> // ImRect, ImFloor
namespace ImGuiEx {
struct CanvasView
{
ImVec2 Origin;
float Scale = 1.0f;
float InvScale = 1.0f;
CanvasView() = default;
CanvasView(const ImVec2& origin, float scale)
: Origin(origin)
, Scale(scale)
, InvScale(scale ? 1.0f / scale : 0.0f)
{
}
void Set(const ImVec2& origin, float scale)
{
*this = CanvasView(origin, scale);
}
};
// Canvas widget represent view over infinite plane.
//
// It acts like a child window without scroll bars with
// ability to zoom to specific part of canvas plane.
//
// Widgets are clipped according to current view exactly
// same way ImGui do. To avoid `missing widgets` artifacts first
// setup visible region with SetView() then draw content.
//
// Everything drawn with ImDrawList betwen calls to Begin()/End()
// will be drawn on canvas plane. This behavior can be suspended
// by calling Suspend() and resumed by calling Resume().
//
// Warning:
// Please do not interleave canvas with use of channel splitter.
// Keep channel splitter contained inside canvas or always
// call canvas functions from same channel.
struct Canvas
{
// Begins drawing content of canvas plane.
//
// When false is returned that mean canvas is not visible to the
// user can drawing should be skipped and End() not called.
// When true is returned drawing must be ended with call to End().
//
// If any size component is equal to zero or less canvas will
// automatically expand to all available area on that axis.
// So (0, 300) will take horizontal space and have height
// of 300 points. (0, 0) will take all remaining space of
// the window.
//
// You can query size of the canvas while it is being drawn
// by calling Rect().
bool Begin(const char* id, const ImVec2& size);
bool Begin(ImGuiID id, const ImVec2& size);
// Ends interaction with canvas plane.
//
// Must be called only when Begin() retuned true.
void End();
// Sets visible region of canvas plane.
//
// Origin is an offset of infinite plane origin from top left
// corner of the canvas.
//
// Scale greater than 1 make canvas content be bigger, less than 1 smaller.
void SetView(const ImVec2& origin, float scale);
void SetView(const CanvasView& view);
// Centers view over specific point on canvas plane.
//
// View will be centered on specific point by changing origin
// but not scale.
void CenterView(const ImVec2& canvasPoint);
// Calculates view over specific point on canvas plane.
CanvasView CalcCenterView(const ImVec2& canvasPoint) const;
// Centers view over specific rectangle on canvas plane.
//
// Whole rectangle will fit in canvas view. This will affect both
// origin and scale.
void CenterView(const ImRect& canvasRect);
// Calculates view over specific rectangle on canvas plane.
CanvasView CalcCenterView(const ImRect& canvasRect) const;
// Suspends canvas by returning to normal ImGui transformation space.
// While suspended UI will not be drawn on canvas plane.
//
// Calls to Suspend()/Resume() are symetrical. Each call to Suspend()
// must be matched with call to Resume().
void Suspend();
void Resume();
// Transforms point from canvas plane to ImGui.
ImVec2 FromLocal(const ImVec2& point) const;
ImVec2 FromLocal(const ImVec2& point, const CanvasView& view) const;
// Transforms vector from canvas plant to ImGui.
ImVec2 FromLocalV(const ImVec2& vector) const;
ImVec2 FromLocalV(const ImVec2& vector, const CanvasView& view) const;
// Transforms point from ImGui to canvas plane.
ImVec2 ToLocal(const ImVec2& point) const;
ImVec2 ToLocal(const ImVec2& point, const CanvasView& view) const;
// Transforms vector from ImGui to canvas plane.
ImVec2 ToLocalV(const ImVec2& vector) const;
ImVec2 ToLocalV(const ImVec2& vector, const CanvasView& view) const;
// Returns widget bounds.
//
// Note:
// Rect is valid after call to Begin().
const ImRect& Rect() const { return m_WidgetRect; }
// Returns visible region on canvas plane (in canvas plane coordinates).
const ImRect& ViewRect() const { return m_ViewRect; }
// Calculates visible region for view.
ImRect CalcViewRect(const CanvasView& view) const;
// Returns current view.
const CanvasView& View() const { return m_View; }
// Returns origin of the view.
//
// Origin is an offset of infinite plane origin from top left
// corner of the canvas.
const ImVec2& ViewOrigin() const { return m_View.Origin; }
// Returns scale of the view.
float ViewScale() const { return m_View.Scale; }
// Returns true if canvas is suspended.
//
// See: Suspend()/Resume()
bool IsSuspended() const { return m_SuspendCounter > 0; }
private:
# define IMGUI_EX_CANVAS_DEFERED() 0
# if IMGUI_EX_CANVAS_DEFERED()
struct Range
{
int BeginVertexIndex = 0;
int EndVertexIndex = 0;
int BeginComandIndex = 0;
int EndCommandIndex = 0;
};
# endif
void UpdateViewTransformPosition();
void SaveInputState();
void RestoreInputState();
void SaveViewportState();
void RestoreViewportState();
void EnterLocalSpace();
void LeaveLocalSpace();
bool m_InBeginEnd = false;
ImVec2 m_WidgetPosition;
ImVec2 m_WidgetSize;
ImRect m_WidgetRect;
ImDrawList* m_DrawList = nullptr;
int m_ExpectedChannel = 0;
# if IMGUI_EX_CANVAS_DEFERED()
ImVector<Range> m_Ranges;
Range* m_CurrentRange = nullptr;
# endif
int m_DrawListCommadBufferSize = 0;
int m_DrawListStartVertexIndex = 0;
CanvasView m_View;
ImRect m_ViewRect;
ImVec2 m_ViewTransformPosition;
int m_SuspendCounter = 0;
float m_LastFringeScale = 1.0f;
ImVec2 m_MousePosBackup;
ImVec2 m_MousePosPrevBackup;
ImVec2 m_MouseClickedPosBackup[IM_ARRAYSIZE(ImGuiIO::MouseClickedPos)];
ImVec2 m_WindowCursorMaxBackup;
# if defined(IMGUI_HAS_VIEWPORT)
ImVec2 m_WindowPosBackup;
ImVec2 m_ViewportPosBackup;
ImVec2 m_ViewportSizeBackup;
# if IMGUI_VERSION_NUM > 18002
ImVec2 m_ViewportWorkPosBackup;
ImVec2 m_ViewportWorkSizeBackup;
# else
ImVec2 m_ViewportWorkOffsetMinBackup;
ImVec2 m_ViewportWorkOffsetMaxBackup;
# endif
# endif
};
} // namespace ImGuiEx
# endif // __IMGUI_EX_CANVAS_H__
+73
View File
@@ -0,0 +1,73 @@
//------------------------------------------------------------------------------
// VERSION 0.9.1
//
// LICENSE
// This software is dual-licensed to the public domain and under the following
// license: you are granted a perpetual, irrevocable license to copy, modify,
// publish, and distribute this file as you see fit.
//
// CREDITS
// Written by Michal Cichon
//------------------------------------------------------------------------------
# ifndef __IMGUI_EXTRA_MATH_H__
# define __IMGUI_EXTRA_MATH_H__
# pragma once
//------------------------------------------------------------------------------
# include <IUI/ImGui/imgui.h>
# ifndef IMGUI_DEFINE_MATH_OPERATORS
# define IMGUI_DEFINE_MATH_OPERATORS
# endif
# include <IUI/ImGui/imgui_internal.h>
//------------------------------------------------------------------------------
struct ImLine
{
ImVec2 A, B;
};
//------------------------------------------------------------------------------
inline bool operator==(const ImVec2& lhs, const ImVec2& rhs);
inline bool operator!=(const ImVec2& lhs, const ImVec2& rhs);
inline ImVec2 operator*(const float lhs, const ImVec2& rhs);
inline ImVec2 operator-(const ImVec2& lhs);
//------------------------------------------------------------------------------
inline float ImLength(float v);
inline float ImLength(const ImVec2& v);
inline float ImLengthSqr(float v);
inline ImVec2 ImNormalized(const ImVec2& v);
//------------------------------------------------------------------------------
inline bool ImRect_IsEmpty(const ImRect& rect);
inline ImVec2 ImRect_ClosestPoint(const ImRect& rect, const ImVec2& p, bool snap_to_edge);
inline ImVec2 ImRect_ClosestPoint(const ImRect& rect, const ImVec2& p, bool snap_to_edge, float radius);
inline ImVec2 ImRect_ClosestPoint(const ImRect& rect, const ImRect& b);
inline ImLine ImRect_ClosestLine(const ImRect& rect_a, const ImRect& rect_b);
inline ImLine ImRect_ClosestLine(const ImRect& rect_a, const ImRect& rect_b, float radius_a, float radius_b);
//------------------------------------------------------------------------------
namespace ImEasing {
template <typename V, typename T>
inline V EaseOutQuad(V b, V c, T t)
{
return b - c * (t * (t - 2));
}
} // namespace ImEasing
//------------------------------------------------------------------------------
# include "imgui_extra_math.inl"
//------------------------------------------------------------------------------
# endif // __IMGUI_EXTRA_MATH_H__
+189
View File
@@ -0,0 +1,189 @@
//------------------------------------------------------------------------------
// VERSION 0.9.1
//
// LICENSE
// This software is dual-licensed to the public domain and under the following
// license: you are granted a perpetual, irrevocable license to copy, modify,
// publish, and distribute this file as you see fit.
//
// CREDITS
// Written by Michal Cichon
//------------------------------------------------------------------------------
# ifndef __IMGUI_EXTRA_MATH_INL__
# define __IMGUI_EXTRA_MATH_INL__
# pragma once
//------------------------------------------------------------------------------
# include "imgui_extra_math.h"
//------------------------------------------------------------------------------
//inline bool operator==(const ImVec2& lhs, const ImVec2& rhs)
//{
// return lhs.x == rhs.x && lhs.y == rhs.y;
//}
//
//inline bool operator!=(const ImVec2& lhs, const ImVec2& rhs)
//{
// return lhs.x != rhs.x || lhs.y != rhs.y;
//}
inline ImVec2 operator*(const float lhs, const ImVec2& rhs)
{
return ImVec2(lhs * rhs.x, lhs * rhs.y);
}
//inline ImVec2 operator-(const ImVec2& lhs)
//{
// return ImVec2(-lhs.x, -lhs.y);
//}
//------------------------------------------------------------------------------
inline float ImLength(float v)
{
return v;
}
inline float ImLength(const ImVec2& v)
{
return ImSqrt(ImLengthSqr(v));
}
inline float ImLengthSqr(float v)
{
return v * v;
}
inline ImVec2 ImNormalized(const ImVec2& v)
{
return v * ImInvLength(v, 0.0f);
}
//------------------------------------------------------------------------------
inline bool ImRect_IsEmpty(const ImRect& rect)
{
return rect.Min.x >= rect.Max.x
|| rect.Min.y >= rect.Max.y;
}
inline ImVec2 ImRect_ClosestPoint(const ImRect& rect, const ImVec2& p, bool snap_to_edge)
{
if (!snap_to_edge && rect.Contains(p))
return p;
return ImVec2(
(p.x > rect.Max.x) ? rect.Max.x : (p.x < rect.Min.x ? rect.Min.x : p.x),
(p.y > rect.Max.y) ? rect.Max.y : (p.y < rect.Min.y ? rect.Min.y : p.y)
);
}
inline ImVec2 ImRect_ClosestPoint(const ImRect& rect, const ImVec2& p, bool snap_to_edge, float radius)
{
auto point = ImRect_ClosestPoint(rect, p, snap_to_edge);
const auto offset = p - point;
const auto distance_sq = offset.x * offset.x + offset.y * offset.y;
if (distance_sq <= 0)
return point;
const auto distance = ImSqrt(distance_sq);
return point + offset * (ImMin(distance, radius) * (1.0f / distance));
}
inline ImVec2 ImRect_ClosestPoint(const ImRect& rect, const ImRect& other)
{
ImVec2 result;
if (other.Min.x >= rect.Max.x)
result.x = rect.Max.x;
else if (other.Max.x <= rect.Min.x)
result.x = rect.Min.x;
else
result.x = (ImMax(rect.Min.x, other.Min.x) + ImMin(rect.Max.x, other.Max.x)) / 2;
if (other.Min.y >= rect.Max.y)
result.y = rect.Max.y;
else if (other.Max.y <= rect.Min.y)
result.y = rect.Min.y;
else
result.y = (ImMax(rect.Min.y, other.Min.y) + ImMin(rect.Max.y, other.Max.y)) / 2;
return result;
}
inline ImLine ImRect_ClosestLine(const ImRect& rect_a, const ImRect& rect_b)
{
ImLine result;
result.A = ImRect_ClosestPoint(rect_a, rect_b);
result.B = ImRect_ClosestPoint(rect_b, rect_a);
auto distribute = [](float& a, float& b, float a0, float a1, float b0, float b1)
{
if (a0 >= b1 || a1 <= b0)
return;
const auto aw = a1 - a0;
const auto bw = b1 - b0;
if (aw > bw)
{
b = b0 + bw - bw * (a - a0) / aw;
a = b;
}
else if (aw < bw)
{
a = a0 + aw - aw * (b - b0) / bw;
b = a;
}
};
distribute(result.A.x, result.B.x, rect_a.Min.x, rect_a.Max.x, rect_b.Min.x, rect_b.Max.x);
distribute(result.A.y, result.B.y, rect_a.Min.y, rect_a.Max.y, rect_b.Min.y, rect_b.Max.y);
return result;
}
inline ImLine ImRect_ClosestLine(const ImRect& rect_a, const ImRect& rect_b, float radius_a, float radius_b)
{
auto line = ImRect_ClosestLine(rect_a, rect_b);
if (radius_a < 0)
radius_a = 0;
if (radius_b < 0)
radius_b = 0;
if (radius_a == 0 && radius_b == 0)
return line;
const auto offset = line.B - line.A;
const auto length_sq = offset.x * offset.x + offset.y * offset.y;
const auto radius_a_sq = radius_a * radius_a;
const auto radius_b_sq = radius_b * radius_b;
if (length_sq <= 0)
return line;
const auto length = ImSqrt(length_sq);
const auto direction = ImVec2(offset.x / length, offset.y / length);
const auto total_radius_sq = radius_a_sq + radius_b_sq;
if (total_radius_sq > length_sq)
{
const auto scale = length / (radius_a + radius_b);
radius_a *= scale;
radius_b *= scale;
}
line.A = line.A + (direction * radius_a);
line.B = line.B - (direction * radius_b);
return line;
}
//------------------------------------------------------------------------------
# endif // __IMGUI_EXTRA_MATH_INL__
+510
View File
@@ -0,0 +1,510 @@
//------------------------------------------------------------------------------
// VERSION 0.9.1
//
// LICENSE
// This software is dual-licensed to the public domain and under the following
// license: you are granted a perpetual, irrevocable license to copy, modify,
// publish, and distribute this file as you see fit.
//
// CREDITS
// Written by Michal Cichon
//------------------------------------------------------------------------------
# ifndef __IMGUI_NODE_EDITOR_H__
# define __IMGUI_NODE_EDITOR_H__
# pragma once
//------------------------------------------------------------------------------
# include <IUI/ImGui/imgui.h>
# include <cstdint> // std::uintXX_t
# include <utility> // std::move
//------------------------------------------------------------------------------
# define IMGUI_NODE_EDITOR_VERSION "0.9.2"
# define IMGUI_NODE_EDITOR_VERSION_NUM 000902
//------------------------------------------------------------------------------
namespace ax {
namespace NodeEditor {
//------------------------------------------------------------------------------
struct NodeId;
struct LinkId;
struct PinId;
//------------------------------------------------------------------------------
enum class PinKind
{
Input,
Output
};
enum class FlowDirection
{
Forward,
Backward
};
enum class CanvasSizeMode
{
FitVerticalView, // Previous view will be scaled to fit new view on Y axis
FitHorizontalView, // Previous view will be scaled to fit new view on X axis
CenterOnly, // Previous view will be centered on new view
};
//------------------------------------------------------------------------------
enum class SaveReasonFlags: uint32_t
{
None = 0x00000000,
Navigation = 0x00000001,
Position = 0x00000002,
Size = 0x00000004,
Selection = 0x00000008,
AddNode = 0x00000010,
RemoveNode = 0x00000020,
User = 0x00000040
};
inline SaveReasonFlags operator |(SaveReasonFlags lhs, SaveReasonFlags rhs) { return static_cast<SaveReasonFlags>(static_cast<uint32_t>(lhs) | static_cast<uint32_t>(rhs)); }
inline SaveReasonFlags operator &(SaveReasonFlags lhs, SaveReasonFlags rhs) { return static_cast<SaveReasonFlags>(static_cast<uint32_t>(lhs) & static_cast<uint32_t>(rhs)); }
using ConfigSaveSettings = bool (*)(const char* data, size_t size, SaveReasonFlags reason, void* userPointer);
using ConfigLoadSettings = size_t (*)(char* data, void* userPointer);
using ConfigSaveNodeSettings = bool (*)(NodeId nodeId, const char* data, size_t size, SaveReasonFlags reason, void* userPointer);
using ConfigLoadNodeSettings = size_t (*)(NodeId nodeId, char* data, void* userPointer);
using ConfigSession = void (*)(void* userPointer);
struct Config
{
using CanvasSizeModeAlias = ax::NodeEditor::CanvasSizeMode;
const char* SettingsFile;
ConfigSession BeginSaveSession;
ConfigSession EndSaveSession;
ConfigSaveSettings SaveSettings;
ConfigLoadSettings LoadSettings;
ConfigSaveNodeSettings SaveNodeSettings;
ConfigLoadNodeSettings LoadNodeSettings;
void* UserPointer;
ImVector<float> CustomZoomLevels;
CanvasSizeModeAlias CanvasSizeMode;
int DragButtonIndex; // Mouse button index drag action will react to (0-left, 1-right, 2-middle)
int SelectButtonIndex; // Mouse button index select action will react to (0-left, 1-right, 2-middle)
int NavigateButtonIndex; // Mouse button index navigate action will react to (0-left, 1-right, 2-middle)
int ContextMenuButtonIndex; // Mouse button index context menu action will react to (0-left, 1-right, 2-middle)
Config()
: SettingsFile("NodeEditor.json")
, BeginSaveSession(nullptr)
, EndSaveSession(nullptr)
, SaveSettings(nullptr)
, LoadSettings(nullptr)
, SaveNodeSettings(nullptr)
, LoadNodeSettings(nullptr)
, UserPointer(nullptr)
, CustomZoomLevels()
, CanvasSizeMode(CanvasSizeModeAlias::FitVerticalView)
, DragButtonIndex(0)
, SelectButtonIndex(0)
, NavigateButtonIndex(1)
, ContextMenuButtonIndex(1)
{
}
};
//------------------------------------------------------------------------------
enum StyleColor
{
StyleColor_Bg,
StyleColor_Grid,
StyleColor_NodeBg,
StyleColor_NodeBorder,
StyleColor_HovNodeBorder,
StyleColor_SelNodeBorder,
StyleColor_NodeSelRect,
StyleColor_NodeSelRectBorder,
StyleColor_HovLinkBorder,
StyleColor_SelLinkBorder,
StyleColor_HighlightLinkBorder,
StyleColor_LinkSelRect,
StyleColor_LinkSelRectBorder,
StyleColor_PinRect,
StyleColor_PinRectBorder,
StyleColor_Flow,
StyleColor_FlowMarker,
StyleColor_GroupBg,
StyleColor_GroupBorder,
StyleColor_Count
};
enum StyleVar
{
StyleVar_NodePadding,
StyleVar_NodeRounding,
StyleVar_NodeBorderWidth,
StyleVar_HoveredNodeBorderWidth,
StyleVar_SelectedNodeBorderWidth,
StyleVar_PinRounding,
StyleVar_PinBorderWidth,
StyleVar_LinkStrength,
StyleVar_SourceDirection,
StyleVar_TargetDirection,
StyleVar_ScrollDuration,
StyleVar_FlowMarkerDistance,
StyleVar_FlowSpeed,
StyleVar_FlowDuration,
StyleVar_PivotAlignment,
StyleVar_PivotSize,
StyleVar_PivotScale,
StyleVar_PinCorners,
StyleVar_PinRadius,
StyleVar_PinArrowSize,
StyleVar_PinArrowWidth,
StyleVar_GroupRounding,
StyleVar_GroupBorderWidth,
StyleVar_HighlightConnectedLinks,
StyleVar_SnapLinkToPinDir,
StyleVar_Count
};
struct Style
{
ImVec4 NodePadding;
float NodeRounding;
float NodeBorderWidth;
float HoveredNodeBorderWidth;
float SelectedNodeBorderWidth;
float PinRounding;
float PinBorderWidth;
float LinkStrength;
ImVec2 SourceDirection;
ImVec2 TargetDirection;
float ScrollDuration;
float FlowMarkerDistance;
float FlowSpeed;
float FlowDuration;
ImVec2 PivotAlignment;
ImVec2 PivotSize;
ImVec2 PivotScale;
float PinCorners;
float PinRadius;
float PinArrowSize;
float PinArrowWidth;
float GroupRounding;
float GroupBorderWidth;
float HighlightConnectedLinks;
float SnapLinkToPinDir; // when true link will start on the line defined by pin direction
ImVec4 Colors[StyleColor_Count];
Style()
{
NodePadding = ImVec4(8, 8, 8, 8);
NodeRounding = 12.0f;
NodeBorderWidth = 1.5f;
HoveredNodeBorderWidth = 3.5f;
SelectedNodeBorderWidth = 3.5f;
PinRounding = 4.0f;
PinBorderWidth = 0.0f;
LinkStrength = 100.0f;
SourceDirection = ImVec2(1.0f, 0.0f);
TargetDirection = ImVec2(-1.0f, 0.0f);
ScrollDuration = 0.35f;
FlowMarkerDistance = 30.0f;
FlowSpeed = 150.0f;
FlowDuration = 2.0f;
PivotAlignment = ImVec2(0.5f, 0.5f);
PivotSize = ImVec2(0.0f, 0.0f);
PivotScale = ImVec2(1, 1);
#if IMGUI_VERSION_NUM > 18101
PinCorners = ImDrawFlags_RoundCornersAll;
#else
PinCorners = ImDrawCornerFlags_All;
#endif
PinRadius = 0.0f;
PinArrowSize = 0.0f;
PinArrowWidth = 0.0f;
GroupRounding = 6.0f;
GroupBorderWidth = 1.0f;
HighlightConnectedLinks = 0.0f;
SnapLinkToPinDir = 0.0f;
Colors[StyleColor_Bg] = ImColor( 60, 60, 70, 200);
Colors[StyleColor_Grid] = ImColor(120, 120, 120, 40);
Colors[StyleColor_NodeBg] = ImColor( 32, 32, 32, 200);
Colors[StyleColor_NodeBorder] = ImColor(255, 255, 255, 96);
Colors[StyleColor_HovNodeBorder] = ImColor( 50, 176, 255, 255);
Colors[StyleColor_SelNodeBorder] = ImColor(255, 176, 50, 255);
Colors[StyleColor_NodeSelRect] = ImColor( 5, 130, 255, 64);
Colors[StyleColor_NodeSelRectBorder] = ImColor( 5, 130, 255, 128);
Colors[StyleColor_HovLinkBorder] = ImColor( 50, 176, 255, 255);
Colors[StyleColor_SelLinkBorder] = ImColor(255, 176, 50, 255);
Colors[StyleColor_HighlightLinkBorder]= ImColor(204, 105, 0, 255);
Colors[StyleColor_LinkSelRect] = ImColor( 5, 130, 255, 64);
Colors[StyleColor_LinkSelRectBorder] = ImColor( 5, 130, 255, 128);
Colors[StyleColor_PinRect] = ImColor( 60, 180, 255, 100);
Colors[StyleColor_PinRectBorder] = ImColor( 60, 180, 255, 128);
Colors[StyleColor_Flow] = ImColor(255, 128, 64, 255);
Colors[StyleColor_FlowMarker] = ImColor(255, 128, 64, 255);
Colors[StyleColor_GroupBg] = ImColor( 0, 0, 0, 160);
Colors[StyleColor_GroupBorder] = ImColor(255, 255, 255, 32);
}
};
//------------------------------------------------------------------------------
struct EditorContext;
//------------------------------------------------------------------------------
void SetCurrentEditor(EditorContext* ctx);
EditorContext* GetCurrentEditor();
EditorContext* CreateEditor(const Config* config = nullptr);
void DestroyEditor(EditorContext* ctx);
const Config& GetConfig(EditorContext* ctx = nullptr);
Style& GetStyle();
const char* GetStyleColorName(StyleColor colorIndex);
void PushStyleColor(StyleColor colorIndex, const ImVec4& color);
void PopStyleColor(int count = 1);
void PushStyleVar(StyleVar varIndex, float value);
void PushStyleVar(StyleVar varIndex, const ImVec2& value);
void PushStyleVar(StyleVar varIndex, const ImVec4& value);
void PopStyleVar(int count = 1);
void Begin(const char* id, const ImVec2& size = ImVec2(0, 0));
void End();
void BeginNode(NodeId id);
void BeginPin(PinId id, PinKind kind);
void PinRect(const ImVec2& a, const ImVec2& b);
void PinPivotRect(const ImVec2& a, const ImVec2& b);
void PinPivotSize(const ImVec2& size);
void PinPivotScale(const ImVec2& scale);
void PinPivotAlignment(const ImVec2& alignment);
void EndPin();
void Group(const ImVec2& size);
void EndNode();
bool BeginGroupHint(NodeId nodeId);
ImVec2 GetGroupMin();
ImVec2 GetGroupMax();
ImDrawList* GetHintForegroundDrawList();
ImDrawList* GetHintBackgroundDrawList();
void EndGroupHint();
// TODO: Add a way to manage node background channels
ImDrawList* GetNodeBackgroundDrawList(NodeId nodeId);
bool Link(LinkId id, PinId startPinId, PinId endPinId, const ImVec4& color = ImVec4(1, 1, 1, 1), float thickness = 1.0f);
void Flow(LinkId linkId, FlowDirection direction = FlowDirection::Forward);
bool BeginCreate(const ImVec4& color = ImVec4(1, 1, 1, 1), float thickness = 1.0f);
bool QueryNewLink(PinId* startId, PinId* endId);
bool QueryNewLink(PinId* startId, PinId* endId, const ImVec4& color, float thickness = 1.0f);
bool QueryNewNode(PinId* pinId);
bool QueryNewNode(PinId* pinId, const ImVec4& color, float thickness = 1.0f);
bool AcceptNewItem();
bool AcceptNewItem(const ImVec4& color, float thickness = 1.0f);
void RejectNewItem();
void RejectNewItem(const ImVec4& color, float thickness = 1.0f);
void EndCreate();
bool BeginDelete();
bool QueryDeletedLink(LinkId* linkId, PinId* startId = nullptr, PinId* endId = nullptr);
bool QueryDeletedNode(NodeId* nodeId);
bool AcceptDeletedItem(bool deleteDependencies = true);
void RejectDeletedItem();
void EndDelete();
void SetNodePosition(NodeId nodeId, const ImVec2& editorPosition);
void SetGroupSize(NodeId nodeId, const ImVec2& size);
ImVec2 GetNodePosition(NodeId nodeId);
ImVec2 GetNodeSize(NodeId nodeId);
void CenterNodeOnScreen(NodeId nodeId);
void SetNodeZPosition(NodeId nodeId, float z); // Sets node z position, nodes with higher value are drawn over nodes with lower value
float GetNodeZPosition(NodeId nodeId); // Returns node z position, defaults is 0.0f
void RestoreNodeState(NodeId nodeId);
void Suspend();
void Resume();
bool IsSuspended();
bool IsActive();
bool HasSelectionChanged();
int GetSelectedObjectCount();
int GetSelectedNodes(NodeId* nodes, int size);
int GetSelectedLinks(LinkId* links, int size);
bool IsNodeSelected(NodeId nodeId);
bool IsLinkSelected(LinkId linkId);
void ClearSelection();
void SelectNode(NodeId nodeId, bool append = false);
void SelectLink(LinkId linkId, bool append = false);
void DeselectNode(NodeId nodeId);
void DeselectLink(LinkId linkId);
bool DeleteNode(NodeId nodeId);
bool DeleteLink(LinkId linkId);
bool HasAnyLinks(NodeId nodeId); // Returns true if node has any link connected
bool HasAnyLinks(PinId pinId); // Return true if pin has any link connected
int BreakLinks(NodeId nodeId); // Break all links connected to this node
int BreakLinks(PinId pinId); // Break all links connected to this pin
void NavigateToContent(float duration = -1);
void NavigateToSelection(bool zoomIn = false, float duration = -1);
bool ShowNodeContextMenu(NodeId* nodeId);
bool ShowPinContextMenu(PinId* pinId);
bool ShowLinkContextMenu(LinkId* linkId);
bool ShowBackgroundContextMenu();
void EnableShortcuts(bool enable);
bool AreShortcutsEnabled();
bool BeginShortcut();
bool AcceptCut();
bool AcceptCopy();
bool AcceptPaste();
bool AcceptDuplicate();
bool AcceptCreateNode();
int GetActionContextSize();
int GetActionContextNodes(NodeId* nodes, int size);
int GetActionContextLinks(LinkId* links, int size);
void EndShortcut();
float GetCurrentZoom();
NodeId GetHoveredNode();
PinId GetHoveredPin();
LinkId GetHoveredLink();
NodeId GetDoubleClickedNode();
PinId GetDoubleClickedPin();
LinkId GetDoubleClickedLink();
bool IsBackgroundClicked();
bool IsBackgroundDoubleClicked();
ImGuiMouseButton GetBackgroundClickButtonIndex(); // -1 if none
ImGuiMouseButton GetBackgroundDoubleClickButtonIndex(); // -1 if none
bool GetLinkPins(LinkId linkId, PinId* startPinId, PinId* endPinId); // pass nullptr if particular pin do not interest you
bool PinHadAnyLinks(PinId pinId);
ImVec2 GetScreenSize();
ImVec2 ScreenToCanvas(const ImVec2& pos);
ImVec2 CanvasToScreen(const ImVec2& pos);
int GetNodeCount(); // Returns number of submitted nodes since Begin() call
int GetOrderedNodeIds(NodeId* nodes, int size); // Fills an array with node id's in order they're drawn; up to 'size` elements are set. Returns actual size of filled id's.
//------------------------------------------------------------------------------
namespace Details {
template <typename T, typename Tag>
struct SafeType
{
SafeType(T t)
: m_Value(std::move(t))
{
}
SafeType(const SafeType&) = default;
template <typename T2, typename Tag2>
SafeType(
const SafeType
<
typename std::enable_if<!std::is_same<T, T2>::value, T2>::type,
typename std::enable_if<!std::is_same<Tag, Tag2>::value, Tag2>::type
>&) = delete;
SafeType& operator=(const SafeType&) = default;
explicit operator T() const { return Get(); }
T Get() const { return m_Value; }
private:
T m_Value;
};
template <typename Tag>
struct SafePointerType
: SafeType<uintptr_t, Tag>
{
static const Tag Invalid;
using SafeType<uintptr_t, Tag>::SafeType;
SafePointerType()
: SafePointerType(Invalid)
{
}
template <typename T = void> explicit SafePointerType(T* ptr): SafePointerType(reinterpret_cast<uintptr_t>(ptr)) {}
template <typename T = void> T* AsPointer() const { return reinterpret_cast<T*>(this->Get()); }
explicit operator bool() const { return *this != Invalid; }
};
template <typename Tag>
const Tag SafePointerType<Tag>::Invalid = { 0 };
template <typename Tag>
inline bool operator==(const SafePointerType<Tag>& lhs, const SafePointerType<Tag>& rhs)
{
return lhs.Get() == rhs.Get();
}
template <typename Tag>
inline bool operator!=(const SafePointerType<Tag>& lhs, const SafePointerType<Tag>& rhs)
{
return lhs.Get() != rhs.Get();
}
} // namespace Details
struct NodeId final: Details::SafePointerType<NodeId>
{
using SafePointerType::SafePointerType;
};
struct LinkId final: Details::SafePointerType<LinkId>
{
using SafePointerType::SafePointerType;
};
struct PinId final: Details::SafePointerType<PinId>
{
using SafePointerType::SafePointerType;
};
//------------------------------------------------------------------------------
} // namespace Editor
} // namespace ax
//------------------------------------------------------------------------------
# endif // __IMGUI_NODE_EDITOR_H__
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,65 @@
//------------------------------------------------------------------------------
// VERSION 0.9.1
//
// LICENSE
// This software is dual-licensed to the public domain and under the following
// license: you are granted a perpetual, irrevocable license to copy, modify,
// publish, and distribute this file as you see fit.
//
// CREDITS
// Written by Michal Cichon
//------------------------------------------------------------------------------
# ifndef __IMGUI_NODE_EDITOR_INTERNAL_INL__
# define __IMGUI_NODE_EDITOR_INTERNAL_INL__
# pragma once
//------------------------------------------------------------------------------
# include "imgui_node_editor_internal.h"
//------------------------------------------------------------------------------
namespace ax {
namespace NodeEditor {
namespace Detail {
//------------------------------------------------------------------------------
//inline ImRect ToRect(const ax::rectf& rect)
//{
// return ImRect(
// to_imvec(rect.top_left()),
// to_imvec(rect.bottom_right())
// );
//}
//
//inline ImRect ToRect(const ax::rect& rect)
//{
// return ImRect(
// to_imvec(rect.top_left()),
// to_imvec(rect.bottom_right())
// );
//}
inline ImRect ImGui_GetItemRect()
{
return ImRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax());
}
inline ImVec2 ImGui_GetMouseClickPos(ImGuiMouseButton buttonIndex)
{
if (ImGui::IsMouseDown(buttonIndex))
return ImGui::GetIO().MouseClickedPos[buttonIndex];
else
return ImGui::GetMousePos();
}
//------------------------------------------------------------------------------
} // namespace Detail
} // namespace Editor
} // namespace ax
//------------------------------------------------------------------------------
# endif // __IMGUI_NODE_EDITOR_INTERNAL_INL__