First
This commit is contained in:
@@ -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);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
@@ -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
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -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_ */
|
||||
@@ -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
|
||||
@@ -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(); }
|
||||
};
|
||||
@@ -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;
|
||||
@@ -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
@@ -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__
|
||||
@@ -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__
|
||||
@@ -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__
|
||||
@@ -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__
|
||||
@@ -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__
|
||||
@@ -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__
|
||||
@@ -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__
|
||||
Reference in New Issue
Block a user