Initial re-upload of spice2x-24-08-24
This commit is contained in:
23
external/imgui/CMakeLists.txt
vendored
Normal file
23
external/imgui/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
cmake_minimum_required(VERSION 3.9)
|
||||
project(imgui CXX)
|
||||
|
||||
# dear imgui uses the C++ virtual interfaces for DirectX
|
||||
remove_definitions(-DCINTERFACE)
|
||||
|
||||
set(IMGUI_HEADERS
|
||||
imconfig.h
|
||||
imgui.h
|
||||
imgui_internal.h
|
||||
imgui_stdlib.h
|
||||
)
|
||||
set(IMGUI_SOURCES
|
||||
imgui.cpp
|
||||
imgui_draw.cpp
|
||||
imgui_tables.cpp
|
||||
imgui_widgets.cpp
|
||||
imgui_demo.cpp
|
||||
imgui_stdlib.cpp
|
||||
)
|
||||
|
||||
add_library(imgui STATIC ${IMGUI_HEADERS} ${IMGUI_SOURCES})
|
||||
target_include_directories(imgui PRIVATE ${PROJECT_SOURCE_DIR})
|
||||
21
external/imgui/LICENSE.txt
vendored
Normal file
21
external/imgui/LICENSE.txt
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014-2023 Omar Cornut
|
||||
|
||||
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.
|
||||
125
external/imgui/imconfig.h
vendored
Normal file
125
external/imgui/imconfig.h
vendored
Normal file
@@ -0,0 +1,125 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// COMPILE-TIME OPTIONS FOR DEAR IMGUI
|
||||
// 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 files 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 avoid using soon-to-be 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 will be folded into IMGUI_DISABLE_OBSOLETE_FUNCTIONS in a few versions.
|
||||
|
||||
//---- 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 ShowStackToolWindow() will be empty (this was called IMGUI_DISABLE_METRICS_WINDOW before 1.88).
|
||||
|
||||
//---- 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
|
||||
//#define IMGUI_INCLUDE_IMGUI_USER_H
|
||||
|
||||
//---- Pack colors to BGRA8 instead of RGBA8 (to avoid converting from one to another)
|
||||
#define IMGUI_USE_BGRA_PACKED_COLOR
|
||||
|
||||
//---- Performance optimization for DX9
|
||||
#define IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT struct ImDrawVert { ImVec2 pos; float z; ImU32 col; ImVec2 uv; }
|
||||
|
||||
//---- 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 enabled
|
||||
//#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION
|
||||
//#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION
|
||||
|
||||
//---- 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 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
|
||||
// (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, here or in your own headers files.
|
||||
/*
|
||||
namespace ImGui
|
||||
{
|
||||
void MyFunction(const char* name, const MyMatrix44& v);
|
||||
}
|
||||
*/
|
||||
20436
external/imgui/imgui.cpp
vendored
Normal file
20436
external/imgui/imgui.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
3398
external/imgui/imgui.h
vendored
Normal file
3398
external/imgui/imgui.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
8334
external/imgui/imgui_demo.cpp
vendored
Normal file
8334
external/imgui/imgui_demo.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
4201
external/imgui/imgui_draw.cpp
vendored
Normal file
4201
external/imgui/imgui_draw.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
983
external/imgui/imgui_filebrowser.h
vendored
Normal file
983
external/imgui/imgui_filebrowser.h
vendored
Normal file
@@ -0,0 +1,983 @@
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <cctype>
|
||||
#include <cstring>
|
||||
#include <filesystem>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#ifndef IMGUI_VERSION
|
||||
# error "include imgui.h before this header"
|
||||
#endif
|
||||
|
||||
using ImGuiFileBrowserFlags = int;
|
||||
|
||||
enum ImGuiFileBrowserFlags_
|
||||
{
|
||||
ImGuiFileBrowserFlags_SelectDirectory = 1 << 0, // select directory instead of regular file
|
||||
ImGuiFileBrowserFlags_EnterNewFilename = 1 << 1, // allow user to enter new filename when selecting regular file
|
||||
ImGuiFileBrowserFlags_NoModal = 1 << 2, // file browsing window is modal by default. specify this to use a popup window
|
||||
ImGuiFileBrowserFlags_NoTitleBar = 1 << 3, // hide window title bar
|
||||
ImGuiFileBrowserFlags_NoStatusBar = 1 << 4, // hide status bar at the bottom of browsing window
|
||||
ImGuiFileBrowserFlags_CloseOnEsc = 1 << 5, // close file browser when pressing 'ESC'
|
||||
ImGuiFileBrowserFlags_CreateNewDir = 1 << 6, // allow user to create new directory
|
||||
ImGuiFileBrowserFlags_MultipleSelection = 1 << 7, // allow user to select multiple files. this will hide ImGuiFileBrowserFlags_EnterNewFilename
|
||||
};
|
||||
|
||||
namespace ImGui
|
||||
{
|
||||
class FileBrowser
|
||||
{
|
||||
public:
|
||||
|
||||
// pwd is set to current working directory by default
|
||||
explicit FileBrowser(ImGuiFileBrowserFlags flags = 0);
|
||||
|
||||
FileBrowser(const FileBrowser ©From);
|
||||
|
||||
FileBrowser &operator=(const FileBrowser ©From);
|
||||
|
||||
// set the window position (in pixels)
|
||||
// default is centered
|
||||
void SetWindowPos(int posx, int posy) noexcept;
|
||||
|
||||
// set the window size (in pixels)
|
||||
// default is (700, 450)
|
||||
void SetWindowSize(int width, int height) noexcept;
|
||||
|
||||
// set the window title text
|
||||
void SetTitle(std::string title);
|
||||
|
||||
// open the browsing window
|
||||
void Open();
|
||||
|
||||
// close the browsing window
|
||||
void Close();
|
||||
|
||||
// the browsing window is opened or not
|
||||
bool IsOpened() const noexcept;
|
||||
|
||||
// display the browsing window if opened
|
||||
void Display();
|
||||
|
||||
// returns true when there is a selected filename and the "ok" button was clicked
|
||||
bool HasSelected() const noexcept;
|
||||
|
||||
// set current browsing directory
|
||||
bool SetPwd(const std::filesystem::path &pwd =
|
||||
std::filesystem::current_path());
|
||||
|
||||
// get current browsing directory
|
||||
const std::filesystem::path &GetPwd() const noexcept;
|
||||
|
||||
// returns selected filename. make sense only when HasSelected returns true
|
||||
// when ImGuiFileBrowserFlags_MultipleSelection is enabled, only one of
|
||||
// selected filename will be returned
|
||||
std::filesystem::path GetSelected() const;
|
||||
|
||||
// returns all selected filenames.
|
||||
// when ImGuiFileBrowserFlags_MultipleSelection is enabled, use this
|
||||
// instead of GetSelected
|
||||
std::vector<std::filesystem::path> GetMultiSelected() const;
|
||||
|
||||
// set selected filename to empty
|
||||
void ClearSelected();
|
||||
|
||||
// (optional) set file type filters. eg. { ".h", ".cpp", ".hpp" }
|
||||
// ".*" matches any file types
|
||||
void SetTypeFilters(const std::vector<std::string> &typeFilters);
|
||||
|
||||
// set currently applied type filter
|
||||
// default value is 0 (the first type filter)
|
||||
void SetCurrentTypeFilterIndex(int index);
|
||||
|
||||
// when ImGuiFileBrowserFlags_EnterNewFilename is set
|
||||
// this function will pre-fill the input dialog with a filename.
|
||||
void SetInputName(std::string_view input);
|
||||
|
||||
private:
|
||||
|
||||
template <class Functor>
|
||||
struct ScopeGuard
|
||||
{
|
||||
ScopeGuard(Functor&& t) : func(std::move(t)) { }
|
||||
|
||||
~ScopeGuard() { func(); }
|
||||
|
||||
private:
|
||||
|
||||
Functor func;
|
||||
};
|
||||
|
||||
struct FileRecord
|
||||
{
|
||||
bool isDir = false;
|
||||
std::filesystem::path name;
|
||||
std::string showName;
|
||||
std::filesystem::path extension;
|
||||
};
|
||||
|
||||
static std::string ToLower(const std::string &s);
|
||||
|
||||
void UpdateFileRecords();
|
||||
|
||||
void SetPwdUncatched(const std::filesystem::path &pwd);
|
||||
|
||||
bool IsExtensionMatched(const std::filesystem::path &extension) const;
|
||||
|
||||
#ifdef _WIN32
|
||||
static std::uint32_t GetDrivesBitMask();
|
||||
#endif
|
||||
|
||||
// for c++17 compatibility
|
||||
|
||||
#if defined(__cpp_lib_char8_t)
|
||||
static std::string u8StrToStr(std::u8string s);
|
||||
#endif
|
||||
static std::string u8StrToStr(std::string s);
|
||||
|
||||
int width_;
|
||||
int height_;
|
||||
int posX_;
|
||||
int posY_;
|
||||
ImGuiFileBrowserFlags flags_;
|
||||
|
||||
std::string title_;
|
||||
std::string openLabel_;
|
||||
|
||||
bool openFlag_;
|
||||
bool closeFlag_;
|
||||
bool isOpened_;
|
||||
bool ok_;
|
||||
bool posIsSet_;
|
||||
|
||||
std::string statusStr_;
|
||||
|
||||
std::vector<std::string> typeFilters_;
|
||||
unsigned int typeFilterIndex_;
|
||||
bool hasAllFilter_;
|
||||
|
||||
std::filesystem::path pwd_;
|
||||
std::set<std::filesystem::path> selectedFilenames_;
|
||||
|
||||
std::vector<FileRecord> fileRecords_;
|
||||
|
||||
// IMPROVE: truncate when selectedFilename_.length() > inputNameBuf_.size() - 1
|
||||
static constexpr size_t INPUT_NAME_BUF_SIZE = 512;
|
||||
std::unique_ptr<std::array<char, INPUT_NAME_BUF_SIZE>> inputNameBuf_;
|
||||
|
||||
std::string openNewDirLabel_;
|
||||
std::unique_ptr<std::array<char, INPUT_NAME_BUF_SIZE>> newDirNameBuf_;
|
||||
|
||||
#ifdef _WIN32
|
||||
uint32_t drives_;
|
||||
#endif
|
||||
};
|
||||
} // namespace ImGui
|
||||
|
||||
inline ImGui::FileBrowser::FileBrowser(ImGuiFileBrowserFlags flags)
|
||||
: width_(700), height_(450), posX_(0), posY_(0), flags_(flags),
|
||||
openFlag_(false), closeFlag_(false), isOpened_(false), ok_(false), posIsSet_(false),
|
||||
inputNameBuf_(std::make_unique<std::array<char, INPUT_NAME_BUF_SIZE>>())
|
||||
{
|
||||
if(flags_ & ImGuiFileBrowserFlags_CreateNewDir)
|
||||
{
|
||||
newDirNameBuf_ =
|
||||
std::make_unique<std::array<char, INPUT_NAME_BUF_SIZE>>();
|
||||
}
|
||||
|
||||
inputNameBuf_->front() = '\0';
|
||||
inputNameBuf_->back() = '\0';
|
||||
SetTitle("file browser");
|
||||
SetPwd(std::filesystem::current_path());
|
||||
|
||||
typeFilters_.clear();
|
||||
typeFilterIndex_ = 0;
|
||||
hasAllFilter_ = false;
|
||||
|
||||
#ifdef _WIN32
|
||||
drives_ = GetDrivesBitMask();
|
||||
#endif
|
||||
}
|
||||
|
||||
inline ImGui::FileBrowser::FileBrowser(const FileBrowser ©From)
|
||||
: FileBrowser()
|
||||
{
|
||||
*this = copyFrom;
|
||||
}
|
||||
|
||||
inline ImGui::FileBrowser &ImGui::FileBrowser::operator=(
|
||||
const FileBrowser ©From)
|
||||
{
|
||||
width_ = copyFrom.width_;
|
||||
height_ = copyFrom.height_;
|
||||
|
||||
posX_ = copyFrom.posX_;
|
||||
posY_ = copyFrom.posY_;
|
||||
|
||||
flags_ = copyFrom.flags_;
|
||||
SetTitle(copyFrom.title_);
|
||||
|
||||
openFlag_ = copyFrom.openFlag_;
|
||||
closeFlag_ = copyFrom.closeFlag_;
|
||||
isOpened_ = copyFrom.isOpened_;
|
||||
ok_ = copyFrom.ok_;
|
||||
posIsSet_ = copyFrom.posIsSet_;
|
||||
|
||||
statusStr_ = "";
|
||||
|
||||
typeFilters_ = copyFrom.typeFilters_;
|
||||
typeFilterIndex_ = copyFrom.typeFilterIndex_;
|
||||
hasAllFilter_ = copyFrom.hasAllFilter_;
|
||||
|
||||
pwd_ = copyFrom.pwd_;
|
||||
selectedFilenames_ = copyFrom.selectedFilenames_;
|
||||
|
||||
fileRecords_ = copyFrom.fileRecords_;
|
||||
|
||||
*inputNameBuf_ = *copyFrom.inputNameBuf_;
|
||||
|
||||
openNewDirLabel_ = copyFrom.openNewDirLabel_;
|
||||
if(flags_ & ImGuiFileBrowserFlags_CreateNewDir)
|
||||
{
|
||||
newDirNameBuf_ = std::make_unique<
|
||||
std::array<char, INPUT_NAME_BUF_SIZE>>();
|
||||
*newDirNameBuf_ = *copyFrom.newDirNameBuf_;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
drives_ = copyFrom.drives_;
|
||||
#endif
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline void ImGui::FileBrowser::SetWindowPos(int posx, int posy) noexcept
|
||||
{
|
||||
posX_ = posx;
|
||||
posY_ = posy;
|
||||
posIsSet_ = true;
|
||||
}
|
||||
|
||||
inline void ImGui::FileBrowser::SetWindowSize(int width, int height) noexcept
|
||||
{
|
||||
assert(width > 0 && height > 0);
|
||||
width_ = width;
|
||||
height_ = height;
|
||||
}
|
||||
|
||||
inline void ImGui::FileBrowser::SetTitle(std::string title)
|
||||
{
|
||||
title_ = std::move(title);
|
||||
openLabel_ = title_ + "##filebrowser_" +
|
||||
std::to_string(reinterpret_cast<size_t>(this));
|
||||
openNewDirLabel_ = "new dir##new_dir_" +
|
||||
std::to_string(reinterpret_cast<size_t>(this));
|
||||
}
|
||||
|
||||
inline void ImGui::FileBrowser::Open()
|
||||
{
|
||||
ClearSelected();
|
||||
UpdateFileRecords();
|
||||
statusStr_ = std::string();
|
||||
openFlag_ = true;
|
||||
closeFlag_ = false;
|
||||
}
|
||||
|
||||
inline void ImGui::FileBrowser::Close()
|
||||
{
|
||||
ClearSelected();
|
||||
statusStr_ = std::string();
|
||||
closeFlag_ = true;
|
||||
openFlag_ = false;
|
||||
}
|
||||
|
||||
inline bool ImGui::FileBrowser::IsOpened() const noexcept
|
||||
{
|
||||
return isOpened_;
|
||||
}
|
||||
|
||||
inline void ImGui::FileBrowser::Display()
|
||||
{
|
||||
PushID(this);
|
||||
ScopeGuard exitThis([this]
|
||||
{
|
||||
openFlag_ = false;
|
||||
closeFlag_ = false;
|
||||
PopID();
|
||||
});
|
||||
|
||||
if(openFlag_)
|
||||
{
|
||||
OpenPopup(openLabel_.c_str());
|
||||
}
|
||||
isOpened_ = false;
|
||||
|
||||
// open the popup window
|
||||
|
||||
if(openFlag_ && (flags_ & ImGuiFileBrowserFlags_NoModal))
|
||||
{
|
||||
if (posIsSet_)
|
||||
SetNextWindowPos(
|
||||
ImVec2(static_cast<float>(posX_), static_cast<float>(posY_)));
|
||||
SetNextWindowSize(
|
||||
ImVec2(static_cast<float>(width_), static_cast<float>(height_)));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (posIsSet_)
|
||||
SetNextWindowPos(
|
||||
ImVec2(static_cast<float>(posX_), static_cast<float>(posY_)),
|
||||
ImGuiCond_FirstUseEver);
|
||||
SetNextWindowSize(
|
||||
ImVec2(static_cast<float>(width_), static_cast<float>(height_)),
|
||||
ImGuiCond_FirstUseEver);
|
||||
}
|
||||
if(flags_ & ImGuiFileBrowserFlags_NoModal)
|
||||
{
|
||||
if(!BeginPopup(openLabel_.c_str()))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if(!BeginPopupModal(openLabel_.c_str(), nullptr,
|
||||
flags_ & ImGuiFileBrowserFlags_NoTitleBar ?
|
||||
ImGuiWindowFlags_NoTitleBar : 0))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
isOpened_ = true;
|
||||
ScopeGuard endPopup([] { EndPopup(); });
|
||||
|
||||
// display elements in pwd
|
||||
|
||||
#ifdef _WIN32
|
||||
char currentDrive = static_cast<char>(pwd_.c_str()[0]);
|
||||
char driveStr[] = { currentDrive, ':', '\0' };
|
||||
|
||||
PushItemWidth(4 * GetFontSize());
|
||||
if(BeginCombo("##select_drive", driveStr))
|
||||
{
|
||||
ScopeGuard guard([&] { EndCombo(); });
|
||||
|
||||
for(int i = 0; i < 26; ++i)
|
||||
{
|
||||
if(!(drives_ & (1 << i)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
char driveCh = static_cast<char>('A' + i);
|
||||
char selectableStr[] = { driveCh, ':', '\0' };
|
||||
bool selected = currentDrive == driveCh;
|
||||
|
||||
if(Selectable(selectableStr, selected) && !selected)
|
||||
{
|
||||
char newPwd[] = { driveCh, ':', '\\', '\0' };
|
||||
SetPwd(newPwd);
|
||||
}
|
||||
}
|
||||
}
|
||||
PopItemWidth();
|
||||
|
||||
SameLine();
|
||||
#endif
|
||||
|
||||
int secIdx = 0, newPwdLastSecIdx = -1;
|
||||
for(const auto &sec : pwd_)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if(secIdx == 1)
|
||||
{
|
||||
++secIdx;
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
PushID(secIdx);
|
||||
if(secIdx > 0)
|
||||
{
|
||||
SameLine();
|
||||
}
|
||||
if(SmallButton(u8StrToStr(sec.u8string()).c_str()))
|
||||
{
|
||||
newPwdLastSecIdx = secIdx;
|
||||
}
|
||||
PopID();
|
||||
|
||||
++secIdx;
|
||||
}
|
||||
|
||||
if(newPwdLastSecIdx >= 0)
|
||||
{
|
||||
int i = 0;
|
||||
std::filesystem::path newPwd;
|
||||
for(const auto &sec : pwd_)
|
||||
{
|
||||
if(i++ > newPwdLastSecIdx)
|
||||
{
|
||||
break;
|
||||
}
|
||||
newPwd /= sec;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
if(newPwdLastSecIdx == 0)
|
||||
{
|
||||
newPwd /= "\\";
|
||||
}
|
||||
#endif
|
||||
|
||||
SetPwd(newPwd);
|
||||
}
|
||||
|
||||
SameLine();
|
||||
|
||||
if(SmallButton("*"))
|
||||
{
|
||||
UpdateFileRecords();
|
||||
|
||||
std::set<std::filesystem::path> newSelectedFilenames;
|
||||
for(auto &name : selectedFilenames_)
|
||||
{
|
||||
auto it = std::find_if(
|
||||
fileRecords_.begin(), fileRecords_.end(),
|
||||
[&](const FileRecord &record)
|
||||
{
|
||||
return name == record.name;
|
||||
});
|
||||
|
||||
if(it != fileRecords_.end())
|
||||
{
|
||||
newSelectedFilenames.insert(name);
|
||||
}
|
||||
}
|
||||
|
||||
if(inputNameBuf_ && (*inputNameBuf_)[0])
|
||||
{
|
||||
newSelectedFilenames.insert(inputNameBuf_->data());
|
||||
}
|
||||
}
|
||||
|
||||
if(newDirNameBuf_)
|
||||
{
|
||||
SameLine();
|
||||
if(SmallButton("+"))
|
||||
{
|
||||
OpenPopup(openNewDirLabel_.c_str());
|
||||
(*newDirNameBuf_)[0] = '\0';
|
||||
}
|
||||
|
||||
if(BeginPopup(openNewDirLabel_.c_str()))
|
||||
{
|
||||
ScopeGuard endNewDirPopup([] { EndPopup(); });
|
||||
|
||||
InputText("name", newDirNameBuf_->data(), newDirNameBuf_->size());
|
||||
SameLine();
|
||||
|
||||
if(Button("ok") && (*newDirNameBuf_)[0] != '\0')
|
||||
{
|
||||
ScopeGuard closeNewDirPopup([] { CloseCurrentPopup(); });
|
||||
if(create_directory(pwd_ / newDirNameBuf_->data()))
|
||||
{
|
||||
UpdateFileRecords();
|
||||
}
|
||||
else
|
||||
{
|
||||
statusStr_ = "failed to create " +
|
||||
std::string(newDirNameBuf_->data());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// browse files in a child window
|
||||
|
||||
float reserveHeight = GetFrameHeightWithSpacing();
|
||||
std::filesystem::path newPwd; bool setNewPwd = false;
|
||||
if(!(flags_ & ImGuiFileBrowserFlags_SelectDirectory) &&
|
||||
(flags_ & ImGuiFileBrowserFlags_EnterNewFilename))
|
||||
reserveHeight += GetFrameHeightWithSpacing();
|
||||
{
|
||||
BeginChild("ch", ImVec2(0, -reserveHeight), true,
|
||||
(flags_ & ImGuiFileBrowserFlags_NoModal) ?
|
||||
ImGuiWindowFlags_AlwaysHorizontalScrollbar : 0);
|
||||
ScopeGuard endChild([] { EndChild(); });
|
||||
|
||||
for(auto &rsc : fileRecords_)
|
||||
{
|
||||
if(!rsc.isDir && !IsExtensionMatched(rsc.extension))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if(!rsc.name.empty() && rsc.name.c_str()[0] == '$')
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
bool selected = selectedFilenames_.find(rsc.name)
|
||||
!= selectedFilenames_.end();
|
||||
|
||||
if(Selectable(rsc.showName.c_str(), selected,
|
||||
ImGuiSelectableFlags_DontClosePopups))
|
||||
{
|
||||
const bool multiSelect =
|
||||
(flags_ & ImGuiFileBrowserFlags_MultipleSelection) &&
|
||||
IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows) &&
|
||||
(GetIO().KeyCtrl || GetIO().KeyShift);
|
||||
|
||||
if(selected)
|
||||
{
|
||||
if(!multiSelect)
|
||||
{
|
||||
selectedFilenames_.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
selectedFilenames_.erase(rsc.name);
|
||||
}
|
||||
|
||||
(*inputNameBuf_)[0] = '\0';
|
||||
}
|
||||
else if(rsc.name != "..")
|
||||
{
|
||||
if((rsc.isDir && (flags_ & ImGuiFileBrowserFlags_SelectDirectory)) ||
|
||||
(!rsc.isDir && !(flags_ & ImGuiFileBrowserFlags_SelectDirectory)))
|
||||
{
|
||||
if(multiSelect)
|
||||
{
|
||||
selectedFilenames_.insert(rsc.name);
|
||||
}
|
||||
else
|
||||
{
|
||||
selectedFilenames_ = { rsc.name };
|
||||
}
|
||||
|
||||
if(!(flags_ & ImGuiFileBrowserFlags_SelectDirectory))
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
strcpy_s(
|
||||
inputNameBuf_->data(), inputNameBuf_->size(),
|
||||
u8StrToStr(rsc.name.u8string()).c_str());
|
||||
#else
|
||||
std::strncpy(inputNameBuf_->data(),
|
||||
u8StrToStr(rsc.name.u8string()).c_str(),
|
||||
inputNameBuf_->size() - 1);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!multiSelect)
|
||||
{
|
||||
selectedFilenames_.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(IsItemClicked(0) && IsMouseDoubleClicked(0))
|
||||
{
|
||||
if(rsc.isDir)
|
||||
{
|
||||
setNewPwd = true;
|
||||
newPwd = (rsc.name != "..") ? (pwd_ / rsc.name) :
|
||||
pwd_.parent_path();
|
||||
}
|
||||
else if(!(flags_ & ImGuiFileBrowserFlags_SelectDirectory))
|
||||
{
|
||||
selectedFilenames_ = { rsc.name };
|
||||
ok_ = true;
|
||||
CloseCurrentPopup();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(setNewPwd)
|
||||
{
|
||||
SetPwd(newPwd);
|
||||
}
|
||||
|
||||
if(!(flags_ & ImGuiFileBrowserFlags_SelectDirectory) &&
|
||||
(flags_ & ImGuiFileBrowserFlags_EnterNewFilename))
|
||||
{
|
||||
PushID(this);
|
||||
ScopeGuard popTextID([] { PopID(); });
|
||||
|
||||
PushItemWidth(-1);
|
||||
if(InputText("", inputNameBuf_->data(), inputNameBuf_->size()) &&
|
||||
inputNameBuf_->at(0) != '\0')
|
||||
{
|
||||
selectedFilenames_ = { inputNameBuf_->data() };
|
||||
}
|
||||
PopItemWidth();
|
||||
}
|
||||
|
||||
if(!(flags_ & ImGuiFileBrowserFlags_SelectDirectory))
|
||||
{
|
||||
if(Button(" ok ") && !selectedFilenames_.empty())
|
||||
{
|
||||
ok_ = true;
|
||||
CloseCurrentPopup();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(Button(" ok "))
|
||||
{
|
||||
ok_ = true;
|
||||
CloseCurrentPopup();
|
||||
}
|
||||
}
|
||||
|
||||
SameLine();
|
||||
|
||||
bool shouldExit =
|
||||
Button("cancel") || closeFlag_ ||
|
||||
((flags_ & ImGuiFileBrowserFlags_CloseOnEsc) &&
|
||||
IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows) &&
|
||||
IsKeyPressed(ImGuiKey_Escape));
|
||||
if(shouldExit)
|
||||
{
|
||||
CloseCurrentPopup();
|
||||
}
|
||||
|
||||
if(!statusStr_.empty() && !(flags_ & ImGuiFileBrowserFlags_NoStatusBar))
|
||||
{
|
||||
SameLine();
|
||||
Text("%s", statusStr_.c_str());
|
||||
}
|
||||
|
||||
if(!typeFilters_.empty())
|
||||
{
|
||||
SameLine();
|
||||
PushItemWidth(8 * GetFontSize());
|
||||
if(BeginCombo(
|
||||
"##type_filters", typeFilters_[typeFilterIndex_].c_str()))
|
||||
{
|
||||
ScopeGuard guard([&] { EndCombo(); });
|
||||
|
||||
for(size_t i = 0; i < typeFilters_.size(); ++i)
|
||||
{
|
||||
bool selected = i == typeFilterIndex_;
|
||||
if(Selectable(typeFilters_[i].c_str(), selected) && !selected)
|
||||
{
|
||||
typeFilterIndex_ = static_cast<unsigned int>(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
PopItemWidth();
|
||||
}
|
||||
}
|
||||
|
||||
inline bool ImGui::FileBrowser::HasSelected() const noexcept
|
||||
{
|
||||
return ok_;
|
||||
}
|
||||
|
||||
inline bool ImGui::FileBrowser::SetPwd(const std::filesystem::path &pwd)
|
||||
{
|
||||
try
|
||||
{
|
||||
SetPwdUncatched(pwd);
|
||||
return true;
|
||||
}
|
||||
catch(const std::exception &err)
|
||||
{
|
||||
statusStr_ = std::string("last error: ") + err.what();
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
statusStr_ = "last error: unknown";
|
||||
}
|
||||
|
||||
SetPwdUncatched(std::filesystem::current_path());
|
||||
return false;
|
||||
}
|
||||
|
||||
inline const class std::filesystem::path &ImGui::FileBrowser::GetPwd() const noexcept
|
||||
{
|
||||
return pwd_;
|
||||
}
|
||||
|
||||
inline std::filesystem::path ImGui::FileBrowser::GetSelected() const
|
||||
{
|
||||
// when ok_ is true, selectedFilenames_ may be empty if SelectDirectory
|
||||
// is enabled. return pwd in that case.
|
||||
if(selectedFilenames_.empty())
|
||||
{
|
||||
return pwd_;
|
||||
}
|
||||
return pwd_ / *selectedFilenames_.begin();
|
||||
}
|
||||
|
||||
inline std::vector<std::filesystem::path>
|
||||
ImGui::FileBrowser::GetMultiSelected() const
|
||||
{
|
||||
if(selectedFilenames_.empty())
|
||||
{
|
||||
return { pwd_ };
|
||||
}
|
||||
|
||||
std::vector<std::filesystem::path> ret;
|
||||
ret.reserve(selectedFilenames_.size());
|
||||
for(auto &s : selectedFilenames_)
|
||||
{
|
||||
ret.push_back(pwd_ / s);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline void ImGui::FileBrowser::ClearSelected()
|
||||
{
|
||||
selectedFilenames_.clear();
|
||||
(*inputNameBuf_)[0] = '\0';
|
||||
ok_ = false;
|
||||
}
|
||||
|
||||
inline void ImGui::FileBrowser::SetTypeFilters(
|
||||
const std::vector<std::string> &_typeFilters)
|
||||
{
|
||||
typeFilters_.clear();
|
||||
|
||||
// remove duplicate filter names due to case unsensitivity on windows
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
std::vector<std::string> typeFilters;
|
||||
for(auto &rawFilter : _typeFilters)
|
||||
{
|
||||
std::string lowerFilter = ToLower(rawFilter);
|
||||
auto it = std::find(typeFilters.begin(), typeFilters.end(), lowerFilter);
|
||||
if(it == typeFilters.end())
|
||||
{
|
||||
typeFilters.push_back(std::move(lowerFilter));
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
auto &typeFilters = _typeFilters;
|
||||
|
||||
#endif
|
||||
|
||||
// insert auto-generated filter
|
||||
|
||||
if(typeFilters.size() > 1)
|
||||
{
|
||||
hasAllFilter_ = true;
|
||||
std::string allFiltersName = std::string();
|
||||
for(size_t i = 0; i < typeFilters.size(); ++i)
|
||||
{
|
||||
if(typeFilters[i] == std::string_view(".*"))
|
||||
{
|
||||
hasAllFilter_ = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if(i > 0)
|
||||
{
|
||||
allFiltersName += ",";
|
||||
}
|
||||
allFiltersName += typeFilters[i];
|
||||
}
|
||||
|
||||
if(hasAllFilter_)
|
||||
{
|
||||
typeFilters_.push_back(std::move(allFiltersName));
|
||||
}
|
||||
}
|
||||
|
||||
std::copy(
|
||||
typeFilters.begin(), typeFilters.end(),
|
||||
std::back_inserter(typeFilters_));
|
||||
|
||||
typeFilterIndex_ = 0;
|
||||
}
|
||||
|
||||
inline void ImGui::FileBrowser::SetCurrentTypeFilterIndex(int index)
|
||||
{
|
||||
typeFilterIndex_ = static_cast<unsigned int>(index);
|
||||
}
|
||||
|
||||
inline void ImGui::FileBrowser::SetInputName(std::string_view input)
|
||||
{
|
||||
if(flags_ & ImGuiFileBrowserFlags_EnterNewFilename)
|
||||
{
|
||||
if(input.size() >= static_cast<size_t>(INPUT_NAME_BUF_SIZE))
|
||||
{
|
||||
// If input doesn't fit trim off characters
|
||||
input = input.substr(0, INPUT_NAME_BUF_SIZE - 1);
|
||||
}
|
||||
std::copy(input.begin(), input.end(), inputNameBuf_->begin());
|
||||
inputNameBuf_->at(input.size()) = '\0';
|
||||
selectedFilenames_ = { inputNameBuf_->data() };
|
||||
}
|
||||
}
|
||||
|
||||
inline std::string ImGui::FileBrowser::ToLower(const std::string &s)
|
||||
{
|
||||
std::string ret = s;
|
||||
for(char &c : ret)
|
||||
{
|
||||
c = static_cast<char>(std::tolower(c));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline void ImGui::FileBrowser::UpdateFileRecords()
|
||||
{
|
||||
fileRecords_ = { FileRecord{ true, "..", "[D] ..", "" } };
|
||||
|
||||
for(auto &p : std::filesystem::directory_iterator(pwd_))
|
||||
{
|
||||
FileRecord rcd;
|
||||
|
||||
if(p.is_regular_file())
|
||||
{
|
||||
rcd.isDir = false;
|
||||
}
|
||||
else if(p.is_directory())
|
||||
{
|
||||
rcd.isDir = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
rcd.name = p.path().filename();
|
||||
if(rcd.name.empty())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
rcd.extension = p.path().filename().extension();
|
||||
|
||||
rcd.showName = (rcd.isDir ? "[D] " : "[F] ") +
|
||||
u8StrToStr(p.path().filename().u8string());
|
||||
fileRecords_.push_back(rcd);
|
||||
}
|
||||
|
||||
std::sort(fileRecords_.begin(), fileRecords_.end(),
|
||||
[](const FileRecord &L, const FileRecord &R)
|
||||
{
|
||||
return (L.isDir ^ R.isDir) ? L.isDir : (L.name < R.name);
|
||||
});
|
||||
}
|
||||
|
||||
inline void ImGui::FileBrowser::SetPwdUncatched(const std::filesystem::path &pwd)
|
||||
{
|
||||
pwd_ = absolute(pwd);
|
||||
UpdateFileRecords();
|
||||
selectedFilenames_.clear();
|
||||
(*inputNameBuf_)[0] = '\0';
|
||||
}
|
||||
|
||||
inline bool ImGui::FileBrowser::IsExtensionMatched(
|
||||
const std::filesystem::path &_extension) const
|
||||
{
|
||||
#ifdef _WIN32
|
||||
std::filesystem::path extension = ToLower(_extension.string());
|
||||
#else
|
||||
auto &extension = _extension;
|
||||
#endif
|
||||
|
||||
// no type filters
|
||||
if(typeFilters_.empty())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// invalid type filter index
|
||||
if(static_cast<size_t>(typeFilterIndex_) >= typeFilters_.size())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// all type filters
|
||||
if(hasAllFilter_ && typeFilterIndex_ == 0)
|
||||
{
|
||||
for(size_t i = 1; i < typeFilters_.size(); ++i)
|
||||
{
|
||||
if(extension == typeFilters_[i])
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// universal filter
|
||||
if(typeFilters_[typeFilterIndex_] == std::string_view(".*"))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// regular filter
|
||||
return extension == typeFilters_[typeFilterIndex_];
|
||||
}
|
||||
|
||||
#if defined(__cpp_lib_char8_t)
|
||||
inline std::string ImGui::FileBrowser::u8StrToStr(std::u8string s)
|
||||
{
|
||||
return std::string(s.begin(), s.end());
|
||||
}
|
||||
#endif
|
||||
|
||||
inline std::string ImGui::FileBrowser::u8StrToStr(std::string s)
|
||||
{
|
||||
return s;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#ifndef _INC_WINDOWS
|
||||
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
|
||||
#define IMGUI_FILEBROWSER_UNDEF_WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
|
||||
#endif // #ifndef WIN32_LEAN_AND_MEAN
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#ifdef IMGUI_FILEBROWSER_UNDEF_WIN32_LEAN_AND_MEAN
|
||||
#undef IMGUI_FILEBROWSER_UNDEF_WIN32_LEAN_AND_MEAN
|
||||
#undef WIN32_LEAN_AND_MEAN
|
||||
#endif // #ifdef IMGUI_FILEBROWSER_UNDEF_WIN32_LEAN_AND_MEAN
|
||||
|
||||
#endif // #ifdef _INC_WINDOWS
|
||||
|
||||
inline std::uint32_t ImGui::FileBrowser::GetDrivesBitMask()
|
||||
{
|
||||
DWORD mask = GetLogicalDrives();
|
||||
uint32_t ret = 0;
|
||||
for(int i = 0; i < 26; ++i)
|
||||
{
|
||||
if(!(mask & (1 << i)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
char rootName[4] = { static_cast<char>('A' + i), ':', '\\', '\0' };
|
||||
UINT type = GetDriveTypeA(rootName);
|
||||
if(type == DRIVE_REMOVABLE || type == DRIVE_FIXED || type == DRIVE_REMOTE)
|
||||
{
|
||||
ret |= (1 << i);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
3585
external/imgui/imgui_internal.h
vendored
Normal file
3585
external/imgui/imgui_internal.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
742
external/imgui/imgui_memory_editor.h
vendored
Normal file
742
external/imgui/imgui_memory_editor.h
vendored
Normal file
@@ -0,0 +1,742 @@
|
||||
// Mini memory editor for Dear ImGui (to embed in your game/tools)
|
||||
// Get latest version at http://www.github.com/ocornut/imgui_club
|
||||
//
|
||||
// Right-click anywhere to access the Options menu!
|
||||
// You can adjust the keyboard repeat delay/rate in ImGuiIO.
|
||||
// The code assume a mono-space font for simplicity!
|
||||
// If you don't use the default font, use ImGui::PushFont()/PopFont() to switch to a mono-space font before calling this.
|
||||
//
|
||||
// Usage:
|
||||
// // Create a window and draw memory editor inside it:
|
||||
// static MemoryEditor mem_edit_1;
|
||||
// static char data[0x10000];
|
||||
// size_t data_size = 0x10000;
|
||||
// mem_edit_1.DrawWindow("Memory Editor", data, data_size);
|
||||
//
|
||||
// Usage:
|
||||
// // If you already have a window, use DrawContents() instead:
|
||||
// static MemoryEditor mem_edit_2;
|
||||
// ImGui::Begin("MyWindow")
|
||||
// mem_edit_2.DrawContents(this, sizeof(*this), (size_t)this);
|
||||
// ImGui::End();
|
||||
//
|
||||
// Changelog:
|
||||
// - v0.10: initial version
|
||||
// - v0.23 (2017/08/17): added to github. fixed right-arrow triggering a byte write.
|
||||
// - v0.24 (2018/06/02): changed DragInt("Rows" to use a %d data format (which is desirable since imgui 1.61).
|
||||
// - v0.25 (2018/07/11): fixed wording: all occurrences of "Rows" renamed to "Columns".
|
||||
// - v0.26 (2018/08/02): fixed clicking on hex region
|
||||
// - v0.30 (2018/08/02): added data preview for common data types
|
||||
// - v0.31 (2018/10/10): added OptUpperCaseHex option to select lower/upper casing display [@samhocevar]
|
||||
// - v0.32 (2018/10/10): changed signatures to use void* instead of unsigned char*
|
||||
// - v0.33 (2018/10/10): added OptShowOptions option to hide all the interactive option setting.
|
||||
// - v0.34 (2019/05/07): binary preview now applies endianness setting [@nicolasnoble]
|
||||
// - v0.35 (2020/01/29): using ImGuiDataType available since Dear ImGui 1.69.
|
||||
// - v0.36 (2020/05/05): minor tweaks, minor refactor.
|
||||
// - v0.40 (2020/10/04): fix misuse of ImGuiListClipper API, broke with Dear ImGui 1.79. made cursor position appears on left-side of edit box. option popup appears on mouse release. fix MSVC warnings where _CRT_SECURE_NO_WARNINGS wasn't working in recent versions.
|
||||
// - v0.41 (2020/10/05): fix when using with keyboard/gamepad navigation enabled.
|
||||
// - v0.42 (2020/10/14): fix for . character in ASCII view always being greyed out.
|
||||
// - v0.43 (2021/03/12): added OptFooterExtraHeight to allow for custom drawing at the bottom of the editor [@leiradel]
|
||||
// - v0.44 (2021/03/12): use ImGuiInputTextFlags_AlwaysOverwrite in 1.82 + fix hardcoded width.
|
||||
// - v0.50 (2021/11/12): various fixes for recent dear imgui versions (fixed misuse of clipper, relying on SetKeyboardFocusHere() handling scrolling from 1.85). added default size.
|
||||
//
|
||||
// Todo/Bugs:
|
||||
// - This is generally old/crappy code, it should work but isn't very good.. to be rewritten some day.
|
||||
// - PageUp/PageDown are supported because we use _NoNav. This is a good test scenario for working out idioms of how to mix natural nav and our own...
|
||||
// - Arrows are being sent to the InputText() about to disappear which for LeftArrow makes the text cursor appear at position 1 for one frame.
|
||||
// - Using InputText() is awkward and maybe overkill here, consider implementing something custom.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdio.h> // sprintf, scanf
|
||||
#include <stdint.h> // uint8_t, etc.
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define _PRISizeT "I"
|
||||
#define ImSnprintf _snprintf
|
||||
#else
|
||||
#define _PRISizeT "z"
|
||||
#define ImSnprintf snprintf
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning (push)
|
||||
#pragma warning (disable: 4996) // warning C4996: 'sprintf': This function or variable may be unsafe.
|
||||
#endif
|
||||
|
||||
struct MemoryEditor
|
||||
{
|
||||
enum DataFormat
|
||||
{
|
||||
DataFormat_Bin = 0,
|
||||
DataFormat_Dec = 1,
|
||||
DataFormat_Hex = 2,
|
||||
DataFormat_COUNT
|
||||
};
|
||||
|
||||
// Settings
|
||||
bool Open; // = true // set to false when DrawWindow() was closed. ignore if not using DrawWindow().
|
||||
bool ReadOnly; // = false // disable any editing.
|
||||
int Cols; // = 16 // number of columns to display.
|
||||
bool OptShowOptions; // = true // display options button/context menu. when disabled, options will be locked unless you provide your own UI for them.
|
||||
bool OptShowDataPreview; // = false // display a footer previewing the decimal/binary/hex/float representation of the currently selected bytes.
|
||||
bool OptShowHexII; // = false // display values in HexII representation instead of regular hexadecimal: hide null/zero bytes, ascii values as ".X".
|
||||
bool OptShowAscii; // = true // display ASCII representation on the right side.
|
||||
bool OptGreyOutZeroes; // = true // display null/zero bytes using the TextDisabled color.
|
||||
bool OptUpperCaseHex; // = true // display hexadecimal values as "FF" instead of "ff".
|
||||
int OptMidColsCount; // = 8 // set to 0 to disable extra spacing between every mid-cols.
|
||||
int OptAddrDigitsCount; // = 0 // number of addr digits to display (default calculated based on maximum displayed addr).
|
||||
float OptFooterExtraHeight; // = 0 // space to reserve at the bottom of the widget to add custom widgets
|
||||
ImU32 HighlightColor; // // background color of highlighted bytes.
|
||||
ImU8 (*ReadFn)(const ImU8* data, size_t off); // = 0 // optional handler to read bytes.
|
||||
void (*WriteFn)(ImU8* data, size_t off, ImU8 d); // = 0 // optional handler to write bytes.
|
||||
bool (*HighlightFn)(const ImU8* data, size_t off);//= 0 // optional handler to return Highlight property (to support non-contiguous highlighting).
|
||||
|
||||
// [Internal State]
|
||||
bool ContentsWidthChanged;
|
||||
size_t DataPreviewAddr;
|
||||
size_t DataEditingAddr;
|
||||
bool DataEditingTakeFocus;
|
||||
char DataInputBuf[32];
|
||||
char AddrInputBuf[32];
|
||||
size_t GotoAddr;
|
||||
size_t HighlightMin, HighlightMax;
|
||||
int PreviewEndianess;
|
||||
ImGuiDataType PreviewDataType;
|
||||
|
||||
MemoryEditor()
|
||||
{
|
||||
// Settings
|
||||
Open = true;
|
||||
ReadOnly = false;
|
||||
Cols = 16;
|
||||
OptShowOptions = true;
|
||||
OptShowDataPreview = false;
|
||||
OptShowHexII = false;
|
||||
OptShowAscii = true;
|
||||
OptGreyOutZeroes = true;
|
||||
OptUpperCaseHex = true;
|
||||
OptMidColsCount = 8;
|
||||
OptAddrDigitsCount = 0;
|
||||
OptFooterExtraHeight = 0.0f;
|
||||
HighlightColor = IM_COL32(255, 255, 255, 50);
|
||||
ReadFn = NULL;
|
||||
WriteFn = NULL;
|
||||
HighlightFn = NULL;
|
||||
|
||||
// State/Internals
|
||||
ContentsWidthChanged = false;
|
||||
DataPreviewAddr = DataEditingAddr = (size_t)-1;
|
||||
DataEditingTakeFocus = false;
|
||||
memset(DataInputBuf, 0, sizeof(DataInputBuf));
|
||||
memset(AddrInputBuf, 0, sizeof(AddrInputBuf));
|
||||
GotoAddr = (size_t)-1;
|
||||
HighlightMin = HighlightMax = (size_t)-1;
|
||||
PreviewEndianess = 0;
|
||||
PreviewDataType = ImGuiDataType_S32;
|
||||
}
|
||||
|
||||
void GotoAddrAndHighlight(size_t addr_min, size_t addr_max)
|
||||
{
|
||||
GotoAddr = addr_min;
|
||||
HighlightMin = addr_min;
|
||||
HighlightMax = addr_max;
|
||||
}
|
||||
|
||||
struct Sizes
|
||||
{
|
||||
int AddrDigitsCount;
|
||||
float LineHeight;
|
||||
float GlyphWidth;
|
||||
float HexCellWidth;
|
||||
float SpacingBetweenMidCols;
|
||||
float PosHexStart;
|
||||
float PosHexEnd;
|
||||
float PosAsciiStart;
|
||||
float PosAsciiEnd;
|
||||
float WindowWidth;
|
||||
|
||||
Sizes() { memset(this, 0, sizeof(*this)); }
|
||||
};
|
||||
|
||||
void CalcSizes(Sizes& s, size_t mem_size, size_t base_display_addr)
|
||||
{
|
||||
ImGuiStyle& style = ImGui::GetStyle();
|
||||
s.AddrDigitsCount = OptAddrDigitsCount;
|
||||
if (s.AddrDigitsCount == 0)
|
||||
for (size_t n = base_display_addr + mem_size - 1; n > 0; n >>= 4)
|
||||
s.AddrDigitsCount++;
|
||||
s.LineHeight = ImGui::GetTextLineHeight();
|
||||
s.GlyphWidth = ImGui::CalcTextSize("F").x + 1; // We assume the font is mono-space
|
||||
s.HexCellWidth = (float)(int)(s.GlyphWidth * 2.5f); // "FF " we include trailing space in the width to easily catch clicks everywhere
|
||||
s.SpacingBetweenMidCols = (float)(int)(s.HexCellWidth * 0.25f); // Every OptMidColsCount columns we add a bit of extra spacing
|
||||
s.PosHexStart = (s.AddrDigitsCount + 2) * s.GlyphWidth;
|
||||
s.PosHexEnd = s.PosHexStart + (s.HexCellWidth * Cols);
|
||||
s.PosAsciiStart = s.PosAsciiEnd = s.PosHexEnd;
|
||||
if (OptShowAscii)
|
||||
{
|
||||
s.PosAsciiStart = s.PosHexEnd + s.GlyphWidth * 1;
|
||||
if (OptMidColsCount > 0)
|
||||
s.PosAsciiStart += (float)((Cols + OptMidColsCount - 1) / OptMidColsCount) * s.SpacingBetweenMidCols;
|
||||
s.PosAsciiEnd = s.PosAsciiStart + Cols * s.GlyphWidth;
|
||||
}
|
||||
s.WindowWidth = s.PosAsciiEnd + style.ScrollbarSize + style.WindowPadding.x * 2 + s.GlyphWidth;
|
||||
}
|
||||
|
||||
// Standalone Memory Editor window
|
||||
void DrawWindow(const char* title, void* mem_data, size_t mem_size, size_t base_display_addr = 0x0000)
|
||||
{
|
||||
Sizes s;
|
||||
CalcSizes(s, mem_size, base_display_addr);
|
||||
ImGui::SetNextWindowSize(ImVec2(s.WindowWidth, s.WindowWidth * 0.60f), ImGuiCond_FirstUseEver);
|
||||
ImGui::SetNextWindowSizeConstraints(ImVec2(0.0f, 0.0f), ImVec2(s.WindowWidth, FLT_MAX));
|
||||
|
||||
Open = true;
|
||||
if (ImGui::Begin(title, &Open, ImGuiWindowFlags_NoScrollbar))
|
||||
{
|
||||
if (ImGui::IsWindowHovered(ImGuiHoveredFlags_RootAndChildWindows) && ImGui::IsMouseReleased(ImGuiMouseButton_Right))
|
||||
ImGui::OpenPopup("context");
|
||||
DrawContents(mem_data, mem_size, base_display_addr);
|
||||
if (ContentsWidthChanged)
|
||||
{
|
||||
CalcSizes(s, mem_size, base_display_addr);
|
||||
ImGui::SetWindowSize(ImVec2(s.WindowWidth, ImGui::GetWindowSize().y));
|
||||
}
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
// Memory Editor contents only
|
||||
void DrawContents(void* mem_data_void, size_t mem_size, size_t base_display_addr = 0x0000)
|
||||
{
|
||||
if (Cols < 1)
|
||||
Cols = 1;
|
||||
|
||||
ImU8* mem_data = (ImU8*)mem_data_void;
|
||||
Sizes s;
|
||||
CalcSizes(s, mem_size, base_display_addr);
|
||||
ImGuiStyle& style = ImGui::GetStyle();
|
||||
|
||||
// We begin into our scrolling region with the 'ImGuiWindowFlags_NoMove' in order to prevent click from moving the window.
|
||||
// This is used as a facility since our main click detection code doesn't assign an ActiveId so the click would normally be caught as a window-move.
|
||||
const float height_separator = style.ItemSpacing.y;
|
||||
float footer_height = OptFooterExtraHeight;
|
||||
if (OptShowOptions)
|
||||
footer_height += height_separator + ImGui::GetFrameHeightWithSpacing() * 1;
|
||||
if (OptShowDataPreview)
|
||||
footer_height += height_separator + ImGui::GetFrameHeightWithSpacing() * 1 + ImGui::GetTextLineHeightWithSpacing() * 3;
|
||||
ImGui::BeginChild("##scrolling", ImVec2(0, -footer_height), false, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoNav);
|
||||
ImDrawList* draw_list = ImGui::GetWindowDrawList();
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
|
||||
|
||||
// We are not really using the clipper API correctly here, because we rely on visible_start_addr/visible_end_addr for our scrolling function.
|
||||
const int line_total_count = (int)((mem_size + Cols - 1) / Cols);
|
||||
ImGuiListClipper clipper;
|
||||
clipper.Begin(line_total_count, s.LineHeight);
|
||||
|
||||
bool data_next = false;
|
||||
|
||||
if (ReadOnly || DataEditingAddr >= mem_size)
|
||||
DataEditingAddr = (size_t)-1;
|
||||
if (DataPreviewAddr >= mem_size)
|
||||
DataPreviewAddr = (size_t)-1;
|
||||
|
||||
size_t preview_data_type_size = OptShowDataPreview ? DataTypeGetSize(PreviewDataType) : 0;
|
||||
|
||||
size_t data_editing_addr_next = (size_t)-1;
|
||||
if (DataEditingAddr != (size_t)-1)
|
||||
{
|
||||
// Move cursor but only apply on next frame so scrolling with be synchronized (because currently we can't change the scrolling while the window is being rendered)
|
||||
if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_UpArrow)) && (ptrdiff_t)DataEditingAddr >= (ptrdiff_t)Cols) { data_editing_addr_next = DataEditingAddr - Cols; }
|
||||
else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_DownArrow)) && (ptrdiff_t)DataEditingAddr < (ptrdiff_t)mem_size - Cols) { data_editing_addr_next = DataEditingAddr + Cols; }
|
||||
else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_LeftArrow)) && (ptrdiff_t)DataEditingAddr > (ptrdiff_t)0) { data_editing_addr_next = DataEditingAddr - 1; }
|
||||
else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_RightArrow)) && (ptrdiff_t)DataEditingAddr < (ptrdiff_t)mem_size - 1) { data_editing_addr_next = DataEditingAddr + 1; }
|
||||
}
|
||||
|
||||
// Draw vertical separator
|
||||
ImVec2 window_pos = ImGui::GetWindowPos();
|
||||
if (OptShowAscii)
|
||||
draw_list->AddLine(ImVec2(window_pos.x + s.PosAsciiStart - s.GlyphWidth, window_pos.y), ImVec2(window_pos.x + s.PosAsciiStart - s.GlyphWidth, window_pos.y + 9999), ImGui::GetColorU32(ImGuiCol_Border));
|
||||
|
||||
const ImU32 color_text = ImGui::GetColorU32(ImGuiCol_Text);
|
||||
const ImU32 color_disabled = OptGreyOutZeroes ? ImGui::GetColorU32(ImGuiCol_TextDisabled) : color_text;
|
||||
|
||||
const char* format_address = OptUpperCaseHex ? "%0*" _PRISizeT "X: " : "%0*" _PRISizeT "x: ";
|
||||
const char* format_data = OptUpperCaseHex ? "%0*" _PRISizeT "X" : "%0*" _PRISizeT "x";
|
||||
const char* format_byte = OptUpperCaseHex ? "%02X" : "%02x";
|
||||
const char* format_byte_space = OptUpperCaseHex ? "%02X " : "%02x ";
|
||||
|
||||
while (clipper.Step())
|
||||
for (int line_i = clipper.DisplayStart; line_i < clipper.DisplayEnd; line_i++) // display only visible lines
|
||||
{
|
||||
size_t addr = (size_t)(line_i * Cols);
|
||||
ImGui::Text(format_address, s.AddrDigitsCount, base_display_addr + addr);
|
||||
|
||||
// Draw Hexadecimal
|
||||
for (int n = 0; n < Cols && addr < mem_size; n++, addr++)
|
||||
{
|
||||
float byte_pos_x = s.PosHexStart + s.HexCellWidth * n;
|
||||
if (OptMidColsCount > 0)
|
||||
byte_pos_x += (float)(n / OptMidColsCount) * s.SpacingBetweenMidCols;
|
||||
ImGui::SameLine(byte_pos_x);
|
||||
|
||||
// Draw highlight
|
||||
bool is_highlight_from_user_range = (addr >= HighlightMin && addr < HighlightMax);
|
||||
bool is_highlight_from_user_func = (HighlightFn && HighlightFn(mem_data, addr));
|
||||
bool is_highlight_from_preview = (addr >= DataPreviewAddr && addr < DataPreviewAddr + preview_data_type_size);
|
||||
if (is_highlight_from_user_range || is_highlight_from_user_func || is_highlight_from_preview)
|
||||
{
|
||||
ImVec2 pos = ImGui::GetCursorScreenPos();
|
||||
float highlight_width = s.GlyphWidth * 2;
|
||||
bool is_next_byte_highlighted = (addr + 1 < mem_size) && ((HighlightMax != (size_t)-1 && addr + 1 < HighlightMax) || (HighlightFn && HighlightFn(mem_data, addr + 1)));
|
||||
if (is_next_byte_highlighted || (n + 1 == Cols))
|
||||
{
|
||||
highlight_width = s.HexCellWidth;
|
||||
if (OptMidColsCount > 0 && n > 0 && (n + 1) < Cols && ((n + 1) % OptMidColsCount) == 0)
|
||||
highlight_width += s.SpacingBetweenMidCols;
|
||||
}
|
||||
draw_list->AddRectFilled(pos, ImVec2(pos.x + highlight_width, pos.y + s.LineHeight), HighlightColor);
|
||||
}
|
||||
|
||||
if (DataEditingAddr == addr)
|
||||
{
|
||||
// Display text input on current byte
|
||||
bool data_write = false;
|
||||
ImGui::PushID((void*)addr);
|
||||
if (DataEditingTakeFocus)
|
||||
{
|
||||
ImGui::SetKeyboardFocusHere(0);
|
||||
sprintf(AddrInputBuf, format_data, s.AddrDigitsCount, base_display_addr + addr);
|
||||
sprintf(DataInputBuf, format_byte, ReadFn ? ReadFn(mem_data, addr) : mem_data[addr]);
|
||||
}
|
||||
struct UserData
|
||||
{
|
||||
// FIXME: We should have a way to retrieve the text edit cursor position more easily in the API, this is rather tedious. This is such a ugly mess we may be better off not using InputText() at all here.
|
||||
static int Callback(ImGuiInputTextCallbackData* data)
|
||||
{
|
||||
UserData* user_data = (UserData*)data->UserData;
|
||||
if (!data->HasSelection())
|
||||
user_data->CursorPos = data->CursorPos;
|
||||
if (data->SelectionStart == 0 && data->SelectionEnd == data->BufTextLen)
|
||||
{
|
||||
// When not editing a byte, always refresh its InputText content pulled from underlying memory data
|
||||
// (this is a bit tricky, since InputText technically "owns" the master copy of the buffer we edit it in there)
|
||||
data->DeleteChars(0, data->BufTextLen);
|
||||
data->InsertChars(0, user_data->CurrentBufOverwrite);
|
||||
data->SelectionStart = 0;
|
||||
data->SelectionEnd = 2;
|
||||
data->CursorPos = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
char CurrentBufOverwrite[3]; // Input
|
||||
int CursorPos; // Output
|
||||
};
|
||||
UserData user_data;
|
||||
user_data.CursorPos = -1;
|
||||
sprintf(user_data.CurrentBufOverwrite, format_byte, ReadFn ? ReadFn(mem_data, addr) : mem_data[addr]);
|
||||
ImGuiInputTextFlags flags = ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_AutoSelectAll | ImGuiInputTextFlags_NoHorizontalScroll | ImGuiInputTextFlags_CallbackAlways;
|
||||
#if IMGUI_VERSION_NUM >= 18104
|
||||
flags |= ImGuiInputTextFlags_AlwaysOverwrite;
|
||||
#else
|
||||
flags |= ImGuiInputTextFlags_AlwaysInsertMode;
|
||||
#endif
|
||||
ImGui::SetNextItemWidth(s.GlyphWidth * 2);
|
||||
if (ImGui::InputText("##data", DataInputBuf, IM_ARRAYSIZE(DataInputBuf), flags, UserData::Callback, &user_data))
|
||||
data_write = data_next = true;
|
||||
else if (!DataEditingTakeFocus && !ImGui::IsItemActive())
|
||||
DataEditingAddr = data_editing_addr_next = (size_t)-1;
|
||||
DataEditingTakeFocus = false;
|
||||
if (user_data.CursorPos >= 2)
|
||||
data_write = data_next = true;
|
||||
if (data_editing_addr_next != (size_t)-1)
|
||||
data_write = data_next = false;
|
||||
unsigned int data_input_value = 0;
|
||||
if (data_write && sscanf(DataInputBuf, "%X", &data_input_value) == 1)
|
||||
{
|
||||
if (WriteFn)
|
||||
WriteFn(mem_data, addr, (ImU8)data_input_value);
|
||||
else
|
||||
mem_data[addr] = (ImU8)data_input_value;
|
||||
}
|
||||
ImGui::PopID();
|
||||
}
|
||||
else
|
||||
{
|
||||
// NB: The trailing space is not visible but ensure there's no gap that the mouse cannot click on.
|
||||
ImU8 b = ReadFn ? ReadFn(mem_data, addr) : mem_data[addr];
|
||||
|
||||
if (OptShowHexII)
|
||||
{
|
||||
if ((b >= 32 && b < 128))
|
||||
ImGui::Text(".%c ", b);
|
||||
else if (b == 0xFF && OptGreyOutZeroes)
|
||||
ImGui::TextDisabled("## ");
|
||||
else if (b == 0x00)
|
||||
ImGui::Text(" ");
|
||||
else
|
||||
ImGui::Text(format_byte_space, b);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (b == 0 && OptGreyOutZeroes)
|
||||
ImGui::TextDisabled("00 ");
|
||||
else
|
||||
ImGui::Text(format_byte_space, b);
|
||||
}
|
||||
if (!ReadOnly && ImGui::IsItemHovered() && ImGui::IsMouseClicked(0))
|
||||
{
|
||||
DataEditingTakeFocus = true;
|
||||
data_editing_addr_next = addr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (OptShowAscii)
|
||||
{
|
||||
// Draw ASCII values
|
||||
ImGui::SameLine(s.PosAsciiStart);
|
||||
ImVec2 pos = ImGui::GetCursorScreenPos();
|
||||
addr = line_i * Cols;
|
||||
ImGui::PushID(line_i);
|
||||
if (ImGui::InvisibleButton("ascii", ImVec2(s.PosAsciiEnd - s.PosAsciiStart, s.LineHeight)))
|
||||
{
|
||||
DataEditingAddr = DataPreviewAddr = addr + (size_t)((ImGui::GetIO().MousePos.x - pos.x) / s.GlyphWidth);
|
||||
DataEditingTakeFocus = true;
|
||||
}
|
||||
ImGui::PopID();
|
||||
for (int n = 0; n < Cols && addr < mem_size; n++, addr++)
|
||||
{
|
||||
if (addr == DataEditingAddr)
|
||||
{
|
||||
draw_list->AddRectFilled(pos, ImVec2(pos.x + s.GlyphWidth, pos.y + s.LineHeight), ImGui::GetColorU32(ImGuiCol_FrameBg));
|
||||
draw_list->AddRectFilled(pos, ImVec2(pos.x + s.GlyphWidth, pos.y + s.LineHeight), ImGui::GetColorU32(ImGuiCol_TextSelectedBg));
|
||||
}
|
||||
unsigned char c = ReadFn ? ReadFn(mem_data, addr) : mem_data[addr];
|
||||
char display_c = (c < 32 || c >= 128) ? '.' : c;
|
||||
draw_list->AddText(pos, (display_c == c) ? color_text : color_disabled, &display_c, &display_c + 1);
|
||||
pos.x += s.GlyphWidth;
|
||||
}
|
||||
}
|
||||
}
|
||||
ImGui::PopStyleVar(2);
|
||||
ImGui::EndChild();
|
||||
|
||||
// Notify the main window of our ideal child content size (FIXME: we are missing an API to get the contents size from the child)
|
||||
ImGui::SetCursorPosX(s.WindowWidth);
|
||||
|
||||
if (data_next && DataEditingAddr + 1 < mem_size)
|
||||
{
|
||||
DataEditingAddr = DataPreviewAddr = DataEditingAddr + 1;
|
||||
DataEditingTakeFocus = true;
|
||||
}
|
||||
else if (data_editing_addr_next != (size_t)-1)
|
||||
{
|
||||
DataEditingAddr = DataPreviewAddr = data_editing_addr_next;
|
||||
DataEditingTakeFocus = true;
|
||||
}
|
||||
|
||||
const bool lock_show_data_preview = OptShowDataPreview;
|
||||
if (OptShowOptions)
|
||||
{
|
||||
ImGui::Separator();
|
||||
DrawOptionsLine(s, mem_data, mem_size, base_display_addr);
|
||||
}
|
||||
|
||||
if (lock_show_data_preview)
|
||||
{
|
||||
ImGui::Separator();
|
||||
DrawPreviewLine(s, mem_data, mem_size, base_display_addr);
|
||||
}
|
||||
}
|
||||
|
||||
void DrawOptionsLine(const Sizes& s, void* mem_data, size_t mem_size, size_t base_display_addr)
|
||||
{
|
||||
IM_UNUSED(mem_data);
|
||||
ImGuiStyle& style = ImGui::GetStyle();
|
||||
const char* format_range = OptUpperCaseHex ? "Range %0*" _PRISizeT "X..%0*" _PRISizeT "X" : "Range %0*" _PRISizeT "x..%0*" _PRISizeT "x";
|
||||
|
||||
// Options menu
|
||||
if (ImGui::Button("Options"))
|
||||
ImGui::OpenPopup("context");
|
||||
if (ImGui::BeginPopup("context"))
|
||||
{
|
||||
ImGui::SetNextItemWidth(s.GlyphWidth * 7 + style.FramePadding.x * 2.0f);
|
||||
if (ImGui::DragInt("##cols", &Cols, 0.2f, 4, 32, "%d cols")) { ContentsWidthChanged = true; if (Cols < 1) Cols = 1; }
|
||||
ImGui::Checkbox("Show Data Preview", &OptShowDataPreview);
|
||||
ImGui::Checkbox("Show HexII", &OptShowHexII);
|
||||
if (ImGui::Checkbox("Show Ascii", &OptShowAscii)) { ContentsWidthChanged = true; }
|
||||
ImGui::Checkbox("Grey out zeroes", &OptGreyOutZeroes);
|
||||
ImGui::Checkbox("Uppercase Hex", &OptUpperCaseHex);
|
||||
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
ImGui::Text(format_range, s.AddrDigitsCount, base_display_addr, s.AddrDigitsCount, base_display_addr + mem_size - 1);
|
||||
ImGui::SameLine();
|
||||
ImGui::SetNextItemWidth((s.AddrDigitsCount + 1) * s.GlyphWidth + style.FramePadding.x * 2.0f);
|
||||
if (ImGui::InputText("##addr", AddrInputBuf, IM_ARRAYSIZE(AddrInputBuf), ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_EnterReturnsTrue))
|
||||
{
|
||||
size_t goto_addr;
|
||||
if (sscanf(AddrInputBuf, "%" _PRISizeT "X", &goto_addr) == 1)
|
||||
{
|
||||
GotoAddr = goto_addr - base_display_addr;
|
||||
HighlightMin = HighlightMax = (size_t)-1;
|
||||
}
|
||||
}
|
||||
|
||||
if (GotoAddr != (size_t)-1)
|
||||
{
|
||||
if (GotoAddr < mem_size)
|
||||
{
|
||||
ImGui::BeginChild("##scrolling");
|
||||
ImGui::SetScrollFromPosY(ImGui::GetCursorStartPos().y + (GotoAddr / Cols) * ImGui::GetTextLineHeight());
|
||||
ImGui::EndChild();
|
||||
DataEditingAddr = DataPreviewAddr = GotoAddr;
|
||||
DataEditingTakeFocus = true;
|
||||
}
|
||||
GotoAddr = (size_t)-1;
|
||||
}
|
||||
}
|
||||
|
||||
void DrawPreviewLine(const Sizes& s, void* mem_data_void, size_t mem_size, size_t base_display_addr)
|
||||
{
|
||||
IM_UNUSED(base_display_addr);
|
||||
ImU8* mem_data = (ImU8*)mem_data_void;
|
||||
ImGuiStyle& style = ImGui::GetStyle();
|
||||
ImGui::AlignTextToFramePadding();
|
||||
ImGui::Text("Preview as:");
|
||||
ImGui::SameLine();
|
||||
ImGui::SetNextItemWidth((s.GlyphWidth * 10.0f) + style.FramePadding.x * 2.0f + style.ItemInnerSpacing.x);
|
||||
if (ImGui::BeginCombo("##combo_type", DataTypeGetDesc(PreviewDataType), ImGuiComboFlags_HeightLargest))
|
||||
{
|
||||
for (int n = 0; n < ImGuiDataType_COUNT; n++)
|
||||
if (ImGui::Selectable(DataTypeGetDesc((ImGuiDataType)n), PreviewDataType == n))
|
||||
PreviewDataType = (ImGuiDataType)n;
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::SetNextItemWidth((s.GlyphWidth * 6.0f) + style.FramePadding.x * 2.0f + style.ItemInnerSpacing.x);
|
||||
ImGui::Combo("##combo_endianess", &PreviewEndianess, "LE\0BE\0\0");
|
||||
|
||||
char buf[128] = "";
|
||||
float x = s.GlyphWidth * 6.0f;
|
||||
bool has_value = DataPreviewAddr != (size_t)-1;
|
||||
if (has_value)
|
||||
DrawPreviewData(DataPreviewAddr, mem_data, mem_size, PreviewDataType, DataFormat_Dec, buf, (size_t)IM_ARRAYSIZE(buf));
|
||||
ImGui::Text("Dec"); ImGui::SameLine(x); ImGui::TextUnformatted(has_value ? buf : "N/A");
|
||||
if (has_value)
|
||||
DrawPreviewData(DataPreviewAddr, mem_data, mem_size, PreviewDataType, DataFormat_Hex, buf, (size_t)IM_ARRAYSIZE(buf));
|
||||
ImGui::Text("Hex"); ImGui::SameLine(x); ImGui::TextUnformatted(has_value ? buf : "N/A");
|
||||
if (has_value)
|
||||
DrawPreviewData(DataPreviewAddr, mem_data, mem_size, PreviewDataType, DataFormat_Bin, buf, (size_t)IM_ARRAYSIZE(buf));
|
||||
buf[IM_ARRAYSIZE(buf) - 1] = 0;
|
||||
ImGui::Text("Bin"); ImGui::SameLine(x); ImGui::TextUnformatted(has_value ? buf : "N/A");
|
||||
}
|
||||
|
||||
// Utilities for Data Preview
|
||||
const char* DataTypeGetDesc(ImGuiDataType data_type) const
|
||||
{
|
||||
const char* descs[] = { "Int8", "Uint8", "Int16", "Uint16", "Int32", "Uint32", "Int64", "Uint64", "Float", "Double" };
|
||||
IM_ASSERT(data_type >= 0 && data_type < ImGuiDataType_COUNT);
|
||||
return descs[data_type];
|
||||
}
|
||||
|
||||
size_t DataTypeGetSize(ImGuiDataType data_type) const
|
||||
{
|
||||
const size_t sizes[] = { 1, 1, 2, 2, 4, 4, 8, 8, sizeof(float), sizeof(double) };
|
||||
IM_ASSERT(data_type >= 0 && data_type < ImGuiDataType_COUNT);
|
||||
return sizes[data_type];
|
||||
}
|
||||
|
||||
const char* DataFormatGetDesc(DataFormat data_format) const
|
||||
{
|
||||
const char* descs[] = { "Bin", "Dec", "Hex" };
|
||||
IM_ASSERT(data_format >= 0 && data_format < DataFormat_COUNT);
|
||||
return descs[data_format];
|
||||
}
|
||||
|
||||
bool IsBigEndian() const
|
||||
{
|
||||
uint16_t x = 1;
|
||||
char c[2];
|
||||
memcpy(c, &x, 2);
|
||||
return c[0] != 0;
|
||||
}
|
||||
|
||||
static void* EndianessCopyBigEndian(void* _dst, void* _src, size_t s, int is_little_endian)
|
||||
{
|
||||
if (is_little_endian)
|
||||
{
|
||||
uint8_t* dst = (uint8_t*)_dst;
|
||||
uint8_t* src = (uint8_t*)_src + s - 1;
|
||||
for (int i = 0, n = (int)s; i < n; ++i)
|
||||
memcpy(dst++, src--, 1);
|
||||
return _dst;
|
||||
}
|
||||
else
|
||||
{
|
||||
return memcpy(_dst, _src, s);
|
||||
}
|
||||
}
|
||||
|
||||
static void* EndianessCopyLittleEndian(void* _dst, void* _src, size_t s, int is_little_endian)
|
||||
{
|
||||
if (is_little_endian)
|
||||
{
|
||||
return memcpy(_dst, _src, s);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8_t* dst = (uint8_t*)_dst;
|
||||
uint8_t* src = (uint8_t*)_src + s - 1;
|
||||
for (int i = 0, n = (int)s; i < n; ++i)
|
||||
memcpy(dst++, src--, 1);
|
||||
return _dst;
|
||||
}
|
||||
}
|
||||
|
||||
void* EndianessCopy(void* dst, void* src, size_t size) const
|
||||
{
|
||||
static void* (*fp)(void*, void*, size_t, int) = NULL;
|
||||
if (fp == NULL)
|
||||
fp = IsBigEndian() ? EndianessCopyBigEndian : EndianessCopyLittleEndian;
|
||||
return fp(dst, src, size, PreviewEndianess);
|
||||
}
|
||||
|
||||
const char* FormatBinary(const uint8_t* buf, int width) const
|
||||
{
|
||||
IM_ASSERT(width <= 64);
|
||||
size_t out_n = 0;
|
||||
static char out_buf[64 + 8 + 1];
|
||||
int n = width / 8;
|
||||
for (int j = n - 1; j >= 0; --j)
|
||||
{
|
||||
for (int i = 0; i < 8; ++i)
|
||||
out_buf[out_n++] = (buf[j] & (1 << (7 - i))) ? '1' : '0';
|
||||
out_buf[out_n++] = ' ';
|
||||
}
|
||||
IM_ASSERT(out_n < IM_ARRAYSIZE(out_buf));
|
||||
out_buf[out_n] = 0;
|
||||
return out_buf;
|
||||
}
|
||||
|
||||
// [Internal]
|
||||
void DrawPreviewData(size_t addr, const ImU8* mem_data, size_t mem_size, ImGuiDataType data_type, DataFormat data_format, char* out_buf, size_t out_buf_size) const
|
||||
{
|
||||
uint8_t buf[8];
|
||||
size_t elem_size = DataTypeGetSize(data_type);
|
||||
size_t size = addr + elem_size > mem_size ? mem_size - addr : elem_size;
|
||||
if (ReadFn)
|
||||
for (int i = 0, n = (int)size; i < n; ++i)
|
||||
buf[i] = ReadFn(mem_data, addr + i);
|
||||
else
|
||||
memcpy(buf, mem_data + addr, size);
|
||||
|
||||
if (data_format == DataFormat_Bin)
|
||||
{
|
||||
uint8_t binbuf[8];
|
||||
EndianessCopy(binbuf, buf, size);
|
||||
ImSnprintf(out_buf, out_buf_size, "%s", FormatBinary(binbuf, (int)size * 8));
|
||||
return;
|
||||
}
|
||||
|
||||
out_buf[0] = 0;
|
||||
switch (data_type)
|
||||
{
|
||||
case ImGuiDataType_S8:
|
||||
{
|
||||
int8_t int8 = 0;
|
||||
EndianessCopy(&int8, buf, size);
|
||||
if (data_format == DataFormat_Dec) { ImSnprintf(out_buf, out_buf_size, "%hhd", int8); return; }
|
||||
if (data_format == DataFormat_Hex) { ImSnprintf(out_buf, out_buf_size, "0x%02x", int8 & 0xFF); return; }
|
||||
break;
|
||||
}
|
||||
case ImGuiDataType_U8:
|
||||
{
|
||||
uint8_t uint8 = 0;
|
||||
EndianessCopy(&uint8, buf, size);
|
||||
if (data_format == DataFormat_Dec) { ImSnprintf(out_buf, out_buf_size, "%hhu", uint8); return; }
|
||||
if (data_format == DataFormat_Hex) { ImSnprintf(out_buf, out_buf_size, "0x%02x", uint8 & 0XFF); return; }
|
||||
break;
|
||||
}
|
||||
case ImGuiDataType_S16:
|
||||
{
|
||||
int16_t int16 = 0;
|
||||
EndianessCopy(&int16, buf, size);
|
||||
if (data_format == DataFormat_Dec) { ImSnprintf(out_buf, out_buf_size, "%hd", int16); return; }
|
||||
if (data_format == DataFormat_Hex) { ImSnprintf(out_buf, out_buf_size, "0x%04x", int16 & 0xFFFF); return; }
|
||||
break;
|
||||
}
|
||||
case ImGuiDataType_U16:
|
||||
{
|
||||
uint16_t uint16 = 0;
|
||||
EndianessCopy(&uint16, buf, size);
|
||||
if (data_format == DataFormat_Dec) { ImSnprintf(out_buf, out_buf_size, "%hu", uint16); return; }
|
||||
if (data_format == DataFormat_Hex) { ImSnprintf(out_buf, out_buf_size, "0x%04x", uint16 & 0xFFFF); return; }
|
||||
break;
|
||||
}
|
||||
case ImGuiDataType_S32:
|
||||
{
|
||||
int32_t int32 = 0;
|
||||
EndianessCopy(&int32, buf, size);
|
||||
if (data_format == DataFormat_Dec) { ImSnprintf(out_buf, out_buf_size, "%d", int32); return; }
|
||||
if (data_format == DataFormat_Hex) { ImSnprintf(out_buf, out_buf_size, "0x%08x", int32); return; }
|
||||
break;
|
||||
}
|
||||
case ImGuiDataType_U32:
|
||||
{
|
||||
uint32_t uint32 = 0;
|
||||
EndianessCopy(&uint32, buf, size);
|
||||
if (data_format == DataFormat_Dec) { ImSnprintf(out_buf, out_buf_size, "%u", uint32); return; }
|
||||
if (data_format == DataFormat_Hex) { ImSnprintf(out_buf, out_buf_size, "0x%08x", uint32); return; }
|
||||
break;
|
||||
}
|
||||
case ImGuiDataType_S64:
|
||||
{
|
||||
int64_t int64 = 0;
|
||||
EndianessCopy(&int64, buf, size);
|
||||
if (data_format == DataFormat_Dec) { ImSnprintf(out_buf, out_buf_size, "%lld", (long long)int64); return; }
|
||||
if (data_format == DataFormat_Hex) { ImSnprintf(out_buf, out_buf_size, "0x%016llx", (long long)int64); return; }
|
||||
break;
|
||||
}
|
||||
case ImGuiDataType_U64:
|
||||
{
|
||||
uint64_t uint64 = 0;
|
||||
EndianessCopy(&uint64, buf, size);
|
||||
if (data_format == DataFormat_Dec) { ImSnprintf(out_buf, out_buf_size, "%llu", (long long)uint64); return; }
|
||||
if (data_format == DataFormat_Hex) { ImSnprintf(out_buf, out_buf_size, "0x%016llx", (long long)uint64); return; }
|
||||
break;
|
||||
}
|
||||
case ImGuiDataType_Float:
|
||||
{
|
||||
float float32 = 0.0f;
|
||||
EndianessCopy(&float32, buf, size);
|
||||
if (data_format == DataFormat_Dec) { ImSnprintf(out_buf, out_buf_size, "%f", float32); return; }
|
||||
if (data_format == DataFormat_Hex) { ImSnprintf(out_buf, out_buf_size, "%a", float32); return; }
|
||||
break;
|
||||
}
|
||||
case ImGuiDataType_Double:
|
||||
{
|
||||
double float64 = 0.0;
|
||||
EndianessCopy(&float64, buf, size);
|
||||
if (data_format == DataFormat_Dec) { ImSnprintf(out_buf, out_buf_size, "%f", float64); return; }
|
||||
if (data_format == DataFormat_Hex) { ImSnprintf(out_buf, out_buf_size, "%a", float64); return; }
|
||||
break;
|
||||
}
|
||||
case ImGuiDataType_COUNT:
|
||||
break;
|
||||
} // Switch
|
||||
IM_ASSERT(0); // Shouldn't reach
|
||||
}
|
||||
};
|
||||
|
||||
#undef _PRISizeT
|
||||
#undef ImSnprintf
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning (pop)
|
||||
#endif
|
||||
85
external/imgui/imgui_stdlib.cpp
vendored
Normal file
85
external/imgui/imgui_stdlib.cpp
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
// 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
|
||||
|
||||
#include "imgui.h"
|
||||
#include "imgui_stdlib.h"
|
||||
|
||||
// Clang warnings with -Weverything
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness
|
||||
#endif
|
||||
|
||||
struct InputTextCallback_UserData
|
||||
{
|
||||
std::string* Str;
|
||||
ImGuiInputTextCallback ChainCallback;
|
||||
void* ChainCallbackUserData;
|
||||
};
|
||||
|
||||
static int InputTextCallback(ImGuiInputTextCallbackData* data)
|
||||
{
|
||||
InputTextCallback_UserData* user_data = (InputTextCallback_UserData*)data->UserData;
|
||||
if (data->EventFlag == ImGuiInputTextFlags_CallbackResize)
|
||||
{
|
||||
// Resize string callback
|
||||
// If for some reason we refuse the new length (BufTextLen) and/or capacity (BufSize) we need to set them back to what we want.
|
||||
std::string* str = user_data->Str;
|
||||
IM_ASSERT(data->Buf == str->c_str());
|
||||
str->resize(data->BufTextLen);
|
||||
data->Buf = (char*)str->c_str();
|
||||
}
|
||||
else if (user_data->ChainCallback)
|
||||
{
|
||||
// Forward to user callback, if any
|
||||
data->UserData = user_data->ChainCallbackUserData;
|
||||
return user_data->ChainCallback(data);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool ImGui::InputText(const char* label, std::string* str, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data)
|
||||
{
|
||||
IM_ASSERT((flags & ImGuiInputTextFlags_CallbackResize) == 0);
|
||||
flags |= ImGuiInputTextFlags_CallbackResize;
|
||||
|
||||
InputTextCallback_UserData cb_user_data;
|
||||
cb_user_data.Str = str;
|
||||
cb_user_data.ChainCallback = callback;
|
||||
cb_user_data.ChainCallbackUserData = user_data;
|
||||
return InputText(label, (char*)str->c_str(), str->capacity() + 1, flags, InputTextCallback, &cb_user_data);
|
||||
}
|
||||
|
||||
bool ImGui::InputTextMultiline(const char* label, std::string* str, const ImVec2& size, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data)
|
||||
{
|
||||
IM_ASSERT((flags & ImGuiInputTextFlags_CallbackResize) == 0);
|
||||
flags |= ImGuiInputTextFlags_CallbackResize;
|
||||
|
||||
InputTextCallback_UserData cb_user_data;
|
||||
cb_user_data.Str = str;
|
||||
cb_user_data.ChainCallback = callback;
|
||||
cb_user_data.ChainCallbackUserData = user_data;
|
||||
return InputTextMultiline(label, (char*)str->c_str(), str->capacity() + 1, size, flags, InputTextCallback, &cb_user_data);
|
||||
}
|
||||
|
||||
bool ImGui::InputTextWithHint(const char* label, const char* hint, std::string* str, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data)
|
||||
{
|
||||
IM_ASSERT((flags & ImGuiInputTextFlags_CallbackResize) == 0);
|
||||
flags |= ImGuiInputTextFlags_CallbackResize;
|
||||
|
||||
InputTextCallback_UserData cb_user_data;
|
||||
cb_user_data.Str = str;
|
||||
cb_user_data.ChainCallback = callback;
|
||||
cb_user_data.ChainCallbackUserData = user_data;
|
||||
return InputTextWithHint(label, hint, (char*)str->c_str(), str->capacity() + 1, flags, InputTextCallback, &cb_user_data);
|
||||
}
|
||||
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
21
external/imgui/imgui_stdlib.h
vendored
Normal file
21
external/imgui/imgui_stdlib.h
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
// dear imgui: wrappers for C++ standard library (STL) types (std::string, etc.)
|
||||
// This is also an example of how you may wrap your own similar types.
|
||||
|
||||
// Changelog:
|
||||
// - v0.10: Initial version. Added InputText() / InputTextMultiline() calls with std::string
|
||||
|
||||
// See more C++ related extension (fmt, RAII, syntaxis sugar) on Wiki:
|
||||
// https://github.com/ocornut/imgui/wiki/Useful-Extensions#cness
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
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, std::string* str, ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = nullptr, void* user_data = nullptr);
|
||||
IMGUI_API bool InputTextMultiline(const char* label, std::string* str, const ImVec2& size = ImVec2(0, 0), ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = nullptr, void* user_data = nullptr);
|
||||
IMGUI_API bool InputTextWithHint(const char* label, const char* hint, std::string* str, ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = nullptr, void* user_data = nullptr);
|
||||
}
|
||||
4117
external/imgui/imgui_tables.cpp
vendored
Normal file
4117
external/imgui/imgui_tables.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
8765
external/imgui/imgui_widgets.cpp
vendored
Normal file
8765
external/imgui/imgui_widgets.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
627
external/imgui/imstb_rectpack.h
vendored
Normal file
627
external/imgui/imstb_rectpack.h
vendored
Normal file
@@ -0,0 +1,627 @@
|
||||
// [DEAR IMGUI]
|
||||
// This is a slightly modified version of stb_rect_pack.h 1.01.
|
||||
// Grep for [DEAR IMGUI] to find the changes.
|
||||
//
|
||||
// stb_rect_pack.h - v1.01 - public domain - rectangle packing
|
||||
// Sean Barrett 2014
|
||||
//
|
||||
// Useful for e.g. packing rectangular textures into an atlas.
|
||||
// Does not do rotation.
|
||||
//
|
||||
// Before #including,
|
||||
//
|
||||
// #define STB_RECT_PACK_IMPLEMENTATION
|
||||
//
|
||||
// in the file that you want to have the implementation.
|
||||
//
|
||||
// Not necessarily the awesomest packing method, but better than
|
||||
// the totally naive one in stb_truetype (which is primarily what
|
||||
// this is meant to replace).
|
||||
//
|
||||
// Has only had a few tests run, may have issues.
|
||||
//
|
||||
// More docs to come.
|
||||
//
|
||||
// No memory allocations; uses qsort() and assert() from stdlib.
|
||||
// Can override those by defining STBRP_SORT and STBRP_ASSERT.
|
||||
//
|
||||
// This library currently uses the Skyline Bottom-Left algorithm.
|
||||
//
|
||||
// Please note: better rectangle packers are welcome! Please
|
||||
// implement them to the same API, but with a different init
|
||||
// function.
|
||||
//
|
||||
// Credits
|
||||
//
|
||||
// Library
|
||||
// Sean Barrett
|
||||
// Minor features
|
||||
// Martins Mozeiko
|
||||
// github:IntellectualKitty
|
||||
//
|
||||
// Bugfixes / warning fixes
|
||||
// Jeremy Jaussaud
|
||||
// Fabian Giesen
|
||||
//
|
||||
// Version history:
|
||||
//
|
||||
// 1.01 (2021-07-11) always use large rect mode, expose STBRP__MAXVAL in public section
|
||||
// 1.00 (2019-02-25) avoid small space waste; gracefully fail too-wide rectangles
|
||||
// 0.99 (2019-02-07) warning fixes
|
||||
// 0.11 (2017-03-03) return packing success/fail result
|
||||
// 0.10 (2016-10-25) remove cast-away-const to avoid warnings
|
||||
// 0.09 (2016-08-27) fix compiler warnings
|
||||
// 0.08 (2015-09-13) really fix bug with empty rects (w=0 or h=0)
|
||||
// 0.07 (2015-09-13) fix bug with empty rects (w=0 or h=0)
|
||||
// 0.06 (2015-04-15) added STBRP_SORT to allow replacing qsort
|
||||
// 0.05: added STBRP_ASSERT to allow replacing assert
|
||||
// 0.04: fixed minor bug in STBRP_LARGE_RECTS support
|
||||
// 0.01: initial release
|
||||
//
|
||||
// LICENSE
|
||||
//
|
||||
// See end of file for license information.
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// INCLUDE SECTION
|
||||
//
|
||||
|
||||
#ifndef STB_INCLUDE_STB_RECT_PACK_H
|
||||
#define STB_INCLUDE_STB_RECT_PACK_H
|
||||
|
||||
#define STB_RECT_PACK_VERSION 1
|
||||
|
||||
#ifdef STBRP_STATIC
|
||||
#define STBRP_DEF static
|
||||
#else
|
||||
#define STBRP_DEF extern
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct stbrp_context stbrp_context;
|
||||
typedef struct stbrp_node stbrp_node;
|
||||
typedef struct stbrp_rect stbrp_rect;
|
||||
|
||||
typedef int stbrp_coord;
|
||||
|
||||
#define STBRP__MAXVAL 0x7fffffff
|
||||
// Mostly for internal use, but this is the maximum supported coordinate value.
|
||||
|
||||
STBRP_DEF int stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects);
|
||||
// Assign packed locations to rectangles. The rectangles are of type
|
||||
// 'stbrp_rect' defined below, stored in the array 'rects', and there
|
||||
// are 'num_rects' many of them.
|
||||
//
|
||||
// Rectangles which are successfully packed have the 'was_packed' flag
|
||||
// set to a non-zero value and 'x' and 'y' store the minimum location
|
||||
// on each axis (i.e. bottom-left in cartesian coordinates, top-left
|
||||
// if you imagine y increasing downwards). Rectangles which do not fit
|
||||
// have the 'was_packed' flag set to 0.
|
||||
//
|
||||
// You should not try to access the 'rects' array from another thread
|
||||
// while this function is running, as the function temporarily reorders
|
||||
// the array while it executes.
|
||||
//
|
||||
// To pack into another rectangle, you need to call stbrp_init_target
|
||||
// again. To continue packing into the same rectangle, you can call
|
||||
// this function again. Calling this multiple times with multiple rect
|
||||
// arrays will probably produce worse packing results than calling it
|
||||
// a single time with the full rectangle array, but the option is
|
||||
// available.
|
||||
//
|
||||
// The function returns 1 if all of the rectangles were successfully
|
||||
// packed and 0 otherwise.
|
||||
|
||||
struct stbrp_rect
|
||||
{
|
||||
// reserved for your use:
|
||||
int id;
|
||||
|
||||
// input:
|
||||
stbrp_coord w, h;
|
||||
|
||||
// output:
|
||||
stbrp_coord x, y;
|
||||
int was_packed; // non-zero if valid packing
|
||||
|
||||
}; // 16 bytes, nominally
|
||||
|
||||
|
||||
STBRP_DEF void stbrp_init_target (stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes);
|
||||
// Initialize a rectangle packer to:
|
||||
// pack a rectangle that is 'width' by 'height' in dimensions
|
||||
// using temporary storage provided by the array 'nodes', which is 'num_nodes' long
|
||||
//
|
||||
// You must call this function every time you start packing into a new target.
|
||||
//
|
||||
// There is no "shutdown" function. The 'nodes' memory must stay valid for
|
||||
// the following stbrp_pack_rects() call (or calls), but can be freed after
|
||||
// the call (or calls) finish.
|
||||
//
|
||||
// Note: to guarantee best results, either:
|
||||
// 1. make sure 'num_nodes' >= 'width'
|
||||
// or 2. call stbrp_allow_out_of_mem() defined below with 'allow_out_of_mem = 1'
|
||||
//
|
||||
// If you don't do either of the above things, widths will be quantized to multiples
|
||||
// of small integers to guarantee the algorithm doesn't run out of temporary storage.
|
||||
//
|
||||
// If you do #2, then the non-quantized algorithm will be used, but the algorithm
|
||||
// may run out of temporary storage and be unable to pack some rectangles.
|
||||
|
||||
STBRP_DEF void stbrp_setup_allow_out_of_mem (stbrp_context *context, int allow_out_of_mem);
|
||||
// Optionally call this function after init but before doing any packing to
|
||||
// change the handling of the out-of-temp-memory scenario, described above.
|
||||
// If you call init again, this will be reset to the default (false).
|
||||
|
||||
|
||||
STBRP_DEF void stbrp_setup_heuristic (stbrp_context *context, int heuristic);
|
||||
// Optionally select which packing heuristic the library should use. Different
|
||||
// heuristics will produce better/worse results for different data sets.
|
||||
// If you call init again, this will be reset to the default.
|
||||
|
||||
enum
|
||||
{
|
||||
STBRP_HEURISTIC_Skyline_default=0,
|
||||
STBRP_HEURISTIC_Skyline_BL_sortHeight = STBRP_HEURISTIC_Skyline_default,
|
||||
STBRP_HEURISTIC_Skyline_BF_sortHeight
|
||||
};
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// the details of the following structures don't matter to you, but they must
|
||||
// be visible so you can handle the memory allocations for them
|
||||
|
||||
struct stbrp_node
|
||||
{
|
||||
stbrp_coord x,y;
|
||||
stbrp_node *next;
|
||||
};
|
||||
|
||||
struct stbrp_context
|
||||
{
|
||||
int width;
|
||||
int height;
|
||||
int align;
|
||||
int init_mode;
|
||||
int heuristic;
|
||||
int num_nodes;
|
||||
stbrp_node *active_head;
|
||||
stbrp_node *free_head;
|
||||
stbrp_node extra[2]; // we allocate two extra nodes so optimal user-node-count is 'width' not 'width+2'
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPLEMENTATION SECTION
|
||||
//
|
||||
|
||||
#ifdef STB_RECT_PACK_IMPLEMENTATION
|
||||
#ifndef STBRP_SORT
|
||||
#include <stdlib.h>
|
||||
#define STBRP_SORT qsort
|
||||
#endif
|
||||
|
||||
#ifndef STBRP_ASSERT
|
||||
#include <assert.h>
|
||||
#define STBRP_ASSERT assert
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define STBRP__NOTUSED(v) (void)(v)
|
||||
#define STBRP__CDECL __cdecl
|
||||
#else
|
||||
#define STBRP__NOTUSED(v) (void)sizeof(v)
|
||||
#define STBRP__CDECL
|
||||
#endif
|
||||
|
||||
enum
|
||||
{
|
||||
STBRP__INIT_skyline = 1
|
||||
};
|
||||
|
||||
STBRP_DEF void stbrp_setup_heuristic(stbrp_context *context, int heuristic)
|
||||
{
|
||||
switch (context->init_mode) {
|
||||
case STBRP__INIT_skyline:
|
||||
STBRP_ASSERT(heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight || heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight);
|
||||
context->heuristic = heuristic;
|
||||
break;
|
||||
default:
|
||||
STBRP_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
STBRP_DEF void stbrp_setup_allow_out_of_mem(stbrp_context *context, int allow_out_of_mem)
|
||||
{
|
||||
if (allow_out_of_mem)
|
||||
// if it's ok to run out of memory, then don't bother aligning them;
|
||||
// this gives better packing, but may fail due to OOM (even though
|
||||
// the rectangles easily fit). @TODO a smarter approach would be to only
|
||||
// quantize once we've hit OOM, then we could get rid of this parameter.
|
||||
context->align = 1;
|
||||
else {
|
||||
// if it's not ok to run out of memory, then quantize the widths
|
||||
// so that num_nodes is always enough nodes.
|
||||
//
|
||||
// I.e. num_nodes * align >= width
|
||||
// align >= width / num_nodes
|
||||
// align = ceil(width/num_nodes)
|
||||
|
||||
context->align = (context->width + context->num_nodes-1) / context->num_nodes;
|
||||
}
|
||||
}
|
||||
|
||||
STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i < num_nodes-1; ++i)
|
||||
nodes[i].next = &nodes[i+1];
|
||||
nodes[i].next = NULL;
|
||||
context->init_mode = STBRP__INIT_skyline;
|
||||
context->heuristic = STBRP_HEURISTIC_Skyline_default;
|
||||
context->free_head = &nodes[0];
|
||||
context->active_head = &context->extra[0];
|
||||
context->width = width;
|
||||
context->height = height;
|
||||
context->num_nodes = num_nodes;
|
||||
stbrp_setup_allow_out_of_mem(context, 0);
|
||||
|
||||
// node 0 is the full width, node 1 is the sentinel (lets us not store width explicitly)
|
||||
context->extra[0].x = 0;
|
||||
context->extra[0].y = 0;
|
||||
context->extra[0].next = &context->extra[1];
|
||||
context->extra[1].x = (stbrp_coord) width;
|
||||
context->extra[1].y = (1<<30);
|
||||
context->extra[1].next = NULL;
|
||||
}
|
||||
|
||||
// find minimum y position if it starts at x1
|
||||
static int stbrp__skyline_find_min_y(stbrp_context *c, stbrp_node *first, int x0, int width, int *pwaste)
|
||||
{
|
||||
stbrp_node *node = first;
|
||||
int x1 = x0 + width;
|
||||
int min_y, visited_width, waste_area;
|
||||
|
||||
STBRP__NOTUSED(c);
|
||||
|
||||
STBRP_ASSERT(first->x <= x0);
|
||||
|
||||
#if 0
|
||||
// skip in case we're past the node
|
||||
while (node->next->x <= x0)
|
||||
++node;
|
||||
#else
|
||||
STBRP_ASSERT(node->next->x > x0); // we ended up handling this in the caller for efficiency
|
||||
#endif
|
||||
|
||||
STBRP_ASSERT(node->x <= x0);
|
||||
|
||||
min_y = 0;
|
||||
waste_area = 0;
|
||||
visited_width = 0;
|
||||
while (node->x < x1) {
|
||||
if (node->y > min_y) {
|
||||
// raise min_y higher.
|
||||
// we've accounted for all waste up to min_y,
|
||||
// but we'll now add more waste for everything we've visted
|
||||
waste_area += visited_width * (node->y - min_y);
|
||||
min_y = node->y;
|
||||
// the first time through, visited_width might be reduced
|
||||
if (node->x < x0)
|
||||
visited_width += node->next->x - x0;
|
||||
else
|
||||
visited_width += node->next->x - node->x;
|
||||
} else {
|
||||
// add waste area
|
||||
int under_width = node->next->x - node->x;
|
||||
if (under_width + visited_width > width)
|
||||
under_width = width - visited_width;
|
||||
waste_area += under_width * (min_y - node->y);
|
||||
visited_width += under_width;
|
||||
}
|
||||
node = node->next;
|
||||
}
|
||||
|
||||
*pwaste = waste_area;
|
||||
return min_y;
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int x,y;
|
||||
stbrp_node **prev_link;
|
||||
} stbrp__findresult;
|
||||
|
||||
static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int width, int height)
|
||||
{
|
||||
int best_waste = (1<<30), best_x, best_y = (1 << 30);
|
||||
stbrp__findresult fr;
|
||||
stbrp_node **prev, *node, *tail, **best = NULL;
|
||||
|
||||
// align to multiple of c->align
|
||||
width = (width + c->align - 1);
|
||||
width -= width % c->align;
|
||||
STBRP_ASSERT(width % c->align == 0);
|
||||
|
||||
// if it can't possibly fit, bail immediately
|
||||
if (width > c->width || height > c->height) {
|
||||
fr.prev_link = NULL;
|
||||
fr.x = fr.y = 0;
|
||||
return fr;
|
||||
}
|
||||
|
||||
node = c->active_head;
|
||||
prev = &c->active_head;
|
||||
while (node->x + width <= c->width) {
|
||||
int y,waste;
|
||||
y = stbrp__skyline_find_min_y(c, node, node->x, width, &waste);
|
||||
if (c->heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight) { // actually just want to test BL
|
||||
// bottom left
|
||||
if (y < best_y) {
|
||||
best_y = y;
|
||||
best = prev;
|
||||
}
|
||||
} else {
|
||||
// best-fit
|
||||
if (y + height <= c->height) {
|
||||
// can only use it if it first vertically
|
||||
if (y < best_y || (y == best_y && waste < best_waste)) {
|
||||
best_y = y;
|
||||
best_waste = waste;
|
||||
best = prev;
|
||||
}
|
||||
}
|
||||
}
|
||||
prev = &node->next;
|
||||
node = node->next;
|
||||
}
|
||||
|
||||
best_x = (best == NULL) ? 0 : (*best)->x;
|
||||
|
||||
// if doing best-fit (BF), we also have to try aligning right edge to each node position
|
||||
//
|
||||
// e.g, if fitting
|
||||
//
|
||||
// ____________________
|
||||
// |____________________|
|
||||
//
|
||||
// into
|
||||
//
|
||||
// | |
|
||||
// | ____________|
|
||||
// |____________|
|
||||
//
|
||||
// then right-aligned reduces waste, but bottom-left BL is always chooses left-aligned
|
||||
//
|
||||
// This makes BF take about 2x the time
|
||||
|
||||
if (c->heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight) {
|
||||
tail = c->active_head;
|
||||
node = c->active_head;
|
||||
prev = &c->active_head;
|
||||
// find first node that's admissible
|
||||
while (tail->x < width)
|
||||
tail = tail->next;
|
||||
while (tail) {
|
||||
int xpos = tail->x - width;
|
||||
int y,waste;
|
||||
STBRP_ASSERT(xpos >= 0);
|
||||
// find the left position that matches this
|
||||
while (node->next->x <= xpos) {
|
||||
prev = &node->next;
|
||||
node = node->next;
|
||||
}
|
||||
STBRP_ASSERT(node->next->x > xpos && node->x <= xpos);
|
||||
y = stbrp__skyline_find_min_y(c, node, xpos, width, &waste);
|
||||
if (y + height <= c->height) {
|
||||
if (y <= best_y) {
|
||||
if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) {
|
||||
best_x = xpos;
|
||||
//STBRP_ASSERT(y <= best_y); [DEAR IMGUI]
|
||||
best_y = y;
|
||||
best_waste = waste;
|
||||
best = prev;
|
||||
}
|
||||
}
|
||||
}
|
||||
tail = tail->next;
|
||||
}
|
||||
}
|
||||
|
||||
fr.prev_link = best;
|
||||
fr.x = best_x;
|
||||
fr.y = best_y;
|
||||
return fr;
|
||||
}
|
||||
|
||||
static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, int width, int height)
|
||||
{
|
||||
// find best position according to heuristic
|
||||
stbrp__findresult res = stbrp__skyline_find_best_pos(context, width, height);
|
||||
stbrp_node *node, *cur;
|
||||
|
||||
// bail if:
|
||||
// 1. it failed
|
||||
// 2. the best node doesn't fit (we don't always check this)
|
||||
// 3. we're out of memory
|
||||
if (res.prev_link == NULL || res.y + height > context->height || context->free_head == NULL) {
|
||||
res.prev_link = NULL;
|
||||
return res;
|
||||
}
|
||||
|
||||
// on success, create new node
|
||||
node = context->free_head;
|
||||
node->x = (stbrp_coord) res.x;
|
||||
node->y = (stbrp_coord) (res.y + height);
|
||||
|
||||
context->free_head = node->next;
|
||||
|
||||
// insert the new node into the right starting point, and
|
||||
// let 'cur' point to the remaining nodes needing to be
|
||||
// stiched back in
|
||||
|
||||
cur = *res.prev_link;
|
||||
if (cur->x < res.x) {
|
||||
// preserve the existing one, so start testing with the next one
|
||||
stbrp_node *next = cur->next;
|
||||
cur->next = node;
|
||||
cur = next;
|
||||
} else {
|
||||
*res.prev_link = node;
|
||||
}
|
||||
|
||||
// from here, traverse cur and free the nodes, until we get to one
|
||||
// that shouldn't be freed
|
||||
while (cur->next && cur->next->x <= res.x + width) {
|
||||
stbrp_node *next = cur->next;
|
||||
// move the current node to the free list
|
||||
cur->next = context->free_head;
|
||||
context->free_head = cur;
|
||||
cur = next;
|
||||
}
|
||||
|
||||
// stitch the list back in
|
||||
node->next = cur;
|
||||
|
||||
if (cur->x < res.x + width)
|
||||
cur->x = (stbrp_coord) (res.x + width);
|
||||
|
||||
#ifdef _DEBUG
|
||||
cur = context->active_head;
|
||||
while (cur->x < context->width) {
|
||||
STBRP_ASSERT(cur->x < cur->next->x);
|
||||
cur = cur->next;
|
||||
}
|
||||
STBRP_ASSERT(cur->next == NULL);
|
||||
|
||||
{
|
||||
int count=0;
|
||||
cur = context->active_head;
|
||||
while (cur) {
|
||||
cur = cur->next;
|
||||
++count;
|
||||
}
|
||||
cur = context->free_head;
|
||||
while (cur) {
|
||||
cur = cur->next;
|
||||
++count;
|
||||
}
|
||||
STBRP_ASSERT(count == context->num_nodes+2);
|
||||
}
|
||||
#endif
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int STBRP__CDECL rect_height_compare(const void *a, const void *b)
|
||||
{
|
||||
const stbrp_rect *p = (const stbrp_rect *) a;
|
||||
const stbrp_rect *q = (const stbrp_rect *) b;
|
||||
if (p->h > q->h)
|
||||
return -1;
|
||||
if (p->h < q->h)
|
||||
return 1;
|
||||
return (p->w > q->w) ? -1 : (p->w < q->w);
|
||||
}
|
||||
|
||||
static int STBRP__CDECL rect_original_order(const void *a, const void *b)
|
||||
{
|
||||
const stbrp_rect *p = (const stbrp_rect *) a;
|
||||
const stbrp_rect *q = (const stbrp_rect *) b;
|
||||
return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed);
|
||||
}
|
||||
|
||||
STBRP_DEF int stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects)
|
||||
{
|
||||
int i, all_rects_packed = 1;
|
||||
|
||||
// we use the 'was_packed' field internally to allow sorting/unsorting
|
||||
for (i=0; i < num_rects; ++i) {
|
||||
rects[i].was_packed = i;
|
||||
}
|
||||
|
||||
// sort according to heuristic
|
||||
STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_height_compare);
|
||||
|
||||
for (i=0; i < num_rects; ++i) {
|
||||
if (rects[i].w == 0 || rects[i].h == 0) {
|
||||
rects[i].x = rects[i].y = 0; // empty rect needs no space
|
||||
} else {
|
||||
stbrp__findresult fr = stbrp__skyline_pack_rectangle(context, rects[i].w, rects[i].h);
|
||||
if (fr.prev_link) {
|
||||
rects[i].x = (stbrp_coord) fr.x;
|
||||
rects[i].y = (stbrp_coord) fr.y;
|
||||
} else {
|
||||
rects[i].x = rects[i].y = STBRP__MAXVAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// unsort
|
||||
STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_original_order);
|
||||
|
||||
// set was_packed flags and all_rects_packed status
|
||||
for (i=0; i < num_rects; ++i) {
|
||||
rects[i].was_packed = !(rects[i].x == STBRP__MAXVAL && rects[i].y == STBRP__MAXVAL);
|
||||
if (!rects[i].was_packed)
|
||||
all_rects_packed = 0;
|
||||
}
|
||||
|
||||
// return the all_rects_packed status
|
||||
return all_rects_packed;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
------------------------------------------------------------------------------
|
||||
This software is available under 2 licenses -- choose whichever you prefer.
|
||||
------------------------------------------------------------------------------
|
||||
ALTERNATIVE A - MIT License
|
||||
Copyright (c) 2017 Sean Barrett
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
------------------------------------------------------------------------------
|
||||
ALTERNATIVE B - Public Domain (www.unlicense.org)
|
||||
This is free and unencumbered software released into the public domain.
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
|
||||
software, either in source code form or as a compiled binary, for any purpose,
|
||||
commercial or non-commercial, and by any means.
|
||||
In jurisdictions that recognize copyright laws, the author or authors of this
|
||||
software dedicate any and all copyright interest in the software to the public
|
||||
domain. We make this dedication for the benefit of the public at large and to
|
||||
the detriment of our heirs and successors. We intend this dedication to be an
|
||||
overt act of relinquishment in perpetuity of all present and future rights to
|
||||
this software under copyright law.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
------------------------------------------------------------------------------
|
||||
*/
|
||||
1437
external/imgui/imstb_textedit.h
vendored
Normal file
1437
external/imgui/imstb_textedit.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
5085
external/imgui/imstb_truetype.h
vendored
Normal file
5085
external/imgui/imstb_truetype.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user