Compare commits

...

42 Commits

Author SHA1 Message Date
Nik
811214ddb7 build: Bump version to v1.35.4 2024-07-09 08:09:55 +02:00
WerWolv
cb406ea357 build: Fix lzma support and simplify zstd building 2024-07-09 07:29:06 +02:00
WerWolv
edb1a8876b fix: Multiple definitions errors with plugin features 2024-07-09 07:21:45 +02:00
WerWolv
2757075a10 impr: Make highlight hovering more efficient 2024-07-09 07:21:39 +02:00
WerWolv
8a4599feea impr: Disable pattern debug mode after evaluation has finished 2024-07-09 07:21:33 +02:00
WerWolv
f8f47012c4 build: Streamline definition on plugin features 2024-07-09 07:21:25 +02:00
WerWolv
32e2ccbca0 git: Update Mesa3D link for Windows NoGPU version 2024-07-09 07:20:48 +02:00
WerWolv
4d1e29d747 fix: Build issue due to uncaptured this pointer 2024-07-09 07:20:18 +02:00
WerWolv
22dc3c6589 fix: Crash on macOS when dirtying or undirtying a provider from a thread
Fixes #1799
2024-07-09 07:20:06 +02:00
WerWolv
1c2bb0c049 fix: Hex editor popups getting transparent when hovering over combo box popup 2024-07-09 07:19:59 +02:00
WerWolv
5d53417683 web: Trigger right click when long touching area 2024-07-09 07:19:50 +02:00
WerWolv
c79321b550 web: Fix canvas to the top left of the screen 2024-07-09 07:19:43 +02:00
WerWolv
0785270dfa fix: Remove unnecessary touch padding 2024-07-09 07:19:33 +02:00
WerWolv
84999d5c06 web: Improve logo size on mobile 2024-07-09 07:19:27 +02:00
WerWolv
a0ca0e8596 fix: Make sure welcome screen always stays in the background 2024-07-09 07:19:16 +02:00
WerWolv
1d99f8534d web: Fix touch input 2024-07-09 07:19:11 +02:00
WerWolv
cfbc6e085a fix: Wrong start/end offset and size for static array entries in pattern data view 2024-07-09 07:18:49 +02:00
WerWolv
a45d30edca impr: Added tooltips to toolbar buttons 2024-07-09 07:18:20 +02:00
Bernard Teo
5a053aa146 build: Update nativefiledialog and keep dialogs on top (#1771)
This PR updates the nativefiledialog submodule and uses its new feature
to set the ImHex main window as the parent of the dialog window. This
ensures that the dialog stays on top of the main window. This is
currently supported by NFDe on Windows, macOS, and Linux/X11.
Linux/Wayland behaves as it did previously due to limitations in NFDe.

Note that macOS file dialogs have already been parented properly as NFDe
previously used the key window (the window currently receiving keyboard
events) on macOS. However, it's probably better to do the correct thing
and pass the main window to NFDe even on macOS.

### Problem description
The file dialog go behind the main window if the main window is clicked
while the file dialog is open.

### Implementation description
Update nativefiledialog and pass the `GLFWwindow*` of the main window to
the library function.

### Screenshots
Before:


https://github.com/WerWolv/ImHex/assets/6948096/589c3401-702a-4b0a-99ed-02d3e4d9080e

After:


https://github.com/WerWolv/ImHex/assets/6948096/8fef4900-eedc-48d5-8a4e-7bd81e37e3c0

### Additional things
I have tested this on Windows and Linux/X11, but did not test this on
macOS. It would be ideal if someone can help with this. (But as far as
NFDe is concerned, macOS `NSWindow*` handles have been tested (with
SDL2) and works.)

Co-authored-by: Nik <werwolv98@gmail.com>
2024-07-09 07:17:59 +02:00
WerWolv
d5a69d9201 fix: Remove interactive help debug code 2024-07-09 07:17:50 +02:00
WerWolv
dd0204f31d impr: Added nicer console warning when .NET runtime isn't installed 2024-07-09 07:17:37 +02:00
WerWolv
3b799388c2 web: Improved canvas webgl creation logic 2024-07-09 07:17:33 +02:00
WerWolv
c7c4ecad6d impr: Improved size display in pattern data view 2024-07-09 07:17:28 +02:00
WerWolv
6784678ff0 impr: Disable tab overlines 2024-07-09 07:17:21 +02:00
WerWolv
dd8e7025d0 fix: Potential race condition with sorting in the pattern drawer 2024-07-09 07:17:17 +02:00
WerWolv
c2f661f021 patterns: Updated pattern language 2024-07-09 07:17:12 +02:00
WerWolv
c6fc26e2e7 impr: Added Boost.Regex to about page 2024-07-09 07:17:01 +02:00
WerWolv
3a99d53ba5 build: Updated ImGui, libfmt and libyara 2024-07-09 07:16:49 +02:00
WerWolv
5fced6bb63 impr: Completely eradicate Window resize flickering on Windows 2024-07-09 07:16:44 +02:00
WerWolv
67930cf65d web: Fix ImHex logo and progress bar default fill 2024-07-09 07:16:26 +02:00
WerWolv
b305adb286 impr: Prevent canvas flickering in web build 2024-07-09 07:16:19 +02:00
WerWolv
cbcf7b78e9 build: Properly look for boost and libimhex library in sdk again 2024-07-09 07:15:40 +02:00
WerWolv
c922d9ceec fix: Updater executable not being launched correctly when path had spaces in it
Fixes #1780
2024-07-09 07:12:25 +02:00
WerWolv
ad235fad25 impr: Further try to improve window resize flickering on Windows 2024-06-29 23:17:59 +02:00
WerWolv
dffb7e95e3 build: Bumped version to 1.35.3 2024-06-29 21:33:34 +02:00
WerWolv
916c1b7d4b fix: ImHex hanging at startup in certain cases 2024-06-29 21:33:12 +02:00
WerWolv
2743b04f50 fix: Don't delete font atlas after passing it to ImGui 2024-06-29 21:33:07 +02:00
WerWolv
dbe8bfd75f fix: Standard magic file not getting bundled into executable correctly 2024-06-29 19:43:40 +02:00
WerWolv
c6c599c75b build: Bumped version to 1.35.2 2024-06-29 19:26:00 +02:00
WerWolv
c2b7b4a11e fix: Default folders still not being created correctly on Linux 2024-06-29 19:25:20 +02:00
WerWolv
495255484e build: Bumped version to 1.35.1 2024-06-29 18:50:10 +02:00
WerWolv
b92b0922d5 fix: Default folders not being created correctly anymore 2024-06-29 18:50:01 +02:00
59 changed files with 946 additions and 413 deletions

View File

@@ -107,7 +107,7 @@ jobs:
run: |
set -x
echo "NoGPU version Powered by Mesa 3D : https://fdossena.com/?p=mesa%2Findex.frag" > build/install/MESA.md
curl https://werwolv.net/downloads/mesa/MesaForWindows-x64-latest.7z -L -o mesa.7z
curl https://downloads.fdossena.com/geth.php?r=mesa64-latest -L -o mesa.7z
7z e mesa.7z
mv opengl32.dll build/install

View File

@@ -1 +1 @@
1.35.0
1.35.4

View File

@@ -703,8 +703,10 @@ macro(addBundledLibraries)
if (USE_SYSTEM_BOOST)
find_package(boost REQUIRED)
set(BOOST_LIBRARIES boost::regex)
else()
add_subdirectory(${THIRD_PARTY_LIBS_FOLDER}/boost ${CMAKE_CURRENT_BINARY_DIR}/boost EXCLUDE_FROM_ALL)
set(BOOST_LIBRARIES boost::regex)
endif()
set(LIBPL_BUILD_CLI_AS_EXECUTABLE OFF CACHE BOOL "" FORCE)
@@ -846,6 +848,9 @@ function(generateSDKDirectory)
if (NOT USE_SYSTEM_NLOHMANN_JSON)
install(DIRECTORY ${CMAKE_SOURCE_DIR}/lib/third_party/nlohmann_json DESTINATION "${SDK_PATH}/lib/third_party")
endif()
if (NOT USE_SYSTEM_NLOHMANN_JSON)
install(DIRECTORY ${CMAKE_SOURCE_DIR}/lib/third_party/boost DESTINATION "${SDK_PATH}/lib/third_party")
endif()
install(DIRECTORY ${CMAKE_SOURCE_DIR}/cmake/modules DESTINATION "${SDK_PATH}/cmake")
install(FILES ${CMAKE_SOURCE_DIR}/cmake/build_helpers.cmake DESTINATION "${SDK_PATH}/cmake")

View File

@@ -89,4 +89,5 @@ if (CoreClrEmbed_INCLUDE_DIR AND CoreClrEmbed_LIBRARY)
set(CoreClrEmbed_LIBRARIES "${CoreClrEmbed_LIBRARY}" CACHE STRING "CoreClrEmbed libraries" FORCE)
set(CoreClrEmbed_SHARED_LIBRARIES "${CoreClrEmbed_SHARED_LIBRARY}" CACHE STRING "CoreClrEmbed shared libraries" FORCE)
set(CoreClrEmbed_INCLUDE_DIRS "${CoreClrEmbed_INCLUDE_DIR}" CACHE STRING "CoreClrEmbed include directories" FORCE)
set(CoreClrEmbed_VERSION "${CORECLR_RUNTIME_VERSION_FULL}" CACHE STRING "CoreClrEmbed version" FORCE)
endif()

View File

@@ -38,4 +38,8 @@ if (ZSTD_FOUND)
message(STATUS "Found Zstd: ${ZSTD_LIBRARY}")
endif()
mark_as_advanced(ZSTD_INCLUDE_DIR ZSTD_LIBRARY)
mark_as_advanced(ZSTD_INCLUDE_DIR ZSTD_LIBRARY)
add_library(ZSTD::zstd INTERFACE IMPORTED)
set_property(TARGET ZSTD::zstd PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${ZSTD_INCLUDE_DIR})
set_property(TARGET ZSTD::zstd PROPERTY INTERFACE_LINK_LIBRARIES ${ZSTD_LIBRARY})

View File

@@ -72,10 +72,23 @@ macro(add_imhex_plugin)
add_subdirectory(${IMHEX_BASE_FOLDER}/lib/external/libromfs ${CMAKE_CURRENT_BINARY_DIR}/libromfs)
target_link_libraries(${IMHEX_PLUGIN_NAME} PRIVATE ${LIBROMFS_LIBRARY})
foreach(feature ${IMHEX_PLUGIN_FEATURES})
string(TOUPPER ${feature} feature)
add_definitions(-DIMHEX_PLUGIN_${IMHEX_PLUGIN_NAME}_FEATURE_${feature}=0)
endforeach()
set(FEATURE_DEFINE_CONTENT)
if (IMHEX_PLUGIN_FEATURES)
list(LENGTH IMHEX_PLUGIN_FEATURES IMHEX_FEATURE_COUNT)
math(EXPR IMHEX_FEATURE_COUNT "${IMHEX_FEATURE_COUNT} - 1" OUTPUT_FORMAT DECIMAL)
foreach(index RANGE 0 ${IMHEX_FEATURE_COUNT} 2)
list(SUBLIST IMHEX_PLUGIN_FEATURES ${index} 2 IMHEX_PLUGIN_FEATURE)
list(GET IMHEX_PLUGIN_FEATURE 0 feature_define)
list(GET IMHEX_PLUGIN_FEATURE 1 feature_description)
string(TOUPPER ${feature_define} feature_define)
add_definitions(-DIMHEX_PLUGIN_${IMHEX_PLUGIN_NAME}_FEATURE_${feature_define}=0)
set(FEATURE_DEFINE_CONTENT "${FEATURE_DEFINE_CONTENT}{ \"${feature_description}\", IMHEX_FEATURE_ENABLED(${feature_define}) },")
endforeach()
endif()
target_compile_options(${IMHEX_PLUGIN_NAME} PRIVATE -DIMHEX_PLUGIN_FEATURES_CONTENT=${FEATURE_DEFINE_CONTENT})
# Add the new plugin to the main dependency list so it gets built by default
if (TARGET imhex_all)
@@ -117,6 +130,10 @@ macro(add_imhex_plugin)
endmacro()
macro(add_romfs_resource input output)
if (NOT EXISTS ${input})
message(WARNING "Resource file ${input} does not exist")
endif()
configure_file(${input} ${CMAKE_CURRENT_BINARY_DIR}/romfs/${output} COPYONLY)
list(APPEND LIBROMFS_RESOURCE_LOCATION ${CMAKE_CURRENT_BINARY_DIR}/romfs)

View File

@@ -29,6 +29,10 @@ add_subdirectory_if_exists(lib/third_party/nlohmann_json)
set(NLOHMANN_JSON_LIBRARIES nlohmann_json PARENT_SCOPE)
set(NLOHMANN_JSON_LIBRARIES nlohmann_json)
add_subdirectory_if_exists(lib/third_party/boost)
set(BOOST_LIBRARIES boost::regex PARENT_SCOPE)
set(BOOST_LIBRARIES boost::regex)
add_subdirectory(lib/external/libwolv EXCLUDE_FROM_ALL)
set(LIBPL_ENABLE_CLI OFF CACHE BOOL "" FORCE)
@@ -44,7 +48,7 @@ add_subdirectory(lib/libimhex)
if (WIN32)
set_target_properties(libimhex PROPERTIES
IMPORTED_LOCATION "${CMAKE_CURRENT_SOURCE_DIR}/../libimhex.dll"
IMPORTED_IMPLIB "${CMAKE_CURRENT_SOURCE_DIR}/lib/libimhex.dll.a"
IMPORTED_IMPLIB "${CMAKE_CURRENT_SOURCE_DIR}/lib/liblibimhex.dll.a"
INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}/lib/libimhex/include")
elseif (APPLE)
file(GLOB LIBIMHEX_DYLIB "${CMAKE_CURRENT_SOURCE_DIR}/../../Frameworks/libimhex.*.dylib")

View File

@@ -62,7 +62,7 @@
</head>
<body>
<div id="loading" class="centered">
<img src="https://raw.githubusercontent.com/WerWolv/ImHex/master/plugins/builtin/romfs/assets/dark/banner.png" id="logo" alt="ImHex Logo">
<img src="https://raw.githubusercontent.com/WerWolv/ImHex/master/plugins/builtin/romfs/assets/dark/banner.svg" id="logo" alt="ImHex Logo">
<h1>A Hex Editor for Reverse Engineers, Programmers and people who value their retinas when working at 3 AM.</h1>
<h2>Available both natively and on the web</h2>
<h5>ImHex runs directly in your web browser with the help of Emscripten and WebAssembly.</h5>

View File

@@ -137,7 +137,7 @@ a:hover {
:root {
--progress: 25%;
--progress: 0%;
}
.progress-bar-container {
@@ -174,4 +174,15 @@ a:hover {
.progress-moved .progress-bar {
width: var(--progress);
background-color: #3864cb;
}
#logo {
height: 25%;
margin-top: 50px;
}
.canvas-fixed {
position: absolute;
top: 0;
left: 0;
}

View File

@@ -100,7 +100,77 @@ var notWorkingTimer = setTimeout(() => {
var Module = {
preRun: [],
postRun: [],
postRun: function() {
// Patch the emscripten GLFW module to send mouse and touch events in the right order
// For ImGui interactions to correctly work with touch input, MousePos events need
// to be processed first and then MouseButton events in the next frame. By default,
// GLFW does the exact opposite, which causes buttons to require two taps to register
// and windows get "stuck" to the cursor when dragged or resized
GLFW.onMousemove = event => {
if (event.type === "touchmove") {
event.preventDefault();
let primaryChanged = false;
for (let i of event.changedTouches) {
if (GLFW.primaryTouchId === i.identifier) {
Browser.setMouseCoords(i.pageX, i.pageY);
primaryChanged = true;
break;
}
}
if (!primaryChanged) {
return;
}
} else {
Browser.calculateMouseEvent(event);
}
};
GLFW.onMouseButtonChanged = (event, status) => {
if (!GLFW.active) return;
if (event.target != Module["canvas"]) return;
const isTouchType = event.type === "touchstart" || event.type === "touchend" || event.type === "touchcancel";
let eventButton = 0;
if (isTouchType) {
event.preventDefault();
let primaryChanged = false;
if (GLFW.primaryTouchId === null && event.type === "touchstart" && event.targetTouches.length > 0) {
const chosenTouch = event.targetTouches[0];
GLFW.primaryTouchId = chosenTouch.identifier;
Browser.setMouseCoords(chosenTouch.pageX, chosenTouch.pageY);
primaryChanged = true;
} else if (event.type === "touchend" || event.type === "touchcancel") {
for (let i of event.changedTouches) {
if (GLFW.primaryTouchId === i.identifier) {
GLFW.primaryTouchId = null;
primaryChanged = true;
break;
}
}
}
if (!primaryChanged) {
return;
}
} else {
Browser.calculateMouseEvent(event);
eventButton = GLFW.DOMToGLFWMouseButton(event);
}
if (status == 1) {
GLFW.active.buttons |= (1 << eventButton);
try {
event.target.setCapture();
} catch (e) {}
} else {
GLFW.active.buttons &= ~(1 << eventButton);
}
if (GLFW.active.cursorPosFunc) {
getWasmTableEntry(GLFW.active.cursorPosFunc)(GLFW.active.id, Browser.mouseX, Browser.mouseY);
}
if (GLFW.active.mouseButtonFunc) {
getWasmTableEntry(GLFW.active.mouseButtonFunc)(GLFW.active.id, eventButton, status, GLFW.getModBits(GLFW.active));
}
};
},
onRuntimeInitialized: function() {
// Triggered when the wasm module is loaded and ready to use.
document.getElementById("loading").style.display = "none"
@@ -111,13 +181,55 @@ var Module = {
print: (function() { })(),
printErr: function(text) { },
canvas: (function() {
let canvas = document.getElementById('canvas');
// As a default initial behavior, pop up an alert when webgl context is lost. To make your
// application robust, you may want to override this behavior before shipping!
// See http://www.khronos.org/registry/webgl/specs/latest/1.0/#5.15.2
canvas.addEventListener("webglcontextlost", function(e) { alert('WebGL context lost. You will need to reload the page.'); e.preventDefault(); }, false);
const canvas = document.getElementById('canvas');
canvas.addEventListener("webglcontextlost", function(e) {
alert('WebGL context lost, please reload the page');
e.preventDefault();
}, false);
return canvas;
// Turn long touches into right-clicks
let timer = null;
canvas.addEventListener('touchstart', event => {
timer = setTimeout(() => {
let eventArgs = {
bubbles: true,
cancelable: true,
view: window,
screenX: event.touches[0].screenX,
screenY: event.touches[0].screenY,
clientX: event.touches[0].clientX,
clientY: event.touches[0].clientY,
button: 2,
buttons: 2,
relatedTarget: event.target,
region: event.region
}
canvas.dispatchEvent(new MouseEvent('mousedown', eventArgs));
canvas.dispatchEvent(new MouseEvent('mouseup', eventArgs));
}, 400);
});
canvas.addEventListener('touchend', event => {
if (timer) {
clearTimeout(timer);
timer = null;
}
});
if (typeof WebGL2RenderingContext !== 'undefined') {
let gl = canvas.getContext('webgl2', { stencil: true });
if (!gl) {
console.error('WebGL 2 not available, falling back to WebGL');
gl = canvas.getContext('webgl', { stencil: true });
}
if (!gl) {
alert('WebGL not available with stencil buffer');
}
return canvas;
} else {
alert('WebGL 2 not supported by this browser');
}
})(),
setStatus: function(text) { },
totalDependencies: 0,
@@ -144,14 +256,9 @@ if (urlParams.has("lang")) {
window.addEventListener('resize', js_resizeCanvas, false);
function js_resizeCanvas() {
let canvas = document.getElementById('canvas');
canvas.top = document.documentElement.clientTop;
canvas.left = document.documentElement.clientLeft;
canvas.width = Math.min(document.documentElement.clientWidth, window.innerWidth || 0);
canvas.height = Math.min(document.documentElement.clientHeight, window.innerHeight || 0);
canvas.classList.add("canvas_full_screen")
if (GLFW.active && GLFW.active.windowPosFunc) {
getWasmTableEntry(GLFW.active.windowPosFunc)(GLFW.active.id, GLFW.active.x, GLFW.active.y);
}
GLFW.onWindowSizeChanged();
}

View File

@@ -144,7 +144,7 @@ if (NOT IMHEX_EXTERNAL_PLUGIN_BUILD)
precompileHeaders(libimhex "${CMAKE_CURRENT_SOURCE_DIR}/include")
endif()
target_link_libraries(libimhex ${LIBIMHEX_LIBRARY_TYPE} ${NLOHMANN_JSON_LIBRARIES} imgui_all_includes ${MBEDTLS_LIBRARIES} ${FMT_LIBRARIES} ${LUNASVG_LIBRARIES} boost::regex)
target_link_libraries(libimhex ${LIBIMHEX_LIBRARY_TYPE} ${NLOHMANN_JSON_LIBRARIES} imgui_all_includes ${MBEDTLS_LIBRARIES} ${FMT_LIBRARIES} ${LUNASVG_LIBRARIES} ${BOOST_LIBRARIES})
set_property(TARGET libimhex PROPERTY INTERPROCEDURAL_OPTIMIZATION FALSE)

View File

@@ -75,7 +75,7 @@ namespace hex {
namespace impl {
using HighlightingFunction = std::function<std::optional<color_t>(u64, const u8*, size_t, bool)>;
using HoveringFunction = std::function<bool(const prv::Provider *, u64, const u8*, size_t)>;
using HoveringFunction = std::function<std::set<Region>(const prv::Provider *, u64, size_t)>;
const std::map<u32, Highlighting>& getBackgroundHighlights();
const std::map<u32, HighlightingFunction>& getBackgroundHighlightingFunctions();

View File

@@ -102,12 +102,9 @@ namespace hex {
std::string m_unlocalizedString;
};
}
template<>
struct fmt::formatter<hex::Lang> : fmt::formatter<std::string_view> {
template<typename FormatContext>
auto format(const hex::Lang &entry, FormatContext &ctx) {
return fmt::formatter<std::string_view>::format(entry.get(), ctx);
// {fmt} formatter for hex::Lang
inline auto format_as(const hex::Lang &entry) {
return entry.get();
}
};
}

View File

@@ -2,6 +2,7 @@
#include <string_view>
#include <fmt/format.h>
#include <fmt/ranges.h>
namespace hex {

View File

@@ -61,6 +61,10 @@ namespace hex {
constexpr static Region Invalid() {
return { 0, 0 };
}
constexpr bool operator<(const Region &other) const {
return this->address < other.address;
}
};

View File

@@ -37,15 +37,34 @@ void* PluginSubCommandsFunctionHelper<T>::getSubCommands() {
return nullptr;
}
[[maybe_unused]] static auto& getFeaturesImpl() {
static std::vector<hex::Feature> features;
return features;
}
#if defined (IMHEX_STATIC_LINK_PLUGINS)
#define IMHEX_PLUGIN_VISIBILITY_PREFIX static
#else
#define IMHEX_PLUGIN_VISIBILITY_PREFIX extern "C" [[gnu::visibility("default")]]
#endif
#define IMHEX_FEATURE_ENABLED(feature) WOLV_TOKEN_CONCAT(WOLV_TOKEN_CONCAT(WOLV_TOKEN_CONCAT(IMHEX_PLUGIN_, IMHEX_PLUGIN_NAME), _FEATURE_), feature)
#define IMHEX_DEFINE_PLUGIN_FEATURES() IMHEX_DEFINE_PLUGIN_FEATURES_IMPL()
#define IMHEX_DEFINE_PLUGIN_FEATURES_IMPL() \
template<> \
struct PluginFeatureFunctionHelper<PluginFunctionHelperInstantiation> { \
static void* getFeatures(); \
}; \
void* PluginFeatureFunctionHelper<PluginFunctionHelperInstantiation>::getFeatures() { \
return &getFeaturesImpl(); \
} \
static auto initFeatures = [] { getFeaturesImpl() = std::vector<hex::Feature>({ IMHEX_PLUGIN_FEATURES_CONTENT }); return 0; }()
#define IMHEX_PLUGIN_FEATURES ::getFeaturesImpl()
/**
* This macro is used to define all the required entry points for a plugin.
* Name, Author and Description will be displayed in the in the plugin list on the Welcome screen.
* Name, Author and Description will be displayed in the plugin list on the Welcome screen.
*/
#define IMHEX_PLUGIN_SETUP(name, author, description) IMHEX_PLUGIN_SETUP_IMPL(name, author, description)
#define IMHEX_LIBRARY_SETUP(name) IMHEX_LIBRARY_SETUP_IMPL(name)
@@ -85,6 +104,7 @@ void* PluginSubCommandsFunctionHelper<T>::getSubCommands() {
ImGui::SetCurrentContext(ctx); \
GImGui = ctx; \
} \
IMHEX_DEFINE_PLUGIN_FEATURES(); \
IMHEX_PLUGIN_VISIBILITY_PREFIX void* getFeatures() { \
return PluginFeatureFunctionHelper<PluginFunctionHelperInstantiation>::getFeatures(); \
} \
@@ -129,18 +149,3 @@ void* PluginSubCommandsFunctionHelper<T>::getSubCommands() {
return &g_subCommands; \
} \
std::vector<hex::SubCommand> g_subCommands
#define IMHEX_FEATURE_ENABLED(feature) WOLV_TOKEN_CONCAT(WOLV_TOKEN_CONCAT(WOLV_TOKEN_CONCAT(IMHEX_PLUGIN_, IMHEX_PLUGIN_NAME), _FEATURE_), feature)
#define IMHEX_DEFINE_PLUGIN_FEATURES() IMHEX_DEFINE_PLUGIN_FEATURES_IMPL()
#define IMHEX_DEFINE_PLUGIN_FEATURES_IMPL() \
extern std::vector<hex::Feature> g_features; \
template<> \
struct PluginFeatureFunctionHelper<PluginFunctionHelperInstantiation> { \
static void* getFeatures(); \
}; \
void* PluginFeatureFunctionHelper<PluginFunctionHelperInstantiation>::getFeatures() { \
return &g_features; \
} \
std::vector<hex::Feature> g_features
#define IMHEX_PLUGIN_FEATURES g_features

View File

@@ -862,7 +862,7 @@ namespace hex {
EventImHexClosing::subscribe([executablePath, updateTypeString] {
hex::executeCommand(
hex::format("{} {}",
hex::format("\"{}\" \"{}\"",
wolv::util::toUTF8String(executablePath),
updateTypeString
)

View File

@@ -24,6 +24,37 @@
#include <emscripten.h>
#else
#include <nfd.hpp>
#if defined(OS_WINDOWS)
#define GLFW_EXPOSE_NATIVE_WIN32
#endif
#if defined(OS_MACOS)
// macOS platform headers can't be compiled with gcc
#define GLFW_NATIVE_INCLUDE_NONE
typedef uint32_t CGDirectDisplayID;
typedef void *id;
typedef void NSWindow;
#define GLFW_EXPOSE_NATIVE_COCOA
#endif
#if defined(OS_LINUX)
#define GLFW_EXPOSE_NATIVE_X11
#endif
#if defined(OS_LINUX) && defined(GLFW_WAYLAND_APP_ID)
#define GLFW_EXPOSE_NATIVE_WAYLAND
#endif
#include <nfd_glfw3.h>
#if defined(OS_LINUX) && defined(GLFW_WAYLAND_APP_ID)
#undef GLFW_EXPOSE_NATIVE_WAYLAND
#endif
#if defined(OS_LINUX)
#undef GLFW_EXPOSE_NATIVE_X11
#endif
#if defined(OS_MACOS)
#undef GLFW_EXPOSE_NATIVE_COCOA
#undef GLFW_NATIVE_INCLUDE_NONE
#endif
#if defined(OS_WINDOWS)
#undef GLFW_EXPOSE_NATIVE_WIN32
#endif
#endif
#include <filesystem>
@@ -233,20 +264,22 @@ namespace hex::fs {
NFD::UniquePathU8 outPath;
NFD::UniquePathSet outPaths;
nfdresult_t result = NFD_ERROR;
nfdwindowhandle_t nativeWindow{};
NFD_GetNativeWindowFromGLFWWindow(ImHexApi::System::getMainWindowHandle(), &nativeWindow);
// Open the correct file dialog based on the mode
switch (mode) {
case DialogMode::Open:
if (multiple)
result = NFD::OpenDialogMultiple(outPaths, validExtensionsNfd.data(), validExtensionsNfd.size(), defaultPath.empty() ? nullptr : defaultPath.c_str());
result = NFD::OpenDialogMultiple(outPaths, validExtensionsNfd.data(), validExtensionsNfd.size(), defaultPath.empty() ? nullptr : defaultPath.c_str(), nativeWindow);
else
result = NFD::OpenDialog(outPath, validExtensionsNfd.data(), validExtensionsNfd.size(), defaultPath.empty() ? nullptr : defaultPath.c_str());
result = NFD::OpenDialog(outPath, validExtensionsNfd.data(), validExtensionsNfd.size(), defaultPath.empty() ? nullptr : defaultPath.c_str(), nativeWindow);
break;
case DialogMode::Save:
result = NFD::SaveDialog(outPath, validExtensionsNfd.data(), validExtensionsNfd.size(), defaultPath.empty() ? nullptr : defaultPath.c_str());
result = NFD::SaveDialog(outPath, validExtensionsNfd.data(), validExtensionsNfd.size(), defaultPath.empty() ? nullptr : defaultPath.c_str(), nullptr, nativeWindow);
break;
case DialogMode::Folder:
result = NFD::PickFolder(outPath, defaultPath.empty() ? nullptr : defaultPath.c_str());
result = NFD::PickFolder(outPath, defaultPath.empty() ? nullptr : defaultPath.c_str(), nativeWindow);
break;
}

View File

@@ -3303,7 +3303,7 @@ typedef union SDL_Event SDL_Event;
#endif // CIMGUI_DEFINE_ENUMS_AND_STRUCTS
#ifndef CIMGUI_DEFINE_ENUMS_AND_STRUCTS
typedef struct ImGuiStorage::ImGuiStoragePair ImGuiStoragePair;
typedef struct ImGuiStoragePair ImGuiStoragePair;
typedef struct ImGuiTextFilter::ImGuiTextRange ImGuiTextRange;
typedef ImStb::STB_TexteditState STB_TexteditState;
typedef ImStb::StbTexteditRow StbTexteditRow;

View File

@@ -1,4 +1,4 @@
// dear imgui, v1.90.8
// dear imgui, v1.90.9
// (headers)
// Help:
@@ -27,8 +27,8 @@
// Library Version
// (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345')
#define IMGUI_VERSION "1.90.8"
#define IMGUI_VERSION_NUM 19080
#define IMGUI_VERSION "1.90.9"
#define IMGUI_VERSION_NUM 19090
#define IMGUI_HAS_TABLE
#define IMGUI_HAS_VIEWPORT // Viewport WIP branch
#define IMGUI_HAS_DOCK // Docking WIP branch
@@ -182,7 +182,8 @@ struct ImGuiPlatformIO; // Multi-viewport support: interface for Pla
struct ImGuiPlatformMonitor; // Multi-viewport support: user-provided bounds for each connected monitor/display. Used when positioning popups and tooltips to avoid them straddling monitors
struct ImGuiPlatformImeData; // Platform IME data for io.SetPlatformImeDataFn() function.
struct ImGuiSizeCallbackData; // Callback data when using SetNextWindowSizeConstraints() (rare/advanced use)
struct ImGuiStorage; // Helper for key->value storage
struct ImGuiStorage; // Helper for key->value storage (container sorted by key)
struct ImGuiStoragePair; // Helper for key->value storage (pair)
struct ImGuiStyle; // Runtime data for styling/colors
struct ImGuiTableSortSpecs; // Sorting specifications for a table (often handling sort specs for a single column, occasionally more)
struct ImGuiTableColumnSortSpecs; // Sorting specification for one column of a table
@@ -787,7 +788,7 @@ namespace ImGui
// - TableNextColumn() -> Text("Hello 0") -> TableNextColumn() -> Text("Hello 1") // OK: TableNextColumn() automatically gets to next row!
// - TableNextRow() -> Text("Hello 0") // Not OK! Missing TableSetColumnIndex() or TableNextColumn()! Text will not appear!
// - 5. Call EndTable()
IMGUI_API bool BeginTable(const char* str_id, int column, ImGuiTableFlags flags = 0, const ImVec2& outer_size = ImVec2(0.0f, 0.0f), float inner_width = 0.0f);
IMGUI_API bool BeginTable(const char* str_id, int columns, ImGuiTableFlags flags = 0, const ImVec2& outer_size = ImVec2(0.0f, 0.0f), float inner_width = 0.0f);
IMGUI_API void EndTable(); // only call EndTable() if BeginTable() returns true!
IMGUI_API void TableNextRow(ImGuiTableRowFlags row_flags = 0, float min_row_height = 0.0f); // append into the first cell of a new row.
IMGUI_API bool TableNextColumn(); // append into the next column (or first column of next row if currently in last column). Return true when column is visible.
@@ -820,6 +821,7 @@ namespace ImGui
IMGUI_API const char* TableGetColumnName(int column_n = -1); // return "" if column didn't have a name declared by TableSetupColumn(). Pass -1 to use current column.
IMGUI_API ImGuiTableColumnFlags TableGetColumnFlags(int column_n = -1); // return column flags so you can query their Enabled/Visible/Sorted/Hovered status flags. Pass -1 to use current column.
IMGUI_API void TableSetColumnEnabled(int column_n, bool v);// change user accessible enabled/disabled state of a column. Set to false to hide the column. User can use the context menu to change this themselves (right-click in headers, or right-click in columns body with ImGuiTableFlags_ContextMenuInBody)
IMGUI_API int TableGetHoveredColumn(); // return hovered column. return -1 when table is not hovered. return columns_count if the unused space at the right of visible columns is hovered. Can also use (TableGetColumnFlags() & ImGuiTableColumnFlags_IsHovered) instead.
IMGUI_API void TableSetBgColor(ImGuiTableBgTarget target, ImU32 color, int column_n = -1); // change the color of a cell, row, or column. See ImGuiTableBgTarget_ flags for details.
// Legacy Columns API (prefer using Tables!)
@@ -888,6 +890,7 @@ namespace ImGui
// Disabling [BETA API]
// - Disable all user interactions and dim items visuals (applying style.DisabledAlpha over current colors)
// - Those can be nested but it cannot be used to enable an already disabled section (a single BeginDisabled(true) in the stack is enough to keep everything disabled)
// - Tooltips windows by exception are opted out of disabling.
// - BeginDisabled(false) essentially does nothing useful but is provided to facilitate use of boolean expressions. If you can avoid calling BeginDisabled(False)/EndDisabled() best to avoid it.
IMGUI_API void BeginDisabled(bool disabled = true);
IMGUI_API void EndDisabled();
@@ -933,10 +936,8 @@ namespace ImGui
IMGUI_API ImGuiViewport* GetMainViewport(); // return primary/default viewport. This can never be NULL.
// Background/Foreground Draw Lists
IMGUI_API ImDrawList* GetBackgroundDrawList(); // get background draw list for the viewport associated to the current window. this draw list will be the first rendering one. Useful to quickly draw shapes/text behind dear imgui contents.
IMGUI_API ImDrawList* GetForegroundDrawList(); // get foreground draw list for the viewport associated to the current window. this draw list will be the last rendered one. Useful to quickly draw shapes/text over dear imgui contents.
IMGUI_API ImDrawList* GetBackgroundDrawList(ImGuiViewport* viewport); // get background draw list for the given viewport. this draw list will be the first rendering one. Useful to quickly draw shapes/text behind dear imgui contents.
IMGUI_API ImDrawList* GetForegroundDrawList(ImGuiViewport* viewport); // get foreground draw list for the given viewport. this draw list will be the last rendered one. Useful to quickly draw shapes/text over dear imgui contents.
IMGUI_API ImDrawList* GetBackgroundDrawList(ImGuiViewport* viewport = NULL); // get background draw list for the given viewport or viewport associated to the current window. this draw list will be the first rendering one. Useful to quickly draw shapes/text behind dear imgui contents.
IMGUI_API ImDrawList* GetForegroundDrawList(ImGuiViewport* viewport = NULL); // get foreground draw list for the given viewport or viewport associated to the current window. this draw list will be the top-most rendered one. Useful to quickly draw shapes/text over dear imgui contents.
// Miscellaneous Utilities
IMGUI_API bool IsRectVisible(const ImVec2& size); // test if rectangle (of given size, starting from cursor position) is visible / not clipped.
@@ -1085,7 +1086,6 @@ enum ImGuiWindowFlags_
ImGuiWindowFlags_NoInputs = ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs | ImGuiWindowFlags_NoNavFocus,
// [Internal]
ImGuiWindowFlags_NavFlattened = 1 << 23, // [BETA] On child window: share focus scope, allow gamepad/keyboard navigation to cross over parent border to this child or between sibling child windows.
ImGuiWindowFlags_ChildWindow = 1 << 24, // Don't use! For internal use by BeginChild()
ImGuiWindowFlags_Tooltip = 1 << 25, // Don't use! For internal use by BeginTooltip()
ImGuiWindowFlags_Popup = 1 << 26, // Don't use! For internal use by BeginPopup()
@@ -1096,6 +1096,7 @@ enum ImGuiWindowFlags_
// Obsolete names
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
ImGuiWindowFlags_AlwaysUseWindowPadding = 1 << 30, // Obsoleted in 1.90: Use ImGuiChildFlags_AlwaysUseWindowPadding in BeginChild() call.
ImGuiWindowFlags_NavFlattened = 1 << 31, // Obsoleted in 1.90.9: Use ImGuiChildFlags_NavFlattened in BeginChild() call.
#endif
};
@@ -1119,6 +1120,7 @@ enum ImGuiChildFlags_
ImGuiChildFlags_AutoResizeY = 1 << 5, // Enable auto-resizing height. Read "IMPORTANT: Size measurement" details above.
ImGuiChildFlags_AlwaysAutoResize = 1 << 6, // Combined with AutoResizeX/AutoResizeY. Always measure size even when child is hidden, always return true, always disable clipping optimization! NOT RECOMMENDED.
ImGuiChildFlags_FrameStyle = 1 << 7, // Style the child window like a framed item: use FrameBg, FrameRounding, FrameBorderSize, FramePadding instead of ChildBg, ChildRounding, ChildBorderSize, WindowPadding.
ImGuiChildFlags_NavFlattened = 1 << 8, // Share focus scope, allow gamepad/keyboard navigation to cross over parent border to this child or between sibling child windows.
};
// Flags for ImGui::InputText()
@@ -1254,8 +1256,9 @@ enum ImGuiTabBarFlags_
ImGuiTabBarFlags_NoCloseWithMiddleMouseButton = 1 << 3, // Disable behavior of closing tabs (that are submitted with p_open != NULL) with middle mouse button. You may handle this behavior manually on user's side with if (IsItemHovered() && IsMouseClicked(2)) *p_open = false.
ImGuiTabBarFlags_NoTabListScrollingButtons = 1 << 4, // Disable scrolling buttons (apply when fitting policy is ImGuiTabBarFlags_FittingPolicyScroll)
ImGuiTabBarFlags_NoTooltip = 1 << 5, // Disable tooltips when hovering a tab
ImGuiTabBarFlags_FittingPolicyResizeDown = 1 << 6, // Resize tabs when they don't fit
ImGuiTabBarFlags_FittingPolicyScroll = 1 << 7, // Add scroll buttons when tabs don't fit
ImGuiTabBarFlags_DrawSelectedOverline = 1 << 6, // Draw selected overline markers over selected tab
ImGuiTabBarFlags_FittingPolicyResizeDown = 1 << 7, // Resize tabs when they don't fit
ImGuiTabBarFlags_FittingPolicyScroll = 1 << 8, // Add scroll buttons when tabs don't fit
ImGuiTabBarFlags_FittingPolicyMask_ = ImGuiTabBarFlags_FittingPolicyResizeDown | ImGuiTabBarFlags_FittingPolicyScroll,
ImGuiTabBarFlags_FittingPolicyDefault_ = ImGuiTabBarFlags_FittingPolicyResizeDown,
};
@@ -1358,12 +1361,18 @@ enum ImGuiDragDropFlags_
ImGuiDragDropFlags_SourceNoHoldToOpenOthers = 1 << 2, // Disable the behavior that allows to open tree nodes and collapsing header by holding over them while dragging a source item.
ImGuiDragDropFlags_SourceAllowNullID = 1 << 3, // Allow items such as Text(), Image() that have no unique identifier to be used as drag source, by manufacturing a temporary identifier based on their window-relative position. This is extremely unusual within the dear imgui ecosystem and so we made it explicit.
ImGuiDragDropFlags_SourceExtern = 1 << 4, // External source (from outside of dear imgui), won't attempt to read current item/window info. Will always return true. Only one Extern source can be active simultaneously.
ImGuiDragDropFlags_SourceAutoExpirePayload = 1 << 5, // Automatically expire the payload if the source cease to be submitted (otherwise payloads are persisting while being dragged)
ImGuiDragDropFlags_PayloadAutoExpire = 1 << 5, // Automatically expire the payload if the source cease to be submitted (otherwise payloads are persisting while being dragged)
ImGuiDragDropFlags_PayloadNoCrossContext = 1 << 6, // Hint to specify that the payload may not be copied outside current dear imgui context.
ImGuiDragDropFlags_PayloadNoCrossProcess = 1 << 7, // Hint to specify that the payload may not be copied outside current process.
// AcceptDragDropPayload() flags
ImGuiDragDropFlags_AcceptBeforeDelivery = 1 << 10, // AcceptDragDropPayload() will returns true even before the mouse button is released. You can then call IsDelivery() to test if the payload needs to be delivered.
ImGuiDragDropFlags_AcceptNoDrawDefaultRect = 1 << 11, // Do not draw the default highlight rectangle when hovering over target.
ImGuiDragDropFlags_AcceptNoPreviewTooltip = 1 << 12, // Request hiding the BeginDragDropSource tooltip from the BeginDragDropTarget site.
ImGuiDragDropFlags_AcceptPeekOnly = ImGuiDragDropFlags_AcceptBeforeDelivery | ImGuiDragDropFlags_AcceptNoDrawDefaultRect, // For peeking ahead and inspecting the payload before delivery.
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
ImGuiDragDropFlags_SourceAutoExpirePayload = ImGuiDragDropFlags_PayloadAutoExpire, // Renamed in 1.90.9
#endif
};
// Standard Drag and Drop payload types. You can define you own payload types using short strings. Types starting with '_' are defined by Dear ImGui.
@@ -1591,11 +1600,12 @@ enum ImGuiConfigFlags_
ImGuiConfigFlags_NavEnableGamepad = 1 << 1, // Master gamepad navigation enable flag. Backend also needs to set ImGuiBackendFlags_HasGamepad.
ImGuiConfigFlags_NavEnableSetMousePos = 1 << 2, // Instruct navigation to move the mouse cursor. May be useful on TV/console systems where moving a virtual mouse is awkward. Will update io.MousePos and set io.WantSetMousePos=true. If enabled you MUST honor io.WantSetMousePos requests in your backend, otherwise ImGui will react as if the mouse is jumping around back and forth.
ImGuiConfigFlags_NavNoCaptureKeyboard = 1 << 3, // Instruct navigation to not set the io.WantCaptureKeyboard flag when io.NavActive is set.
ImGuiConfigFlags_NoMouse = 1 << 4, // Instruct imgui to clear mouse position/buttons in NewFrame(). This allows ignoring the mouse information set by the backend.
ImGuiConfigFlags_NoMouse = 1 << 4, // Instruct dear imgui to disable mouse inputs and interactions.
ImGuiConfigFlags_NoMouseCursorChange = 1 << 5, // Instruct backend to not alter mouse cursor shape and visibility. Use if the backend cursor changes are interfering with yours and you don't want to use SetMouseCursor() to change mouse cursor. You may want to honor requests from imgui by reading GetMouseCursor() yourself instead.
ImGuiConfigFlags_NoKeyboard = 1 << 6, // Instruct dear imgui to disable keyboard inputs and interactions. This is done by ignoring keyboard events and clearing existing states.
// [BETA] Docking
ImGuiConfigFlags_DockingEnable = 1 << 6, // Docking enable flags.
ImGuiConfigFlags_DockingEnable = 1 << 7, // Docking enable flags.
// [BETA] Viewports
// When using viewports it is recommended that your default value for ImGuiCol_WindowBg is opaque (Alpha=1.0) so transition to a viewport won't be noticeable.
@@ -1659,11 +1669,13 @@ enum ImGuiCol_
ImGuiCol_ResizeGrip, // Resize grip in lower-right and lower-left corners of windows.
ImGuiCol_ResizeGripHovered,
ImGuiCol_ResizeGripActive,
ImGuiCol_Tab, // TabItem in a TabBar
ImGuiCol_TabHovered,
ImGuiCol_TabActive,
ImGuiCol_TabUnfocused,
ImGuiCol_TabUnfocusedActive,
ImGuiCol_TabHovered, // Tab background, when hovered
ImGuiCol_Tab, // Tab background, when tab-bar is focused & tab is unselected
ImGuiCol_TabSelected, // Tab background, when tab-bar is focused & tab is selected
ImGuiCol_TabSelectedOverline, // Tab horizontal overline, when tab-bar is focused & tab is selected
ImGuiCol_TabDimmed, // Tab background, when tab-bar is unfocused & tab is unselected
ImGuiCol_TabDimmedSelected, // Tab background, when tab-bar is unfocused & tab is selected
ImGuiCol_TabDimmedSelectedOverline,//..horizontal overline, when tab-bar is unfocused & tab is selected
ImGuiCol_DockingPreview, // Preview overlay color when about to docking something
ImGuiCol_DockingEmptyBg, // Background color for empty node (e.g. CentralNode with no window docked into it)
ImGuiCol_PlotLines,
@@ -1682,7 +1694,13 @@ enum ImGuiCol_
ImGuiCol_NavWindowingDimBg, // Darken/colorize entire screen behind the CTRL+TAB window list, when active
ImGuiCol_ModalWindowDimBg, // Darken/colorize entire screen behind a modal window, when one is active
ImGuiCol_WindowShadow, // Window shadows
ImGuiCol_COUNT
ImGuiCol_COUNT,
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
ImGuiCol_TabActive = ImGuiCol_TabSelected, // [renamed in 1.90.9]
ImGuiCol_TabUnfocused = ImGuiCol_TabDimmed, // [renamed in 1.90.9]
ImGuiCol_TabUnfocusedActive = ImGuiCol_TabDimmedSelected, // [renamed in 1.90.9]
#endif
};
// Enumeration for PushStyleVar() / PopStyleVar() to temporarily modify the ImGuiStyle structure.
@@ -1795,8 +1813,9 @@ enum ImGuiSliderFlags_
ImGuiSliderFlags_None = 0,
ImGuiSliderFlags_AlwaysClamp = 1 << 4, // Clamp value to min/max bounds when input manually with CTRL+Click. By default CTRL+Click allows going out of bounds.
ImGuiSliderFlags_Logarithmic = 1 << 5, // Make the widget logarithmic (linear otherwise). Consider using ImGuiSliderFlags_NoRoundToFormat with this if using a format-string with small amount of digits.
ImGuiSliderFlags_NoRoundToFormat = 1 << 6, // Disable rounding underlying value to match precision of the display format string (e.g. %.3f values are rounded to those 3 digits)
ImGuiSliderFlags_NoInput = 1 << 7, // Disable CTRL+Click or Enter key allowing to input text directly into the widget
ImGuiSliderFlags_NoRoundToFormat = 1 << 6, // Disable rounding underlying value to match precision of the display format string (e.g. %.3f values are rounded to those 3 digits).
ImGuiSliderFlags_NoInput = 1 << 7, // Disable CTRL+Click or Enter key allowing to input text directly into the widget.
ImGuiSliderFlags_WrapAround = 1 << 8, // Enable wrapping around from max to min and from min to max (only supported by DragXXX() functions for now.
ImGuiSliderFlags_InvalidMask_ = 0x7000000F, // [Internal] We treat using those bits as being potentially a 'float power' argument from the previous API that has got miscast to this enum, and will trigger an assert if needed.
// Obsolete names
@@ -2280,7 +2299,7 @@ struct ImGuiIO
// Option to deactivate io.AddFocusEvent(false) handling.
// - May facilitate interactions with a debugger when focus loss leads to clearing inputs data.
// - Backends may have other side-effects on focus loss, so this will reduce side-effects but not necessary remove all of them.
bool ConfigDebugIgnoreFocusLoss; // = false // Ignore io.AddFocusEvent(false), consequently not calling io.ClearInputKeys() in input processing.
bool ConfigDebugIgnoreFocusLoss; // = false // Ignore io.AddFocusEvent(false), consequently not calling io.ClearInputKeys()/io.ClearInputMouse() in input processing.
// Option to audit .ini data
bool ConfigDebugIniSettings; // = false // Save .ini data with extra comments (particularly helpful for Docking, but makes saving slower)
@@ -2330,7 +2349,8 @@ struct ImGuiIO
IMGUI_API void SetKeyEventNativeData(ImGuiKey key, int native_keycode, int native_scancode, int native_legacy_index = -1); // [Optional] Specify index for legacy <1.87 IsKeyXXX() functions with native indices + specify native keycode, scancode.
IMGUI_API void SetAppAcceptingEvents(bool accepting_events); // Set master flag for accepting key/mouse/text events (default to true). Useful if you have native dialog boxes that are interrupting your application loop/refresh, and you want to disable events being queued while your app is frozen.
IMGUI_API void ClearEventsQueue(); // Clear all incoming events.
IMGUI_API void ClearInputKeys(); // Clear current keyboard/mouse/gamepad state + current frame text input buffer. Equivalent to releasing all keys/buttons.
IMGUI_API void ClearInputKeys(); // Clear current keyboard/gamepad state + current frame text input buffer. Equivalent to releasing all keys/buttons.
IMGUI_API void ClearInputMouse(); // Clear current mouse state.
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
IMGUI_API void ClearInputCharacters(); // [Obsoleted in 1.89.8] Clear the current frame text input buffer. Now included within ClearInputKeys().
#endif
@@ -2583,6 +2603,16 @@ struct ImGuiTextBuffer
IMGUI_API void appendfv(const char* fmt, va_list args) IM_FMTLIST(2);
};
// [Internal] Key+Value for ImGuiStorage
struct ImGuiStoragePair
{
ImGuiID key;
union { int val_i; float val_f; void* val_p; };
ImGuiStoragePair(ImGuiID _key, int _val) { key = _key; val_i = _val; }
ImGuiStoragePair(ImGuiID _key, float _val) { key = _key; val_f = _val; }
ImGuiStoragePair(ImGuiID _key, void* _val) { key = _key; val_p = _val; }
};
// Helper: Key->Value storage
// Typically you don't have to worry about this since a storage is held within each Window.
// We use it to e.g. store collapse state for a tree (Int 0/1)
@@ -2594,15 +2624,6 @@ struct ImGuiTextBuffer
struct ImGuiStorage
{
// [Internal]
struct ImGuiStoragePair
{
ImGuiID key;
union { int val_i; float val_f; void* val_p; };
ImGuiStoragePair(ImGuiID _key, int _val) { key = _key; val_i = _val; }
ImGuiStoragePair(ImGuiID _key, float _val) { key = _key; val_f = _val; }
ImGuiStoragePair(ImGuiID _key, void* _val) { key = _key; val_p = _val; }
};
ImVector<ImGuiStoragePair> Data;
// - Get***() functions find pair, never add/allocate. Pairs are sorted so a query is O(log N)
@@ -2631,6 +2652,10 @@ struct ImGuiStorage
IMGUI_API void BuildSortByKey();
// Obsolete: use on your own storage if you know only integer are being stored (open/close all tree nodes)
IMGUI_API void SetAllInt(int val);
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
//typedef ::ImGuiStoragePair ImGuiStoragePair; // 1.90.8: moved type outside struct
#endif
};
// Helper: Manually clip large list of items.
@@ -3402,7 +3427,7 @@ struct ImGuiViewport
// The library never uses those fields, they are merely storage to facilitate backend implementation.
void* RendererUserData; // void* to hold custom data structure for the renderer (e.g. swap chain, framebuffers etc.). generally set by your Renderer_CreateWindow function.
void* PlatformUserData; // void* to hold custom data structure for the OS / platform (e.g. windowing info, render context). generally set by your Platform_CreateWindow function.
void* PlatformHandle; // void* for FindViewportByPlatformHandle(). (e.g. suggested to use natural platform handle such as HWND, GLFWWindow*, SDL_Window*)
void* PlatformHandle; // void* to hold higher-level, platform window handle (e.g. HWND, GLFWWindow*, SDL_Window*), for FindViewportByPlatformHandle().
void* PlatformHandleRaw; // void* to hold lower-level, platform-native window handle (under Win32 this is expected to be a HWND, unused for other platforms), when using an abstraction layer like GLFW or SDL (where PlatformHandle would be a SDL_Window*)
bool PlatformWindowCreated; // Platform window has been created (Platform_CreateWindow() has been called). This is false during the first frame where a viewport is being created.
bool PlatformRequestMove; // Platform window requested move (e.g. window was moved by the OS / host window manager, authoritative position will be OS window position)

View File

@@ -1,4 +1,4 @@
// dear imgui, v1.90.8
// dear imgui, v1.90.9
// (internal structures/api)
// You may use this file to debug, understand or extend Dear ImGui features but we don't provide any guarantee of forward compatibility.
@@ -361,6 +361,7 @@ namespace ImStb
// - Helper: ImPool<>
// - Helper: ImChunkStream<>
// - Helper: ImGuiTextIndex
// - Helper: ImGuiStorage
//-----------------------------------------------------------------------------
// Helpers: Hashing
@@ -736,7 +737,7 @@ struct ImChunkStream
void swap(ImChunkStream<T>& rhs) { rhs.Buf.swap(Buf); }
};
// Helper: ImGuiTextIndex<>
// Helper: ImGuiTextIndex
// Maintain a line index for a text buffer. This is a strong candidate to be moved into the public API.
struct ImGuiTextIndex
{
@@ -750,6 +751,8 @@ struct ImGuiTextIndex
void append(const char* base, int old_size, int new_size);
};
// Helper: ImGuiStorage
IMGUI_API ImGuiStoragePair* ImLowerBound(ImGuiStoragePair* in_begin, ImGuiStoragePair* in_end, ImGuiID key);
//-----------------------------------------------------------------------------
// [SECTION] ImDrawList support
//-----------------------------------------------------------------------------
@@ -1624,7 +1627,7 @@ struct ImGuiNavItemData
float DistBox; // Move // Best candidate box distance to current NavId
float DistCenter; // Move // Best candidate center distance to current NavId
float DistAxial; // Move // Best candidate axial distance to current NavId
ImGuiSelectionUserData SelectionUserData;//I+Mov // Best candidate SetNextItemSelectionData() value.
ImGuiSelectionUserData SelectionUserData;//I+Mov // Best candidate SetNextItemSelectionUserData() value. Valid if (InFlags & ImGuiItemFlags_HasSelectionUserData)
ImGuiNavItemData() { Clear(); }
void Clear() { Window = NULL; ID = FocusScopeId = 0; InFlags = 0; SelectionUserData = -1; DistBox = DistCenter = DistAxial = FLT_MAX; }
@@ -1866,11 +1869,13 @@ struct IMGUI_API ImGuiDockNode
enum ImGuiWindowDockStyleCol
{
ImGuiWindowDockStyleCol_Text,
ImGuiWindowDockStyleCol_Tab,
ImGuiWindowDockStyleCol_TabHovered,
ImGuiWindowDockStyleCol_TabActive,
ImGuiWindowDockStyleCol_TabUnfocused,
ImGuiWindowDockStyleCol_TabUnfocusedActive,
ImGuiWindowDockStyleCol_TabFocused,
ImGuiWindowDockStyleCol_TabSelected,
ImGuiWindowDockStyleCol_TabSelectedOverline,
ImGuiWindowDockStyleCol_TabDimmed,
ImGuiWindowDockStyleCol_TabDimmedSelected,
ImGuiWindowDockStyleCol_TabDimmedSelectedOverline,
ImGuiWindowDockStyleCol_COUNT
};
@@ -2135,6 +2140,7 @@ struct ImGuiContext
bool GcCompactAll; // Request full GC
bool TestEngineHookItems; // Will call test engine hooks: ImGuiTestEngineHook_ItemAdd(), ImGuiTestEngineHook_ItemInfo(), ImGuiTestEngineHook_Log()
void* TestEngine; // Test engine user data
char ContextName[16]; // Storage for a context name (to facilitate debugging multi-context setups)
// Inputs
ImVector<ImGuiInputEvent> InputEventsQueue; // Input events which will be trickled/written into IO structure.
@@ -2154,6 +2160,7 @@ struct ImGuiContext
ImGuiWindow* CurrentWindow; // Window being drawn into
ImGuiWindow* HoveredWindow; // Window the mouse is hovering. Will typically catch mouse inputs.
ImGuiWindow* HoveredWindowUnderMovingWindow; // Hovered window ignoring MovingWindow. Only set if MovingWindow is set.
ImGuiWindow* HoveredWindowBeforeClear; // Window the mouse is hovering. Filled even with _NoMouse. This is currently useful for multi-context compositors.
ImGuiWindow* MovingWindow; // Track the window we clicked on (in order to preserve focus). The actual window that is moved is generally MovingWindow->RootWindowDockTree.
ImGuiWindow* WheelingWindow; // Track the window we started mouse-wheeling on. Until a timer elapse or mouse has moved, generally keep scrolling the same window even if during the course of scrolling the mouse ends up hovering a child window.
ImVec2 WheelingWindowRefMousePos;
@@ -2170,7 +2177,7 @@ struct ImGuiContext
float HoveredIdTimer; // Measure contiguous hovering time
float HoveredIdNotActiveTimer; // Measure contiguous hovering time where the item has not been active
bool HoveredIdAllowOverlap;
bool HoveredIdDisabled; // At least one widget passed the rect test, but has been discarded by disabled flag or popup inhibit. May be true even if HoveredId == 0.
bool HoveredIdIsDisabled; // At least one widget passed the rect test, but has been discarded by disabled flag or popup inhibit. May be true even if HoveredId == 0.
bool ItemUnclipByLog; // Disable ItemAdd() clipping, essentially a memory-locality friendly copy of LogEnabled
ImGuiID ActiveId; // Active widget
ImGuiID ActiveIdIsAlive; // Active widget has been seen this frame (we can't use a bool as the ActiveId may change within the frame)
@@ -2247,6 +2254,7 @@ struct ImGuiContext
ImGuiWindow* NavWindow; // Focused window for navigation. Could be called 'FocusedWindow'
ImGuiID NavId; // Focused item for navigation
ImGuiID NavFocusScopeId; // Focused focus scope (e.g. selection code often wants to "clear other items" when landing on an item of the same scope)
ImGuiNavLayer NavLayer; // Focused layer (main scrolling layer, or menu/title bar layer)
ImGuiID NavActivateId; // ~~ (g.ActiveId == 0) && (IsKeyPressed(ImGuiKey_Space) || IsKeyDown(ImGuiKey_Enter) || IsKeyPressed(ImGuiKey_NavGamepadActivate)) ? NavId : 0, also set when calling ActivateItem()
ImGuiID NavActivateDownId; // ~~ IsKeyDown(ImGuiKey_Space) || IsKeyDown(ImGuiKey_Enter) || IsKeyDown(ImGuiKey_NavGamepadActivate) ? NavId : 0
ImGuiID NavActivatePressedId; // ~~ IsKeyPressed(ImGuiKey_Space) || IsKeyPressed(ImGuiKey_Enter) || IsKeyPressed(ImGuiKey_NavGamepadActivate) ? NavId : 0 (no repeat)
@@ -2254,13 +2262,9 @@ struct ImGuiContext
ImVector<ImGuiFocusScopeData> NavFocusRoute; // Reversed copy focus scope stack for NavId (should contains NavFocusScopeId). This essentially follow the window->ParentWindowForFocusRoute chain.
ImGuiID NavHighlightActivatedId;
float NavHighlightActivatedTimer;
ImGuiID NavJustMovedToId; // Just navigated to this id (result of a successfully MoveRequest).
ImGuiID NavJustMovedToFocusScopeId; // Just navigated to this focus scope id (result of a successfully MoveRequest).
ImGuiKeyChord NavJustMovedToKeyMods;
ImGuiID NavNextActivateId; // Set by ActivateItem(), queued until next frame.
ImGuiActivateFlags NavNextActivateFlags;
ImGuiInputSource NavInputSource; // Keyboard or Gamepad mode? THIS CAN ONLY BE ImGuiInputSource_Keyboard or ImGuiInputSource_Mouse
ImGuiNavLayer NavLayer; // Layer we are navigating on. For now the system is hard-coded for 0=main contents and 1=menu/title bar, may expose layers later.
ImGuiSelectionUserData NavLastValidSelectionUserData; // Last valid data passed to SetNextItemSelectionUser(), or -1. For current window. Not reset when focusing an item that doesn't have selection data.
bool NavIdIsAlive; // Nav widget has been seen this frame ~~ NavRectRel is valid
bool NavMousePosDirty; // When set we will update mouse position if (io.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos) if set (NB: this not enabled by default)
@@ -2291,6 +2295,14 @@ struct ImGuiContext
ImGuiNavItemData NavMoveResultOther; // Best move request candidate within NavWindow's flattened hierarchy (when using ImGuiWindowFlags_NavFlattened flag)
ImGuiNavItemData NavTabbingResultFirst; // First tabbing request candidate within NavWindow and flattened hierarchy
// Navigation: record of last move request
ImGuiID NavJustMovedFromFocusScopeId; // Just navigated from this focus scope id (result of a successfully MoveRequest).
ImGuiID NavJustMovedToId; // Just navigated to this id (result of a successfully MoveRequest).
ImGuiID NavJustMovedToFocusScopeId; // Just navigated to this focus scope id (result of a successfully MoveRequest).
ImGuiKeyChord NavJustMovedToKeyMods;
bool NavJustMovedToIsTabbing; // Copy of ImGuiNavMoveFlags_IsTabbing. Maybe we should store whole flags.
bool NavJustMovedToHasSelectionData; // Copy of move result's InFlags & ImGuiItemFlags_HasSelectionUserData). Maybe we should just store ImGuiNavItemData.
// Navigation: Windowing (CTRL+TAB for list, or Menu button + keys or directional pads to move/resize)
ImGuiKeyChord ConfigNavWindowingKeyNext; // = ImGuiMod_Ctrl | ImGuiKey_Tab (or ImGuiMod_Super | ImGuiKey_Tab on OS X). For reconfiguration (see #4828)
ImGuiKeyChord ConfigNavWindowingKeyPrev; // = ImGuiMod_Ctrl | ImGuiMod_Shift | ImGuiKey_Tab (or ImGuiMod_Super | ImGuiMod_Shift | ImGuiKey_Tab on OS X)
@@ -2479,6 +2491,7 @@ struct ImGuiContext
GcCompactAll = false;
TestEngineHookItems = false;
TestEngine = NULL;
memset(ContextName, 0, sizeof(ContextName));
InputEventsNextMouseSource = ImGuiMouseSource_Mouse;
InputEventsNextEventId = 1;
@@ -2487,6 +2500,7 @@ struct ImGuiContext
CurrentWindow = NULL;
HoveredWindow = NULL;
HoveredWindowUnderMovingWindow = NULL;
HoveredWindowBeforeClear = NULL;
MovingWindow = NULL;
WheelingWindow = NULL;
WheelingWindowStartFrame = WheelingWindowScrolledFrame = -1;
@@ -2495,7 +2509,7 @@ struct ImGuiContext
DebugHookIdInfo = 0;
HoveredId = HoveredIdPreviousFrame = 0;
HoveredIdAllowOverlap = false;
HoveredIdDisabled = false;
HoveredIdIsDisabled = false;
HoveredIdTimer = HoveredIdNotActiveTimer = 0.0f;
ItemUnclipByLog = false;
ActiveId = 0;
@@ -2539,18 +2553,18 @@ struct ImGuiContext
NavWindow = NULL;
NavId = NavFocusScopeId = NavActivateId = NavActivateDownId = NavActivatePressedId = 0;
NavJustMovedToId = NavJustMovedToFocusScopeId = NavNextActivateId = 0;
NavLayer = ImGuiNavLayer_Main;
NavNextActivateId = 0;
NavActivateFlags = NavNextActivateFlags = ImGuiActivateFlags_None;
NavHighlightActivatedId = 0;
NavHighlightActivatedTimer = 0.0f;
NavJustMovedToKeyMods = ImGuiMod_None;
NavInputSource = ImGuiInputSource_Keyboard;
NavLayer = ImGuiNavLayer_Main;
NavLastValidSelectionUserData = ImGuiSelectionUserData_Invalid;
NavIdIsAlive = false;
NavMousePosDirty = false;
NavDisableHighlight = true;
NavDisableMouseHover = false;
NavAnyRequest = false;
NavInitRequest = false;
NavInitRequestFromMove = false;
@@ -2565,6 +2579,11 @@ struct ImGuiContext
NavTabbingDir = 0;
NavTabbingCounter = 0;
NavJustMovedFromFocusScopeId = NavJustMovedToId = NavJustMovedToFocusScopeId = 0;
NavJustMovedToKeyMods = ImGuiMod_None;
NavJustMovedToIsTabbing = false;
NavJustMovedToHasSelectionData = false;
// All platforms use Ctrl+Tab but Ctrl<>Super are swapped on Mac...
// FIXME: Because this value is stored, it annoyingly interfere with toggling io.ConfigMacOSXBehaviors updating this..
ConfigNavWindowingKeyNext = IO.ConfigMacOSXBehaviors ? (ImGuiMod_Super | ImGuiKey_Tab) : (ImGuiMod_Ctrl | ImGuiKey_Tab);
@@ -3399,16 +3418,16 @@ namespace ImGui
IMGUI_API void LogRenderedText(const ImVec2* ref_pos, const char* text, const char* text_end = NULL);
IMGUI_API void LogSetNextTextDecoration(const char* prefix, const char* suffix);
// Popups, Modals, Tooltips
// Childs
IMGUI_API bool BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, ImGuiChildFlags child_flags, ImGuiWindowFlags window_flags);
// Popups, Modals
IMGUI_API bool BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_window_flags);
IMGUI_API void OpenPopupEx(ImGuiID id, ImGuiPopupFlags popup_flags = ImGuiPopupFlags_None);
IMGUI_API void ClosePopupToLevel(int remaining, bool restore_focus_to_window_under_popup);
IMGUI_API void ClosePopupsOverWindow(ImGuiWindow* ref_window, bool restore_focus_to_window_under_popup);
IMGUI_API void ClosePopupsExceptModals();
IMGUI_API bool IsPopupOpen(ImGuiID id, ImGuiPopupFlags popup_flags);
IMGUI_API bool BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_flags);
IMGUI_API bool BeginTooltipEx(ImGuiTooltipFlags tooltip_flags, ImGuiWindowFlags extra_window_flags);
IMGUI_API bool BeginTooltipHidden();
IMGUI_API ImRect GetPopupAllowedExtentRect(ImGuiWindow* window);
IMGUI_API ImGuiWindow* GetTopMostPopupModal();
IMGUI_API ImGuiWindow* GetTopMostAndVisiblePopupModal();
@@ -3416,6 +3435,10 @@ namespace ImGui
IMGUI_API ImVec2 FindBestWindowPosForPopup(ImGuiWindow* window);
IMGUI_API ImVec2 FindBestWindowPosForPopupEx(const ImVec2& ref_pos, const ImVec2& size, ImGuiDir* last_dir, const ImRect& r_outer, const ImRect& r_avoid, ImGuiPopupPositionPolicy policy);
// Tooltips
IMGUI_API bool BeginTooltipEx(ImGuiTooltipFlags tooltip_flags, ImGuiWindowFlags extra_window_flags);
IMGUI_API bool BeginTooltipHidden();
// Menus
IMGUI_API bool BeginViewportSideBar(const char* name, ImGuiViewport* viewport, ImGuiDir dir, float size, ImGuiWindowFlags window_flags);
IMGUI_API bool BeginMenuEx(const char* label, const char* icon, bool enabled = true);
@@ -3632,7 +3655,6 @@ namespace ImGui
IMGUI_API void TableOpenContextMenu(int column_n = -1);
IMGUI_API void TableSetColumnWidth(int column_n, float width);
IMGUI_API void TableSetColumnSortDirection(int column_n, ImGuiSortDirection sort_direction, bool append_to_sort_specs);
IMGUI_API int TableGetHoveredColumn(); // May use (TableGetColumnFlags() & ImGuiTableColumnFlags_IsHovered) instead. Return hovered column. return -1 when table is not hovered. return columns_count if the unused space at the right of visible columns is hovered.
IMGUI_API int TableGetHoveredRow(); // Retrieve *PREVIOUS FRAME* hovered row. This difference with TableGetHoveredColumn() is the reason why this is not public yet.
IMGUI_API float TableGetHeaderRowHeight();
IMGUI_API float TableGetHeaderAngledMaxLabelWidth();

View File

@@ -1,4 +1,4 @@
// dear imgui, v1.90.8
// dear imgui, v1.90.9
// (main code and documentation)
// Help:
@@ -438,6 +438,13 @@ CODE
- likewise io.MousePos and GetMousePos() will use OS coordinates.
If you query mouse positions to interact with non-imgui coordinates you will need to offset them, e.g. subtract GetWindowViewport()->Pos.
- 2024/06/21 (1.90.9) - BeginChild: added ImGuiChildFlags_NavFlattened as a replacement for the window flag ImGuiWindowFlags_NavFlattened: the feature only ever made sense for BeginChild() anyhow.
- old: BeginChild("Name", size, 0, ImGuiWindowFlags_NavFlattened);
- new: BeginChild("Name", size, ImGuiChildFlags_NavFlattened, 0);
- 2024/06/21 (1.90.9) - io: ClearInputKeys() (first exposed in 1.89.8) doesn't clear mouse data, newly added ClearInputMouse() does.
- 2024/06/20 (1.90.9) - renamed ImGuiDragDropFlags_SourceAutoExpirePayload to ImGuiDragDropFlags_PayloadAutoExpire.
- 2024/06/18 (1.90.9) - style: renamed ImGuiCol_TabActive -> ImGuiCol_TabSelected, ImGuiCol_TabUnfocused -> ImGuiCol_TabDimmed, ImGuiCol_TabUnfocusedActive -> ImGuiCol_TabDimmedSelected.
- 2024/06/10 (1.90.9) - removed old nested structure: renaming ImGuiStorage::ImGuiStoragePair type to ImGuiStoragePair (simpler for many languages).
- 2024/06/06 (1.90.8) - reordered ImGuiInputTextFlags values. This should not be breaking unless you are using generated headers that have values not matching the main library.
- 2024/06/06 (1.90.8) - removed 'ImGuiButtonFlags_MouseButtonDefault_ = ImGuiButtonFlags_MouseButtonLeft', was mostly unused and misleading.
- 2024/05/27 (1.90.7) - commented out obsolete symbols marked obsolete in 1.88 (May 2022):
@@ -1494,7 +1501,7 @@ void ImGuiIO::ClearEventsQueue()
g.InputEventsQueue.clear();
}
// Clear current keyboard/mouse/gamepad state + current frame text input buffer. Equivalent to releasing all keys/buttons.
// Clear current keyboard/gamepad state + current frame text input buffer. Equivalent to releasing all keys/buttons.
void ImGuiIO::ClearInputKeys()
{
#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO
@@ -1502,12 +1509,26 @@ void ImGuiIO::ClearInputKeys()
#endif
for (int n = 0; n < IM_ARRAYSIZE(KeysData); n++)
{
if (ImGui::IsMouseKey((ImGuiKey)(n + ImGuiKey_KeysData_OFFSET)))
continue;
KeysData[n].Down = false;
KeysData[n].DownDuration = -1.0f;
KeysData[n].DownDurationPrev = -1.0f;
}
KeyCtrl = KeyShift = KeyAlt = KeySuper = false;
KeyMods = ImGuiMod_None;
InputQueueCharacters.resize(0); // Behavior of old ClearInputCharacters().
}
void ImGuiIO::ClearInputMouse()
{
for (ImGuiKey key = ImGuiKey_Mouse_BEGIN; key < ImGuiKey_Mouse_END; key = (ImGuiKey)(key + 1))
{
ImGuiKeyData* key_data = &KeysData[key - ImGuiKey_KeysData_OFFSET];
key_data->Down = false;
key_data->DownDuration = -1.0f;
key_data->DownDurationPrev = -1.0f;
}
MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
for (int n = 0; n < IM_ARRAYSIZE(MouseDown); n++)
{
@@ -1515,7 +1536,6 @@ void ImGuiIO::ClearInputKeys()
MouseDownDuration[n] = MouseDownDurationPrev[n] = -1.0f;
}
MouseWheel = MouseWheelH = 0.0f;
InputQueueCharacters.resize(0); // Behavior of old ClearInputCharacters().
}
// Removed this as it is ambiguous/misleading and generally incorrect to use with the existence of a higher-level input queue.
@@ -2567,18 +2587,16 @@ void ImGui::ColorConvertHSVtoRGB(float h, float s, float v, float& out_r, float&
//-----------------------------------------------------------------------------
// std::lower_bound but without the bullshit
static ImGuiStorage::ImGuiStoragePair* LowerBound(ImVector<ImGuiStorage::ImGuiStoragePair>& data, ImGuiID key)
ImGuiStoragePair* ImLowerBound(ImGuiStoragePair* in_begin, ImGuiStoragePair* in_end, ImGuiID key)
{
ImGuiStorage::ImGuiStoragePair* first = data.Data;
ImGuiStorage::ImGuiStoragePair* last = data.Data + data.Size;
size_t count = (size_t)(last - first);
while (count > 0)
ImGuiStoragePair* in_p = in_begin;
for (size_t count = (size_t)(in_end - in_p); count > 0; )
{
size_t count2 = count >> 1;
ImGuiStorage::ImGuiStoragePair* mid = first + count2;
ImGuiStoragePair* mid = in_p + count2;
if (mid->key < key)
{
first = ++mid;
in_p = ++mid;
count -= count2 + 1;
}
else
@@ -2586,28 +2604,26 @@ static ImGuiStorage::ImGuiStoragePair* LowerBound(ImVector<ImGuiStorage::ImGuiSt
count = count2;
}
}
return first;
return in_p;
}
static int IMGUI_CDECL PairComparerByID(const void* lhs, const void* rhs)
{
// We can't just do a subtraction because qsort uses signed integers and subtracting our ID doesn't play well with that.
ImGuiID lhs_v = ((const ImGuiStoragePair*)lhs)->key;
ImGuiID rhs_v = ((const ImGuiStoragePair*)rhs)->key;
return (lhs_v > rhs_v ? +1 : lhs_v < rhs_v ? -1 : 0);
}
// For quicker full rebuild of a storage (instead of an incremental one), you may add all your contents and then sort once.
void ImGuiStorage::BuildSortByKey()
{
struct StaticFunc
{
static int IMGUI_CDECL PairComparerByID(const void* lhs, const void* rhs)
{
// We can't just do a subtraction because qsort uses signed integers and subtracting our ID doesn't play well with that.
if (((const ImGuiStoragePair*)lhs)->key > ((const ImGuiStoragePair*)rhs)->key) return +1;
if (((const ImGuiStoragePair*)lhs)->key < ((const ImGuiStoragePair*)rhs)->key) return -1;
return 0;
}
};
ImQsort(Data.Data, (size_t)Data.Size, sizeof(ImGuiStoragePair), StaticFunc::PairComparerByID);
ImQsort(Data.Data, (size_t)Data.Size, sizeof(ImGuiStoragePair), PairComparerByID);
}
int ImGuiStorage::GetInt(ImGuiID key, int default_val) const
{
ImGuiStoragePair* it = LowerBound(const_cast<ImVector<ImGuiStoragePair>&>(Data), key);
ImGuiStoragePair* it = ImLowerBound(const_cast<ImGuiStoragePair*>(Data.Data), const_cast<ImGuiStoragePair*>(Data.Data + Data.Size), key);
if (it == Data.end() || it->key != key)
return default_val;
return it->val_i;
@@ -2620,7 +2636,7 @@ bool ImGuiStorage::GetBool(ImGuiID key, bool default_val) const
float ImGuiStorage::GetFloat(ImGuiID key, float default_val) const
{
ImGuiStoragePair* it = LowerBound(const_cast<ImVector<ImGuiStoragePair>&>(Data), key);
ImGuiStoragePair* it = ImLowerBound(const_cast<ImGuiStoragePair*>(Data.Data), const_cast<ImGuiStoragePair*>(Data.Data + Data.Size), key);
if (it == Data.end() || it->key != key)
return default_val;
return it->val_f;
@@ -2628,7 +2644,7 @@ float ImGuiStorage::GetFloat(ImGuiID key, float default_val) const
void* ImGuiStorage::GetVoidPtr(ImGuiID key) const
{
ImGuiStoragePair* it = LowerBound(const_cast<ImVector<ImGuiStoragePair>&>(Data), key);
ImGuiStoragePair* it = ImLowerBound(const_cast<ImGuiStoragePair*>(Data.Data), const_cast<ImGuiStoragePair*>(Data.Data + Data.Size), key);
if (it == Data.end() || it->key != key)
return NULL;
return it->val_p;
@@ -2637,7 +2653,7 @@ void* ImGuiStorage::GetVoidPtr(ImGuiID key) const
// References are only valid until a new value is added to the storage. Calling a Set***() function or a Get***Ref() function invalidates the pointer.
int* ImGuiStorage::GetIntRef(ImGuiID key, int default_val)
{
ImGuiStoragePair* it = LowerBound(Data, key);
ImGuiStoragePair* it = ImLowerBound(Data.Data, Data.Data + Data.Size, key);
if (it == Data.end() || it->key != key)
it = Data.insert(it, ImGuiStoragePair(key, default_val));
return &it->val_i;
@@ -2650,7 +2666,7 @@ bool* ImGuiStorage::GetBoolRef(ImGuiID key, bool default_val)
float* ImGuiStorage::GetFloatRef(ImGuiID key, float default_val)
{
ImGuiStoragePair* it = LowerBound(Data, key);
ImGuiStoragePair* it = ImLowerBound(Data.Data, Data.Data + Data.Size, key);
if (it == Data.end() || it->key != key)
it = Data.insert(it, ImGuiStoragePair(key, default_val));
return &it->val_f;
@@ -2658,7 +2674,7 @@ float* ImGuiStorage::GetFloatRef(ImGuiID key, float default_val)
void** ImGuiStorage::GetVoidPtrRef(ImGuiID key, void* default_val)
{
ImGuiStoragePair* it = LowerBound(Data, key);
ImGuiStoragePair* it = ImLowerBound(Data.Data, Data.Data + Data.Size, key);
if (it == Data.end() || it->key != key)
it = Data.insert(it, ImGuiStoragePair(key, default_val));
return &it->val_p;
@@ -2667,7 +2683,7 @@ void** ImGuiStorage::GetVoidPtrRef(ImGuiID key, void* default_val)
// FIXME-OPT: Need a way to reuse the result of lower_bound when doing GetInt()/SetInt() - not too bad because it only happens on explicit interaction (maximum one a frame)
void ImGuiStorage::SetInt(ImGuiID key, int val)
{
ImGuiStoragePair* it = LowerBound(Data, key);
ImGuiStoragePair* it = ImLowerBound(Data.Data, Data.Data + Data.Size, key);
if (it == Data.end() || it->key != key)
Data.insert(it, ImGuiStoragePair(key, val));
else
@@ -2681,7 +2697,7 @@ void ImGuiStorage::SetBool(ImGuiID key, bool val)
void ImGuiStorage::SetFloat(ImGuiID key, float val)
{
ImGuiStoragePair* it = LowerBound(Data, key);
ImGuiStoragePair* it = ImLowerBound(Data.Data, Data.Data + Data.Size, key);
if (it == Data.end() || it->key != key)
Data.insert(it, ImGuiStoragePair(key, val));
else
@@ -2690,7 +2706,7 @@ void ImGuiStorage::SetFloat(ImGuiID key, float val)
void ImGuiStorage::SetVoidPtr(ImGuiID key, void* val)
{
ImGuiStoragePair* it = LowerBound(Data, key);
ImGuiStoragePair* it = ImLowerBound(Data.Data, Data.Data + Data.Size, key);
if (it == Data.end() || it->key != key)
Data.insert(it, ImGuiStoragePair(key, val));
else
@@ -3256,7 +3272,7 @@ void ImGui::PopStyleColor(int count)
static const ImGuiCol GWindowDockStyleColors[ImGuiWindowDockStyleCol_COUNT] =
{
ImGuiCol_Text, ImGuiCol_Tab, ImGuiCol_TabHovered, ImGuiCol_TabActive, ImGuiCol_TabUnfocused, ImGuiCol_TabUnfocusedActive
ImGuiCol_Text, ImGuiCol_TabHovered, ImGuiCol_Tab, ImGuiCol_TabSelected, ImGuiCol_TabSelectedOverline, ImGuiCol_TabDimmed, ImGuiCol_TabDimmedSelected, ImGuiCol_TabDimmedSelectedOverline,
};
static const ImGuiDataVarInfo GStyleVarInfo[] =
@@ -3390,11 +3406,13 @@ const char* ImGui::GetStyleColorName(ImGuiCol idx)
case ImGuiCol_ResizeGrip: return "ResizeGrip";
case ImGuiCol_ResizeGripHovered: return "ResizeGripHovered";
case ImGuiCol_ResizeGripActive: return "ResizeGripActive";
case ImGuiCol_Tab: return "Tab";
case ImGuiCol_TabHovered: return "TabHovered";
case ImGuiCol_TabActive: return "TabActive";
case ImGuiCol_TabUnfocused: return "TabUnfocused";
case ImGuiCol_TabUnfocusedActive: return "TabUnfocusedActive";
case ImGuiCol_Tab: return "Tab";
case ImGuiCol_TabSelected: return "TabSelected";
case ImGuiCol_TabSelectedOverline: return "TabSelectedOverline";
case ImGuiCol_TabDimmed: return "TabDimmed";
case ImGuiCol_TabDimmedSelected: return "TabDimmedSelected";
case ImGuiCol_TabDimmedSelectedOverline: return "TabDimmedSelectedOverline";
case ImGuiCol_DockingPreview: return "DockingPreview";
case ImGuiCol_DockingEmptyBg: return "DockingEmptyBg";
case ImGuiCol_PlotLines: return "PlotLines";
@@ -4276,7 +4294,7 @@ bool ImGui::ItemHoverable(const ImRect& bb, ImGuiID id, ImGuiItemFlags item_flag
// Done with rectangle culling so we can perform heavier checks now.
if (!(item_flags & ImGuiItemFlags_NoWindowHoverableCheck) && !IsWindowContentHoverable(window, ImGuiHoveredFlags_None))
{
g.HoveredIdDisabled = true;
g.HoveredIdIsDisabled = true;
return false;
}
@@ -4300,6 +4318,7 @@ bool ImGui::ItemHoverable(const ImRect& bb, ImGuiID id, ImGuiItemFlags item_flag
}
// Display shortcut (only works with mouse)
// (ImGuiItemStatusFlags_HasShortcut in LastItemData denotes we want a tooltip)
if (id == g.LastItemData.ID && (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HasShortcut))
if (IsItemHovered(ImGuiHoveredFlags_ForTooltip | ImGuiHoveredFlags_DelayNormal))
SetTooltip("%s", GetKeyChordName(g.LastItemData.Shortcut));
@@ -4311,7 +4330,7 @@ bool ImGui::ItemHoverable(const ImRect& bb, ImGuiID id, ImGuiItemFlags item_flag
// Release active id if turning disabled
if (g.ActiveId == id && id != 0)
ClearActiveID();
g.HoveredIdDisabled = true;
g.HoveredIdIsDisabled = true;
return false;
}
@@ -4457,7 +4476,7 @@ ImGuiIO& ImGui::GetIO()
ImGuiPlatformIO& ImGui::GetPlatformIO()
{
IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() or ImGui::SetCurrentContext()?");
IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() and ImGui::SetCurrentContext()?");
return GImGui->PlatformIO;
}
@@ -4505,26 +4524,18 @@ static ImDrawList* GetViewportBgFgDrawList(ImGuiViewportP* viewport, size_t draw
ImDrawList* ImGui::GetBackgroundDrawList(ImGuiViewport* viewport)
{
if (viewport == NULL)
viewport = GImGui->CurrentWindow->Viewport;
return GetViewportBgFgDrawList((ImGuiViewportP*)viewport, 0, "##Background");
}
ImDrawList* ImGui::GetBackgroundDrawList()
{
ImGuiContext& g = *GImGui;
return GetBackgroundDrawList(g.CurrentWindow->Viewport);
}
ImDrawList* ImGui::GetForegroundDrawList(ImGuiViewport* viewport)
{
if (viewport == NULL)
viewport = GImGui->CurrentWindow->Viewport;
return GetViewportBgFgDrawList((ImGuiViewportP*)viewport, 1, "##Foreground");
}
ImDrawList* ImGui::GetForegroundDrawList()
{
ImGuiContext& g = *GImGui;
return GetForegroundDrawList(g.CurrentWindow->Viewport);
}
ImDrawListSharedData* ImGui::GetDrawListSharedData()
{
return &GImGui->DrawListSharedData;
@@ -4674,7 +4685,7 @@ void ImGui::UpdateMouseMovingWindowEndFrame()
g.MovingWindow = NULL;
// Cancel moving if clicked over an item which was disabled or inhibited by popups (note that we know HoveredId == 0 already)
if (g.HoveredIdDisabled)
if (g.HoveredIdIsDisabled)
g.MovingWindow = NULL;
}
else if (root_window == NULL && g.NavWindow != NULL)
@@ -4742,13 +4753,14 @@ void ImGui::UpdateHoveredWindowAndCaptureFlags()
bool clear_hovered_windows = false;
FindHoveredWindowEx(g.IO.MousePos, false, &g.HoveredWindow, &g.HoveredWindowUnderMovingWindow);
IM_ASSERT(g.HoveredWindow == NULL || g.HoveredWindow == g.MovingWindow || g.HoveredWindow->Viewport == g.MouseViewport);
g.HoveredWindowBeforeClear = g.HoveredWindow;
// Modal windows prevents mouse from hovering behind them.
ImGuiWindow* modal_window = GetTopMostPopupModal();
if (modal_window && g.HoveredWindow && !IsWindowWithinBeginStackOf(g.HoveredWindow->RootWindow, modal_window)) // FIXME-MERGE: RootWindowDockTree ?
clear_hovered_windows = true;
// Disabled mouse?
// Disabled mouse hovering (we don't currently clear MousePos, we could)
if (io.ConfigFlags & ImGuiConfigFlags_NoMouse)
clear_hovered_windows = true;
@@ -4766,7 +4778,7 @@ void ImGui::UpdateHoveredWindowAndCaptureFlags()
io.MouseDownOwnedUnlessPopupClose[i] = (g.HoveredWindow != NULL) || has_open_modal;
}
mouse_any_down |= io.MouseDown[i];
if (io.MouseDown[i])
if (io.MouseDown[i] || io.MouseReleased[i]) // Increase release frame for our evaluation of earliest button (#1392)
if (mouse_earliest_down == -1 || io.MouseClickedTime[i] < io.MouseClickedTime[mouse_earliest_down])
mouse_earliest_down = i;
}
@@ -4898,7 +4910,7 @@ void ImGui::NewFrame()
g.HoveredIdPreviousFrame = g.HoveredId;
g.HoveredId = 0;
g.HoveredIdAllowOverlap = false;
g.HoveredIdDisabled = false;
g.HoveredIdIsDisabled = false;
// Clear ActiveID if the item is not alive anymore.
// In 1.87, the common most call to KeepAliveID() was moved from GetID() to ItemAdd().
@@ -5392,12 +5404,16 @@ void ImGui::EndFrame()
if (g.DragDropActive)
{
bool is_delivered = g.DragDropPayload.Delivery;
bool is_elapsed = (g.DragDropPayload.DataFrameCount + 1 < g.FrameCount) && ((g.DragDropSourceFlags & ImGuiDragDropFlags_SourceAutoExpirePayload) || !IsMouseDown(g.DragDropMouseButton));
bool is_elapsed = (g.DragDropSourceFrameCount + 1 < g.FrameCount) && ((g.DragDropSourceFlags & ImGuiDragDropFlags_PayloadAutoExpire) || g.DragDropMouseButton == -1 || !IsMouseDown(g.DragDropMouseButton));
if (is_delivered || is_elapsed)
ClearDragDrop();
}
// Drag and Drop: Fallback for source tooltip. This is not ideal but better than nothing.
// Drag and Drop: Fallback for missing source tooltip. This is not ideal but better than nothing.
// If you want to handle source item disappearing: instead of submitting your description tooltip
// in the BeginDragDropSource() block of the dragged item, you can submit them from a safe single spot
// (e.g. end of your item loop, or before EndFrame) by reading payload data.
// In the typical case, the contents of drag tooltip should be possible to infer solely from payload data.
if (g.DragDropActive && g.DragDropSourceFrameCount < g.FrameCount && !(g.DragDropSourceFlags & ImGuiDragDropFlags_SourceNoPreviewTooltip))
{
g.DragDropWithinSource = true;
@@ -5791,7 +5807,7 @@ bool ImGui::BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, I
IM_ASSERT(id != 0);
// Sanity check as it is likely that some user will accidentally pass ImGuiWindowFlags into the ImGuiChildFlags argument.
const ImGuiChildFlags ImGuiChildFlags_SupportedMask_ = ImGuiChildFlags_Border | ImGuiChildFlags_AlwaysUseWindowPadding | ImGuiChildFlags_ResizeX | ImGuiChildFlags_ResizeY | ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY | ImGuiChildFlags_AlwaysAutoResize | ImGuiChildFlags_FrameStyle;
const ImGuiChildFlags ImGuiChildFlags_SupportedMask_ = ImGuiChildFlags_Border | ImGuiChildFlags_AlwaysUseWindowPadding | ImGuiChildFlags_ResizeX | ImGuiChildFlags_ResizeY | ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY | ImGuiChildFlags_AlwaysAutoResize | ImGuiChildFlags_FrameStyle | ImGuiChildFlags_NavFlattened;
IM_UNUSED(ImGuiChildFlags_SupportedMask_);
IM_ASSERT((child_flags & ~ImGuiChildFlags_SupportedMask_) == 0 && "Illegal ImGuiChildFlags value. Did you pass ImGuiWindowFlags values instead of ImGuiChildFlags?");
IM_ASSERT((window_flags & ImGuiWindowFlags_AlwaysAutoResize) == 0 && "Cannot specify ImGuiWindowFlags_AlwaysAutoResize for BeginChild(). Use ImGuiChildFlags_AlwaysAutoResize!");
@@ -5803,6 +5819,8 @@ bool ImGui::BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, I
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
if (window_flags & ImGuiWindowFlags_AlwaysUseWindowPadding)
child_flags |= ImGuiChildFlags_AlwaysUseWindowPadding;
if (window_flags & ImGuiWindowFlags_NavFlattened)
child_flags |= ImGuiChildFlags_NavFlattened;
#endif
if (child_flags & ImGuiChildFlags_AutoResizeX)
child_flags &= ~ImGuiChildFlags_ResizeX;
@@ -5881,7 +5899,7 @@ bool ImGui::BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, I
const ImGuiID temp_id_for_activation = ImHashStr("##Child", 0, id);
if (g.ActiveId == temp_id_for_activation)
ClearActiveID();
if (g.NavActivateId == id && !(window_flags & ImGuiWindowFlags_NavFlattened) && (child_window->DC.NavLayersActiveMask != 0 || child_window->DC.NavWindowHasScrollY))
if (g.NavActivateId == id && !(child_flags & ImGuiChildFlags_NavFlattened) && (child_window->DC.NavLayersActiveMask != 0 || child_window->DC.NavWindowHasScrollY))
{
FocusWindow(child_window);
NavInitWindow(child_window, false);
@@ -5907,7 +5925,8 @@ void ImGui::EndChild()
ImGuiWindow* parent_window = g.CurrentWindow;
ImRect bb(parent_window->DC.CursorPos, parent_window->DC.CursorPos + child_size);
ItemSize(child_size);
if ((child_window->DC.NavLayersActiveMask != 0 || child_window->DC.NavWindowHasScrollY) && !(child_window->Flags & ImGuiWindowFlags_NavFlattened))
const bool nav_flattened = (child_window->ChildFlags & ImGuiChildFlags_NavFlattened) != 0;
if ((child_window->DC.NavLayersActiveMask != 0 || child_window->DC.NavWindowHasScrollY) && !nav_flattened)
{
ItemAdd(bb, child_window->ChildId);
RenderNavHighlight(bb, child_window->ChildId);
@@ -5924,7 +5943,7 @@ void ImGui::EndChild()
ItemAdd(bb, child_window->ChildId, NULL, ImGuiItemFlags_NoNav);
// But when flattened we directly reach items, adjust active layer mask accordingly
if (child_window->Flags & ImGuiWindowFlags_NavFlattened)
if (nav_flattened)
parent_window->DC.NavLayersActiveMaskNext |= child_window->DC.NavLayersActiveMaskNext;
}
if (g.HoveredWindow == child_window)
@@ -6150,10 +6169,18 @@ static ImVec2 CalcWindowAutoFitSize(ImGuiWindow* window, const ImVec2& size_cont
{
// Maximum window size is determined by the viewport size or monitor size
ImVec2 size_min = CalcWindowMinSize(window);
ImVec2 size_max = (window->ViewportOwned || ((window->Flags & ImGuiWindowFlags_ChildWindow) && !(window->Flags & ImGuiWindowFlags_Popup))) ? ImVec2(FLT_MAX, FLT_MAX) : ImGui::GetMainViewport()->WorkSize - style.DisplaySafeAreaPadding * 2.0f;
const int monitor_idx = window->ViewportAllowPlatformMonitorExtend;
if (monitor_idx >= 0 && monitor_idx < g.PlatformIO.Monitors.Size && (window->Flags & ImGuiWindowFlags_ChildWindow) == 0)
size_max = g.PlatformIO.Monitors[monitor_idx].WorkSize - style.DisplaySafeAreaPadding * 2.0f;
ImVec2 size_max = ImVec2(FLT_MAX, FLT_MAX);
// Child windows are layed within their parent (unless they are also popups/menus) and thus have no restriction
if ((window->Flags & ImGuiWindowFlags_ChildWindow) == 0 || (window->Flags & ImGuiWindowFlags_Popup) != 0)
{
if (!window->ViewportOwned)
size_max = ImGui::GetMainViewport()->WorkSize - style.DisplaySafeAreaPadding * 2.0f;
const int monitor_idx = window->ViewportAllowPlatformMonitorExtend;
if (monitor_idx >= 0 && monitor_idx < g.PlatformIO.Monitors.Size)
size_max = g.PlatformIO.Monitors[monitor_idx].WorkSize - style.DisplaySafeAreaPadding * 2.0f;
}
ImVec2 size_auto_fit = ImClamp(size_desired, size_min, ImMax(size_min, size_max));
// FIXME: CalcWindowAutoFitSize() doesn't take into account that only one axis may be auto-fit when calculating scrollbars,
@@ -6427,12 +6454,13 @@ static int ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& si
border_target = ImClamp(border_target, clamp_min, clamp_max);
if (flags & ImGuiWindowFlags_ChildWindow) // Clamp resizing of childs within parent
{
ImGuiWindowFlags parent_flags = window->ParentWindow->Flags;
ImRect border_limit_rect = window->ParentWindow->InnerRect;
border_limit_rect.Expand(ImVec2(-ImMax(window->WindowPadding.x, window->WindowBorderSize), -ImMax(window->WindowPadding.y, window->WindowBorderSize)));
if ((parent_flags & (ImGuiWindowFlags_HorizontalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar)) == 0 || (parent_flags & ImGuiWindowFlags_NoScrollbar))
ImGuiWindow* parent_window = window->ParentWindow;
ImGuiWindowFlags parent_flags = parent_window->Flags;
ImRect border_limit_rect = parent_window->InnerRect;
border_limit_rect.Expand(ImVec2(-ImMax(parent_window->WindowPadding.x, parent_window->WindowBorderSize), -ImMax(parent_window->WindowPadding.y, parent_window->WindowBorderSize)));
if ((axis == ImGuiAxis_X) && ((parent_flags & (ImGuiWindowFlags_HorizontalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar)) == 0 || (parent_flags & ImGuiWindowFlags_NoScrollbar)))
border_target.x = ImClamp(border_target.x, border_limit_rect.Min.x, border_limit_rect.Max.x);
if (parent_flags & ImGuiWindowFlags_NoScrollbar)
if ((axis == ImGuiAxis_Y) && (parent_flags & ImGuiWindowFlags_NoScrollbar))
border_target.y = ImClamp(border_target.y, border_limit_rect.Min.y, border_limit_rect.Max.y);
}
if (!ignore_resize)
@@ -6812,7 +6840,7 @@ void ImGui::UpdateWindowParentAndRootLinks(ImGuiWindow* window, ImGuiWindowFlags
window->RootWindowPopupTree = parent_window->RootWindowPopupTree;
if (parent_window && !(flags & ImGuiWindowFlags_Modal) && (flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Popup))) // FIXME: simply use _NoTitleBar ?
window->RootWindowForTitleBarHighlight = parent_window->RootWindowForTitleBarHighlight;
while (window->RootWindowForNav->Flags & ImGuiWindowFlags_NavFlattened)
while (window->RootWindowForNav->ChildFlags & ImGuiChildFlags_NavFlattened)
{
IM_ASSERT(window->RootWindowForNav->ParentWindow != NULL);
window->RootWindowForNav = window->RootWindowForNav->ParentWindow;
@@ -6908,9 +6936,6 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
if ((flags & ImGuiWindowFlags_NoInputs) == ImGuiWindowFlags_NoInputs)
flags |= ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize;
if (flags & ImGuiWindowFlags_NavFlattened)
IM_ASSERT(flags & ImGuiWindowFlags_ChildWindow);
const int current_frame = g.FrameCount;
const bool first_begin_of_the_frame = (window->LastFrameActive != current_frame);
window->IsFallbackWindow = (g.CurrentWindowStack.Size == 0 && g.WithinFrameScopeWithImplicitWindow);
@@ -6994,7 +7019,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
window_stack_data.Window = window;
window_stack_data.ParentLastItemDataBackup = g.LastItemData;
window_stack_data.StackSizesOnBegin.SetToContextState(&g);
window_stack_data.DisabledOverrideReenable = (g.CurrentItemFlags & ImGuiItemFlags_Disabled) != 0;
window_stack_data.DisabledOverrideReenable = (flags & ImGuiWindowFlags_Tooltip) && (g.CurrentItemFlags & ImGuiItemFlags_Disabled);
g.CurrentWindowStack.push_back(window_stack_data);
if (flags & ImGuiWindowFlags_ChildMenu)
g.BeginMenuDepth++;
@@ -7022,7 +7047,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
}
// Add to focus scope stack
PushFocusScope((flags & ImGuiWindowFlags_NavFlattened) ? g.CurrentFocusScopeId : window->ID);
PushFocusScope((window->ChildFlags & ImGuiChildFlags_NavFlattened) ? g.CurrentFocusScopeId : window->ID);
window->NavRootFocusScopeId = g.CurrentFocusScopeId;
// Add to popup stacks: update OpenPopupStack[] data, push to BeginPopupStack[]
@@ -7734,8 +7759,8 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
{
// Child window can be out of sight and have "negative" clip windows.
// Mark them as collapsed so commands are skipped earlier (we can't manually collapse them because they have no title bar).
IM_ASSERT((flags& ImGuiWindowFlags_NoTitleBar) != 0 || window->DockIsActive);
const bool nav_request = (flags & ImGuiWindowFlags_NavFlattened) && (g.NavAnyRequest && g.NavWindow && g.NavWindow->RootWindowForNav == window->RootWindowForNav);
IM_ASSERT((flags & ImGuiWindowFlags_NoTitleBar) != 0 || window->DockIsActive);
const bool nav_request = (window->ChildFlags & ImGuiChildFlags_NavFlattened) && (g.NavAnyRequest && g.NavWindow && g.NavWindow->RootWindowForNav == window->RootWindowForNav);
if (!g.LogEnabled && !nav_request)
if (window->OuterRectClipped.Min.x >= window->OuterRectClipped.Max.x || window->OuterRectClipped.Min.y >= window->OuterRectClipped.Max.y)
{
@@ -9766,6 +9791,9 @@ static void ImGui::UpdateKeyboardInputs()
ImGuiContext& g = *GImGui;
ImGuiIO& io = g.IO;
if (io.ConfigFlags & ImGuiConfigFlags_NoKeyboard)
io.ClearInputKeys();
// Import legacy keys or verify they are not used
#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO
if (io.BackendUsingLegacyKeyArrays == 0)
@@ -10220,6 +10248,8 @@ void ImGui::UpdateInputEvents(bool trickle_fast_inputs)
else if (e->Type == ImGuiInputEventType_Key)
{
// Trickling Rule: Stop processing queued events if we got multiple action on the same button
if (io.ConfigFlags & ImGuiConfigFlags_NoKeyboard)
continue;
ImGuiKey key = e->Key.Key;
IM_ASSERT(key != ImGuiKey_None);
ImGuiKeyData* key_data = GetKeyData(key);
@@ -10240,6 +10270,8 @@ void ImGui::UpdateInputEvents(bool trickle_fast_inputs)
}
else if (e->Type == ImGuiInputEventType_Text)
{
if (io.ConfigFlags & ImGuiConfigFlags_NoKeyboard)
continue;
// Trickling Rule: Stop processing queued events if keys/mouse have been interacted with
if (trickle_fast_inputs && ((key_changed && trickle_interleaved_keys_and_text) || mouse_button_changed != 0 || mouse_moved || mouse_wheeled))
break;
@@ -10284,7 +10316,10 @@ void ImGui::UpdateInputEvents(bool trickle_fast_inputs)
// - we clear in EndFrame() and not now in order allow application/user code polling this flag
// (e.g. custom backend may want to clear additional data, custom widgets may want to react with a "canceling" event).
if (g.IO.AppFocusLost)
{
g.IO.ClearInputKeys();
g.IO.ClearInputMouse();
}
}
ImGuiID ImGui::GetKeyOwner(ImGuiKey key)
@@ -10419,12 +10454,15 @@ void ImGui::SetNextItemShortcut(ImGuiKeyChord key_chord, ImGuiInputFlags flags)
g.NextItemData.ShortcutFlags = flags;
}
// Called from within ItemAdd: at this point we can read from NextItemData and write to LastItemData
void ImGui::ItemHandleShortcut(ImGuiID id)
{
ImGuiContext& g = *GImGui;
ImGuiInputFlags flags = g.NextItemData.ShortcutFlags;
IM_ASSERT((flags & ~ImGuiInputFlags_SupportedBySetNextItemShortcut) == 0); // Passing flags not supported by SetNextItemShortcut()!
if (g.LastItemData.InFlags & ImGuiItemFlags_Disabled)
return;
if (flags & ImGuiInputFlags_Tooltip)
{
g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HasShortcut;
@@ -10448,7 +10486,7 @@ bool ImGui::Shortcut(ImGuiKeyChord key_chord, ImGuiInputFlags flags)
bool ImGui::Shortcut(ImGuiKeyChord key_chord, ImGuiInputFlags flags, ImGuiID owner_id)
{
//ImGuiContext& g = *GImGui;
ImGuiContext& g = *GImGui;
//IMGUI_DEBUG_LOG("Shortcut(%s, flags=%X, owner_id=0x%08X)\n", GetKeyChordName(key_chord, g.TempBuffer.Data, g.TempBuffer.Size), flags, owner_id);
// When using (owner_id == 0/Any): SetShortcutRouting() will use CurrentFocusScopeId and filter with this, so IsKeyPressed() is fine with he 0/Any.
@@ -10460,6 +10498,9 @@ bool ImGui::Shortcut(ImGuiKeyChord key_chord, ImGuiInputFlags flags, ImGuiID own
if (owner_id == ImGuiKeyOwner_Any || owner_id == ImGuiKeyOwner_NoOwner)
owner_id = GetRoutingIdFromOwnerId(owner_id);
if (g.CurrentItemFlags & ImGuiItemFlags_Disabled)
return false;
// Submit route
if (!SetShortcutRouting(key_chord, flags, owner_id))
return false;
@@ -10580,10 +10621,6 @@ static void ImGui::ErrorCheckNewFrameSanityChecks()
IM_ASSERT(g.IO.KeyMap[ImGuiKey_Space] != -1 && "ImGuiKey_Space is not mapped, required for keyboard navigation.");
#endif
// Check: the io.ConfigWindowsResizeFromEdges option requires backend to honor mouse cursor changes and set the ImGuiBackendFlags_HasMouseCursors flag accordingly.
if (g.IO.ConfigWindowsResizeFromEdges && !(g.IO.BackendFlags & ImGuiBackendFlags_HasMouseCursors))
g.IO.ConfigWindowsResizeFromEdges = false;
// Perform simple check: error if Docking or Viewport are enabled _exactly_ on frame 1 (instead of frame 0 or later), which is a common error leading to loss of .ini data.
if (g.FrameCount == 1 && (g.IO.ConfigFlags & ImGuiConfigFlags_DockingEnable) && (g.ConfigFlagsLastFrame & ImGuiConfigFlags_DockingEnable) == 0)
IM_ASSERT(0 && "Please set DockingEnable before the first call to NewFrame()! Otherwise you will lose your .ini settings!");
@@ -10859,7 +10896,7 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg, ImGu
window->DC.NavLayersActiveMaskNext |= (1 << window->DC.NavLayerCurrent);
if (g.NavId == id || g.NavAnyRequest)
if (g.NavWindow->RootWindowForNav == window->RootWindowForNav)
if (window == g.NavWindow || ((window->Flags | g.NavWindow->Flags) & ImGuiWindowFlags_NavFlattened))
if (window == g.NavWindow || ((window->ChildFlags | g.NavWindow->ChildFlags) & ImGuiChildFlags_NavFlattened))
NavProcessItem();
}
@@ -11937,8 +11974,8 @@ void ImGui::CloseCurrentPopup()
window->DC.NavHideHighlightOneFrame = true;
}
// Attention! BeginPopup() adds default flags which BeginPopupEx()!
bool ImGui::BeginPopupEx(ImGuiID id, ImGuiWindowFlags flags)
// Attention! BeginPopup() adds default flags when calling BeginPopupEx()!
bool ImGui::BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_window_flags)
{
ImGuiContext& g = *GImGui;
if (!IsPopupOpen(id, ImGuiPopupFlags_None))
@@ -11948,13 +11985,12 @@ bool ImGui::BeginPopupEx(ImGuiID id, ImGuiWindowFlags flags)
}
char name[20];
if (flags & ImGuiWindowFlags_ChildMenu)
if (extra_window_flags & ImGuiWindowFlags_ChildMenu)
ImFormatString(name, IM_ARRAYSIZE(name), "##Menu_%02d", g.BeginMenuDepth); // Recycle windows based on depth
else
ImFormatString(name, IM_ARRAYSIZE(name), "##Popup_%08x", id); // Not recycling, so we can close/open during the same frame
flags |= ImGuiWindowFlags_Popup | ImGuiWindowFlags_NoDocking;
bool is_open = Begin(name, NULL, flags);
bool is_open = Begin(name, NULL, extra_window_flags | ImGuiWindowFlags_Popup | ImGuiWindowFlags_NoDocking);
if (!is_open) // NB: Begin can return false when the popup is completely clipped (e.g. zero size display)
EndPopup();
@@ -12360,7 +12396,7 @@ static bool ImGui::NavScoreItem(ImGuiNavItemData* result)
// When entering through a NavFlattened border, we consider child window items as fully clipped for scoring
if (window->ParentWindow == g.NavWindow)
{
IM_ASSERT((window->Flags | g.NavWindow->Flags) & ImGuiWindowFlags_NavFlattened);
IM_ASSERT((window->ChildFlags | g.NavWindow->ChildFlags) & ImGuiChildFlags_NavFlattened);
if (!window->ClipRect.Overlaps(cand))
return false;
cand.ClipWithFull(window->ClipRect); // This allows the scored item to not overlap other candidates in the parent window
@@ -13070,6 +13106,8 @@ void ImGui::NavInitRequestApplyResult()
g.NavJustMovedToId = result->ID;
g.NavJustMovedToFocusScopeId = result->FocusScopeId;
g.NavJustMovedToKeyMods = 0;
g.NavJustMovedToIsTabbing = false;
g.NavJustMovedToHasSelectionData = (result->InFlags & ImGuiItemFlags_HasSelectionUserData) != 0;
}
// Apply result from previous navigation init request (will typically select the first item, unless SetItemDefaultFocus() has been called)
@@ -13326,6 +13364,9 @@ void ImGui::NavMoveRequestApplyResult()
g.NavJustMovedToId = result->ID;
g.NavJustMovedToFocusScopeId = result->FocusScopeId;
g.NavJustMovedToKeyMods = g.NavMoveKeyMods;
g.NavJustMovedToIsTabbing = (g.NavMoveFlags & ImGuiNavMoveFlags_IsTabbing) != 0;
g.NavJustMovedToHasSelectionData = (result->InFlags & ImGuiItemFlags_HasSelectionUserData) != 0;
//IMGUI_DEBUG_LOG_NAV("[nav] NavJustMovedFromFocusScopeId = 0x%08X, NavJustMovedToFocusScopeId = 0x%08X\n", g.NavJustMovedFromFocusScopeId, g.NavJustMovedToFocusScopeId);
}
// Apply new NavID/Focus
@@ -13832,6 +13873,8 @@ void ImGui::NavUpdateWindowingOverlay()
SetNextWindowPos(viewport->GetCenter(), ImGuiCond_Always, ImVec2(0.5f, 0.5f));
PushStyleVar(ImGuiStyleVar_WindowPadding, g.Style.WindowPadding * 2.0f);
Begin("###NavWindowingList", NULL, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings);
if (g.ContextName[0] != 0)
SeparatorText(g.ContextName);
for (int n = g.WindowsFocusOrder.Size - 1; n >= 0; n--)
{
ImGuiWindow* window = g.WindowsFocusOrder[n];
@@ -13957,9 +14000,13 @@ bool ImGui::BeginDragDropSource(ImGuiDragDropFlags flags)
}
else
{
// When ImGuiDragDropFlags_SourceExtern is set:
window = NULL;
source_id = ImHashStr("#SourceExtern");
source_drag_active = true;
mouse_button = g.IO.MouseDown[0] ? 0 : -1;
KeepAliveID(source_id);
SetActiveID(source_id, NULL);
}
IM_ASSERT(g.DragDropWithinTarget == false); // Can't nest BeginDragDropSource() and BeginDragDropTarget()
@@ -13971,7 +14018,8 @@ bool ImGui::BeginDragDropSource(ImGuiDragDropFlags flags)
{
IM_ASSERT(source_id != 0);
ClearDragDrop();
IMGUI_DEBUG_LOG_ACTIVEID("[dragdrop] BeginDragDropSource() DragDropActive = true, source_id = %08X\n", source_id);
IMGUI_DEBUG_LOG_ACTIVEID("[dragdrop] BeginDragDropSource() DragDropActive = true, source_id = 0x%08X%s\n",
source_id, (flags & ImGuiDragDropFlags_SourceExtern) ? " (EXTERN)" : "");
ImGuiPayload& payload = g.DragDropPayload;
payload.SourceId = source_id;
payload.SourceParentId = source_parent_id;
@@ -14030,7 +14078,7 @@ bool ImGui::SetDragDropPayload(const char* type, const void* data, size_t data_s
IM_ASSERT(strlen(type) < IM_ARRAYSIZE(payload.DataType) && "Payload type can be at most 32 characters long");
IM_ASSERT((data != NULL && data_size > 0) || (data == NULL && data_size == 0));
IM_ASSERT(cond == ImGuiCond_Always || cond == ImGuiCond_Once);
IM_ASSERT(payload.SourceId != 0); // Not called between BeginDragDropSource() and EndDragDropSource()
IM_ASSERT(payload.SourceId != 0); // Not called between BeginDragDropSource() and EndDragDropSource()
if (cond == ImGuiCond_Always || payload.DataFrameCount == -1)
{
@@ -14157,11 +14205,15 @@ const ImGuiPayload* ImGui::AcceptDragDropPayload(const char* type, ImGuiDragDrop
RenderDragDropTargetRect(r, g.DragDropTargetClipRect);
g.DragDropAcceptFrameCount = g.FrameCount;
payload.Delivery = was_accepted_previously && !IsMouseDown(g.DragDropMouseButton); // For extern drag sources affecting OS window focus, it's easier to just test !IsMouseDown() instead of IsMouseReleased()
if ((g.DragDropSourceFlags & ImGuiDragDropFlags_SourceExtern) && g.DragDropMouseButton == -1)
payload.Delivery = was_accepted_previously && (g.DragDropSourceFrameCount < g.FrameCount);
else
payload.Delivery = was_accepted_previously && !IsMouseDown(g.DragDropMouseButton); // For extern drag sources affecting OS window focus, it's easier to just test !IsMouseDown() instead of IsMouseReleased()
if (!payload.Delivery && !(flags & ImGuiDragDropFlags_AcceptBeforeDelivery))
return NULL;
//IMGUI_DEBUG_LOG("AcceptDragDropPayload(): %08X: return payload\n", g.DragDropTargetId);
if (payload.Delivery)
IMGUI_DEBUG_LOG_ACTIVEID("[dragdrop] AcceptDragDropPayload(): 0x%08X: payload delivery\n", g.DragDropTargetId);
return &payload;
}
@@ -17732,6 +17784,7 @@ static void ImGui::DockNodeUpdateTabBar(ImGuiDockNode* node, ImGuiWindow* host_w
// Begin tab bar
ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_Reorderable | ImGuiTabBarFlags_AutoSelectNewTabs; // | ImGuiTabBarFlags_NoTabListScrollingButtons);
tab_bar_flags |= ImGuiTabBarFlags_SaveSettings | ImGuiTabBarFlags_DockNode;// | ImGuiTabBarFlags_FittingPolicyScroll;
tab_bar_flags |= ImGuiTabBarFlags_DrawSelectedOverline;
if (!host_window->Collapsed && is_focused)
tab_bar_flags |= ImGuiTabBarFlags_IsFocused;
tab_bar->ID = GetID("#TabBar");
@@ -18215,7 +18268,7 @@ static void ImGui::DockNodePreviewDockRender(ImGuiWindow* host_window, ImGuiDock
ImRect tab_bb(tab_pos.x, tab_pos.y, tab_pos.x + tab_size.x, tab_pos.y + tab_size.y);
tab_pos.x += tab_size.x + g.Style.ItemInnerSpacing.x;
const ImU32 overlay_col_text = GetColorU32(payload_window->DockStyle.Colors[ImGuiWindowDockStyleCol_Text]);
const ImU32 overlay_col_tabs = GetColorU32(payload_window->DockStyle.Colors[ImGuiWindowDockStyleCol_TabActive]);
const ImU32 overlay_col_tabs = GetColorU32(payload_window->DockStyle.Colors[ImGuiWindowDockStyleCol_TabSelected]);
PushStyleColor(ImGuiCol_Text, overlay_col_text);
for (int overlay_n = 0; overlay_n < overlay_draw_lists_count; overlay_n++)
{
@@ -19474,7 +19527,8 @@ void ImGui::BeginDockableDragDropSource(ImGuiWindow* window)
window = window->RootWindowDockTree;
IM_ASSERT((window->Flags & ImGuiWindowFlags_NoDocking) == 0);
bool is_drag_docking = (g.IO.ConfigDockingWithShift) || ImRect(0, 0, window->SizeFull.x, GetFrameHeight()).Contains(g.ActiveIdClickOffset); // FIXME-DOCKING: Need to make this stateful and explicit
if (is_drag_docking && BeginDragDropSource(ImGuiDragDropFlags_SourceNoPreviewTooltip | ImGuiDragDropFlags_SourceNoHoldToOpenOthers | ImGuiDragDropFlags_SourceAutoExpirePayload))
ImGuiDragDropFlags drag_drop_flags = ImGuiDragDropFlags_SourceNoPreviewTooltip | ImGuiDragDropFlags_SourceNoHoldToOpenOthers | ImGuiDragDropFlags_PayloadAutoExpire | ImGuiDragDropFlags_PayloadNoCrossContext | ImGuiDragDropFlags_PayloadNoCrossProcess;
if (is_drag_docking && BeginDragDropSource(drag_drop_flags))
{
SetDragDropPayload(IMGUI_PAYLOAD_TYPE_WINDOW, &window, sizeof(window));
EndDragDropSource();
@@ -20221,6 +20275,11 @@ void ImGui::ShowMetricsWindow(bool* p_open)
// Basic info
Text("Dear ImGui %s", GetVersion());
if (g.ContextName[0] != 0)
{
SameLine();
Text("(Context Name: \"%s\")", g.ContextName);
}
Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate);
Text("%d vertices, %d indices (%d triangles)", io.MetricsRenderVertices, io.MetricsRenderIndices, io.MetricsRenderIndices / 3);
Text("%d visible windows, %d current allocations", io.MetricsRenderWindows, g.DebugAllocInfo.TotalAllocCount - g.DebugAllocInfo.TotalFreeCount);
@@ -21265,8 +21324,11 @@ void ImGui::DebugNodeStorage(ImGuiStorage* storage, const char* label)
{
if (!TreeNode(label, "%s: %d entries, %d bytes", label, storage->Data.Size, storage->Data.size_in_bytes()))
return;
for (const ImGuiStorage::ImGuiStoragePair& p : storage->Data)
for (const ImGuiStoragePair& p : storage->Data)
{
BulletText("Key 0x%08X Value { i: %d }", p.key, p.val_i); // Important: we currently don't store a type, real value may not be integer.
DebugLocateItemOnHover(p.key);
}
TreePop();
}
@@ -21475,7 +21537,10 @@ void ImGui::DebugLogV(const char* fmt, va_list args)
{
ImGuiContext& g = *GImGui;
const int old_size = g.DebugLogBuf.size();
g.DebugLogBuf.appendf("[%05d] ", g.FrameCount);
if (g.ContextName[0] != 0)
g.DebugLogBuf.appendf("[%s] [%05d] ", g.ContextName, g.FrameCount);
else
g.DebugLogBuf.appendf("[%05d] ", g.FrameCount);
g.DebugLogBuf.appendfv(fmt, args);
g.DebugLogIndex.append(g.DebugLogBuf.c_str(), old_size, g.DebugLogBuf.size());
if (g.DebugLogFlags & ImGuiDebugLogFlags_OutputToTTY)

View File

@@ -1,4 +1,4 @@
// dear imgui, v1.90.8
// dear imgui, v1.90.9
// (demo code)
// Help:
@@ -479,19 +479,25 @@ void ImGui::ShowDemoWindow(bool* p_open)
ImGui::CheckboxFlags("io.ConfigFlags: NavEnableSetMousePos", &io.ConfigFlags, ImGuiConfigFlags_NavEnableSetMousePos);
ImGui::SameLine(); HelpMarker("Instruct navigation to move the mouse cursor. See comment for ImGuiConfigFlags_NavEnableSetMousePos.");
ImGui::CheckboxFlags("io.ConfigFlags: NoMouse", &io.ConfigFlags, ImGuiConfigFlags_NoMouse);
ImGui::SameLine(); HelpMarker("Instruct dear imgui to disable mouse inputs and interactions.");
// The "NoMouse" option can get us stuck with a disabled mouse! Let's provide an alternative way to fix it:
if (io.ConfigFlags & ImGuiConfigFlags_NoMouse)
{
// The "NoMouse" option can get us stuck with a disabled mouse! Let's provide an alternative way to fix it:
if (fmodf((float)ImGui::GetTime(), 0.40f) < 0.20f)
{
ImGui::SameLine();
ImGui::Text("<<PRESS SPACE TO DISABLE>>");
}
if (ImGui::IsKeyPressed(ImGuiKey_Space))
// Prevent both being checked
if (ImGui::IsKeyPressed(ImGuiKey_Space) || (io.ConfigFlags & ImGuiConfigFlags_NoKeyboard))
io.ConfigFlags &= ~ImGuiConfigFlags_NoMouse;
}
ImGui::CheckboxFlags("io.ConfigFlags: NoMouseCursorChange", &io.ConfigFlags, ImGuiConfigFlags_NoMouseCursorChange);
ImGui::CheckboxFlags("io.ConfigFlags: NoMouseCursorChange", &io.ConfigFlags, ImGuiConfigFlags_NoMouseCursorChange);
ImGui::SameLine(); HelpMarker("Instruct backend to not alter mouse cursor shape and visibility.");
ImGui::CheckboxFlags("io.ConfigFlags: NoKeyboard", &io.ConfigFlags, ImGuiConfigFlags_NoKeyboard);
ImGui::SameLine(); HelpMarker("Instruct dear imgui to disable keyboard inputs and interactions.");
ImGui::Checkbox("io.ConfigInputTrickleEventQueue", &io.ConfigInputTrickleEventQueue);
ImGui::SameLine(); HelpMarker("Enable input queue trickling: some types of events submitted during the same frame (e.g. button down + up) will be spread over multiple frames, improving interactions with low framerates.");
@@ -774,18 +780,19 @@ static void ShowDemoWindowWidgets()
{
IMGUI_DEMO_MARKER("Widgets/Basic/DragInt, DragFloat");
static int i1 = 50, i2 = 42;
static int i1 = 50, i2 = 42, i3 = 128;
ImGui::DragInt("drag int", &i1, 1);
ImGui::SameLine(); HelpMarker(
"Click and drag to edit value.\n"
"Hold SHIFT/ALT for faster/slower edit.\n"
"Double-click or CTRL+click to input value.");
ImGui::DragInt("drag int 0..100", &i2, 1, 0, 100, "%d%%", ImGuiSliderFlags_AlwaysClamp);
ImGui::DragInt("drag int wrap 100..200", &i3, 1, 100, 200, "%d", ImGuiSliderFlags_WrapAround);
static float f1 = 1.00f, f2 = 0.0067f;
ImGui::DragFloat("drag float", &f1, 0.005f);
ImGui::DragFloat("drag small float", &f2, 0.0001f, 0.0f, 0.0f, "%.06f ns");
//ImGui::DragFloat("drag wrap -1..1", &f3, 0.005f, -1.0f, 1.0f, NULL, ImGuiSliderFlags_WrapAround);
}
ImGui::SeparatorText("Sliders");
@@ -942,12 +949,11 @@ static void ShowDemoWindowWidgets()
// Using ImGuiHoveredFlags_ForTooltip will pull flags from 'style.HoverFlagsForTooltipMouse' or 'style.HoverFlagsForTooltipNav',
// which default value include the ImGuiHoveredFlags_AllowWhenDisabled flag.
// As a result, Set
ImGui::BeginDisabled();
ImGui::Button("Disabled item", sz);
ImGui::EndDisabled();
if (ImGui::IsItemHovered(ImGuiHoveredFlags_ForTooltip))
ImGui::SetTooltip("I am a a tooltip for a disabled item.");
ImGui::EndDisabled();
ImGui::TreePop();
}
@@ -1791,6 +1797,7 @@ static void ShowDemoWindowWidgets()
ImGui::CheckboxFlags("ImGuiTabBarFlags_AutoSelectNewTabs", &tab_bar_flags, ImGuiTabBarFlags_AutoSelectNewTabs);
ImGui::CheckboxFlags("ImGuiTabBarFlags_TabListPopupButton", &tab_bar_flags, ImGuiTabBarFlags_TabListPopupButton);
ImGui::CheckboxFlags("ImGuiTabBarFlags_NoCloseWithMiddleMouseButton", &tab_bar_flags, ImGuiTabBarFlags_NoCloseWithMiddleMouseButton);
ImGui::CheckboxFlags("ImGuiTabBarFlags_DrawSelectedOverline", &tab_bar_flags, ImGuiTabBarFlags_DrawSelectedOverline);
if ((tab_bar_flags & ImGuiTabBarFlags_FittingPolicyMask_) == 0)
tab_bar_flags |= ImGuiTabBarFlags_FittingPolicyDefault_;
if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyResizeDown", &tab_bar_flags, ImGuiTabBarFlags_FittingPolicyResizeDown))
@@ -1799,11 +1806,13 @@ static void ShowDemoWindowWidgets()
tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyScroll);
// Tab Bar
ImGui::AlignTextToFramePadding();
ImGui::Text("Opened:");
const char* names[4] = { "Artichoke", "Beetroot", "Celery", "Daikon" };
static bool opened[4] = { true, true, true, true }; // Persistent user state
for (int n = 0; n < IM_ARRAYSIZE(opened); n++)
{
if (n > 0) { ImGui::SameLine(); }
ImGui::SameLine();
ImGui::Checkbox(names[n], &opened[n]);
}
@@ -2196,6 +2205,8 @@ static void ShowDemoWindowWidgets()
ImGui::SameLine(); HelpMarker("Disable rounding underlying value to match precision of the format string (e.g. %.3f values are rounded to those 3 digits).");
ImGui::CheckboxFlags("ImGuiSliderFlags_NoInput", &flags, ImGuiSliderFlags_NoInput);
ImGui::SameLine(); HelpMarker("Disable CTRL+Click or Enter key allowing to input text directly into the widget.");
ImGui::CheckboxFlags("ImGuiSliderFlags_WrapAround", &flags, ImGuiSliderFlags_WrapAround);
ImGui::SameLine(); HelpMarker("Enable wrapping around from max to min and from min to max (only supported by DragXXX() functions)");
// Drags
static float drag_f = 0.5f;
@@ -2210,9 +2221,10 @@ static void ShowDemoWindowWidgets()
// Sliders
static float slider_f = 0.5f;
static int slider_i = 50;
const ImGuiSliderFlags flags_for_sliders = flags & ~ImGuiSliderFlags_WrapAround;
ImGui::Text("Underlying float value: %f", slider_f);
ImGui::SliderFloat("SliderFloat (0 -> 1)", &slider_f, 0.0f, 1.0f, "%.3f", flags);
ImGui::SliderInt("SliderInt (0 -> 100)", &slider_i, 0, 100, "%d", flags);
ImGui::SliderFloat("SliderFloat (0 -> 1)", &slider_f, 0.0f, 1.0f, "%.3f", flags_for_sliders);
ImGui::SliderInt("SliderInt (0 -> 100)", &slider_i, 0, 100, "%d", flags_for_sliders);
ImGui::TreePop();
}
@@ -6941,7 +6953,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref)
"Right-click to open edit options menu.");
ImGui::SetNextWindowSizeConstraints(ImVec2(0.0f, ImGui::GetTextLineHeightWithSpacing() * 10), ImVec2(FLT_MAX, FLT_MAX));
ImGui::BeginChild("##colors", ImVec2(0, 0), ImGuiChildFlags_Border, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar | ImGuiWindowFlags_NavFlattened);
ImGui::BeginChild("##colors", ImVec2(0, 0), ImGuiChildFlags_Border | ImGuiChildFlags_NavFlattened, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar);
ImGui::PushItemWidth(ImGui::GetFontSize() * -12);
for (int i = 0; i < ImGuiCol_COUNT; i++)
{
@@ -7022,10 +7034,10 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref)
ImGui::SetNextWindowPos(ImGui::GetCursorScreenPos());
if (show_samples && ImGui::BeginTooltip())
{
ImGui::TextUnformatted("(R = radius, N = number of segments)");
ImGui::TextUnformatted("(R = radius, N = approx number of segments)");
ImGui::Spacing();
ImDrawList* draw_list = ImGui::GetWindowDrawList();
const float min_widget_width = ImGui::CalcTextSize("N: MMM\nR: MMM").x;
const float min_widget_width = ImGui::CalcTextSize("R: MMM\nN: MMM").x;
for (int n = 0; n < 8; n++)
{
const float RAD_MIN = 5.0f;
@@ -7034,6 +7046,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref)
ImGui::BeginGroup();
// N is not always exact here due to how PathArcTo() function work internally
ImGui::Text("R: %.f\nN: %d", rad, draw_list->_CalcCircleAutoSegmentCount(rad));
const float canvas_width = IM_MAX(min_widget_width, rad * 2.0f);
@@ -7357,7 +7370,7 @@ struct ExampleAppConsole
// Reserve enough left-over height for 1 separator + 1 input text
const float footer_height_to_reserve = ImGui::GetStyle().ItemSpacing.y + ImGui::GetFrameHeightWithSpacing();
if (ImGui::BeginChild("ScrollingRegion", ImVec2(0, -footer_height_to_reserve), ImGuiChildFlags_None, ImGuiWindowFlags_HorizontalScrollbar | ImGuiWindowFlags_NavFlattened))
if (ImGui::BeginChild("ScrollingRegion", ImVec2(0, -footer_height_to_reserve), ImGuiChildFlags_NavFlattened, ImGuiWindowFlags_HorizontalScrollbar))
{
if (ImGui::BeginPopupContextWindow())
{
@@ -9044,6 +9057,7 @@ void ShowExampleAppDocuments(bool* p_open)
if (opt_target == Target_Tab)
{
ImGuiTabBarFlags tab_bar_flags = (opt_fitting_flags) | (opt_reorderable ? ImGuiTabBarFlags_Reorderable : 0);
tab_bar_flags |= ImGuiTabBarFlags_DrawSelectedOverline;
if (ImGui::BeginTabBar("##tabs", tab_bar_flags))
{
if (opt_reorderable)

View File

@@ -1,4 +1,4 @@
// dear imgui, v1.90.8
// dear imgui, v1.90.9
// (drawing and font code)
/*
@@ -213,11 +213,13 @@ void ImGui::StyleColorsDark(ImGuiStyle* dst)
colors[ImGuiCol_ResizeGrip] = ImVec4(0.26f, 0.59f, 0.98f, 0.20f);
colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f);
colors[ImGuiCol_ResizeGripActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f);
colors[ImGuiCol_Tab] = ImLerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.80f);
colors[ImGuiCol_TabHovered] = colors[ImGuiCol_HeaderHovered];
colors[ImGuiCol_TabActive] = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f);
colors[ImGuiCol_TabUnfocused] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f);
colors[ImGuiCol_TabUnfocusedActive] = ImLerp(colors[ImGuiCol_TabActive], colors[ImGuiCol_TitleBg], 0.40f);
colors[ImGuiCol_Tab] = ImLerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.80f);
colors[ImGuiCol_TabSelected] = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f);
colors[ImGuiCol_TabSelectedOverline] = colors[ImGuiCol_HeaderActive];
colors[ImGuiCol_TabDimmed] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f);
colors[ImGuiCol_TabDimmedSelected] = ImLerp(colors[ImGuiCol_TabSelected], colors[ImGuiCol_TitleBg], 0.40f);
colors[ImGuiCol_TabDimmedSelectedOverline] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f);
colors[ImGuiCol_DockingPreview] = colors[ImGuiCol_HeaderActive] * ImVec4(1.0f, 1.0f, 1.0f, 0.7f);
colors[ImGuiCol_DockingEmptyBg] = ImVec4(0.20f, 0.20f, 0.20f, 1.00f);
colors[ImGuiCol_PlotLines] = ImVec4(0.61f, 0.61f, 0.61f, 1.00f);
@@ -276,11 +278,13 @@ void ImGui::StyleColorsClassic(ImGuiStyle* dst)
colors[ImGuiCol_ResizeGrip] = ImVec4(1.00f, 1.00f, 1.00f, 0.10f);
colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.78f, 0.82f, 1.00f, 0.60f);
colors[ImGuiCol_ResizeGripActive] = ImVec4(0.78f, 0.82f, 1.00f, 0.90f);
colors[ImGuiCol_Tab] = ImLerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.80f);
colors[ImGuiCol_TabHovered] = colors[ImGuiCol_HeaderHovered];
colors[ImGuiCol_TabActive] = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f);
colors[ImGuiCol_TabUnfocused] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f);
colors[ImGuiCol_TabUnfocusedActive] = ImLerp(colors[ImGuiCol_TabActive], colors[ImGuiCol_TitleBg], 0.40f);
colors[ImGuiCol_Tab] = ImLerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.80f);
colors[ImGuiCol_TabSelected] = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f);
colors[ImGuiCol_TabSelectedOverline] = colors[ImGuiCol_HeaderActive];
colors[ImGuiCol_TabDimmed] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f);
colors[ImGuiCol_TabDimmedSelected] = ImLerp(colors[ImGuiCol_TabSelected], colors[ImGuiCol_TitleBg], 0.40f);
colors[ImGuiCol_TabDimmedSelectedOverline] = colors[ImGuiCol_HeaderActive];
colors[ImGuiCol_DockingPreview] = colors[ImGuiCol_Header] * ImVec4(1.0f, 1.0f, 1.0f, 0.7f);
colors[ImGuiCol_DockingEmptyBg] = ImVec4(0.20f, 0.20f, 0.20f, 1.00f);
colors[ImGuiCol_PlotLines] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
@@ -340,11 +344,13 @@ void ImGui::StyleColorsLight(ImGuiStyle* dst)
colors[ImGuiCol_ResizeGrip] = ImVec4(0.35f, 0.35f, 0.35f, 0.17f);
colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f);
colors[ImGuiCol_ResizeGripActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f);
colors[ImGuiCol_Tab] = ImLerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.90f);
colors[ImGuiCol_TabHovered] = colors[ImGuiCol_HeaderHovered];
colors[ImGuiCol_TabActive] = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f);
colors[ImGuiCol_TabUnfocused] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f);
colors[ImGuiCol_TabUnfocusedActive] = ImLerp(colors[ImGuiCol_TabActive], colors[ImGuiCol_TitleBg], 0.40f);
colors[ImGuiCol_Tab] = ImLerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.90f);
colors[ImGuiCol_TabSelected] = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f);
colors[ImGuiCol_TabSelectedOverline] = colors[ImGuiCol_HeaderActive];
colors[ImGuiCol_TabDimmed] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f);
colors[ImGuiCol_TabDimmedSelected] = ImLerp(colors[ImGuiCol_TabSelected], colors[ImGuiCol_TitleBg], 0.40f);
colors[ImGuiCol_TabDimmedSelectedOverline] = ImVec4(0.26f, 0.59f, 1.00f, 1.00f);
colors[ImGuiCol_DockingPreview] = colors[ImGuiCol_Header] * ImVec4(1.0f, 1.0f, 1.0f, 0.7f);
colors[ImGuiCol_DockingEmptyBg] = ImVec4(0.20f, 0.20f, 0.20f, 1.00f);
colors[ImGuiCol_PlotLines] = ImVec4(0.39f, 0.39f, 0.39f, 1.00f);

View File

@@ -1,4 +1,4 @@
// dear imgui, v1.90.8
// dear imgui, v1.90.9
// (tables and columns code)
/*

View File

@@ -1,4 +1,4 @@
// dear imgui, v1.90.8
// dear imgui, v1.90.9
// (widgets code)
/*
@@ -1138,7 +1138,8 @@ bool ImGui::Checkbox(const char* label, bool* v)
const ImVec2 pos = window->DC.CursorPos;
const ImRect total_bb(pos, pos + ImVec2(square_sz + (label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f), label_size.y + style.FramePadding.y * 2.0f));
ItemSize(total_bb, style.FramePadding.y);
if (!ItemAdd(total_bb, id))
const bool is_visible = ItemAdd(total_bb, id);
if (!is_visible)
{
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Checkable | (*v ? ImGuiItemStatusFlags_Checked : 0));
return false;
@@ -1153,27 +1154,29 @@ bool ImGui::Checkbox(const char* label, bool* v)
}
const ImRect check_bb(pos, pos + ImVec2(square_sz, square_sz));
RenderNavHighlight(total_bb, id);
RenderFrame(check_bb.Min, check_bb.Max, GetColorU32((held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), true, style.FrameRounding);
ImU32 check_col = GetColorU32(ImGuiCol_CheckMark);
bool mixed_value = (g.LastItemData.InFlags & ImGuiItemFlags_MixedValue) != 0;
if (mixed_value)
const bool mixed_value = (g.LastItemData.InFlags & ImGuiItemFlags_MixedValue) != 0;
if (is_visible)
{
// Undocumented tristate/mixed/indeterminate checkbox (#2644)
// This may seem awkwardly designed because the aim is to make ImGuiItemFlags_MixedValue supported by all widgets (not just checkbox)
ImVec2 pad(ImMax(1.0f, IM_TRUNC(square_sz / 3.6f)), ImMax(1.0f, IM_TRUNC(square_sz / 3.6f)));
window->DrawList->AddRectFilled(check_bb.Min + pad, check_bb.Max - pad, check_col, style.FrameRounding);
RenderNavHighlight(total_bb, id);
RenderFrame(check_bb.Min, check_bb.Max, GetColorU32((held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), true, style.FrameRounding);
ImU32 check_col = GetColorU32(ImGuiCol_CheckMark);
if (mixed_value)
{
// Undocumented tristate/mixed/indeterminate checkbox (#2644)
// This may seem awkwardly designed because the aim is to make ImGuiItemFlags_MixedValue supported by all widgets (not just checkbox)
ImVec2 pad(ImMax(1.0f, IM_TRUNC(square_sz / 3.6f)), ImMax(1.0f, IM_TRUNC(square_sz / 3.6f)));
window->DrawList->AddRectFilled(check_bb.Min + pad, check_bb.Max - pad, check_col, style.FrameRounding);
}
else if (*v)
{
const float pad = ImMax(1.0f, IM_TRUNC(square_sz / 6.0f));
RenderCheckMark(window->DrawList, check_bb.Min + ImVec2(pad, pad), check_col, square_sz - pad * 2.0f);
}
}
else if (*v)
{
const float pad = ImMax(1.0f, IM_TRUNC(square_sz / 6.0f));
RenderCheckMark(window->DrawList, check_bb.Min + ImVec2(pad, pad), check_col, square_sz - pad * 2.0f);
}
ImVec2 label_pos = ImVec2(check_bb.Max.x + style.ItemInnerSpacing.x, check_bb.Min.y + style.FramePadding.y);
const ImVec2 label_pos = ImVec2(check_bb.Max.x + style.ItemInnerSpacing.x, check_bb.Min.y + style.FramePadding.y);
if (g.LogEnabled)
LogRenderedText(&label_pos, mixed_value ? "[~]" : *v ? "[x]" : "[ ]");
if (label_size.x > 0.0f)
if (is_visible && label_size.x > 0.0f)
RenderText(label_pos, label);
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Checkable | (*v ? ImGuiItemStatusFlags_Checked : 0));
@@ -2311,12 +2314,13 @@ bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const
{
ImGuiContext& g = *GImGui;
const ImGuiAxis axis = (flags & ImGuiSliderFlags_Vertical) ? ImGuiAxis_Y : ImGuiAxis_X;
const bool is_clamped = (v_min < v_max);
const bool is_bounded = (v_min < v_max);
const bool is_wrapped = is_bounded && (flags & ImGuiSliderFlags_WrapAround);
const bool is_logarithmic = (flags & ImGuiSliderFlags_Logarithmic) != 0;
const bool is_floating_point = (data_type == ImGuiDataType_Float) || (data_type == ImGuiDataType_Double);
// Default tweak speed
if (v_speed == 0.0f && is_clamped && (v_max - v_min < FLT_MAX))
if (v_speed == 0.0f && is_bounded && (v_max - v_min < FLT_MAX))
v_speed = (float)((v_max - v_min) * g.DragSpeedDefaultRatio);
// Inputs accumulates into g.DragCurrentAccum, which is flushed into the current value as soon as it makes a difference with our precision settings
@@ -2350,8 +2354,8 @@ bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const
// Clear current value on activation
// Avoid altering values and clamping when we are _already_ past the limits and heading in the same direction, so e.g. if range is 0..255, current value is 300 and we are pushing to the right side, keep the 300.
bool is_just_activated = g.ActiveIdIsJustActivated;
bool is_already_past_limits_and_pushing_outward = is_clamped && ((*v >= v_max && adjust_delta > 0.0f) || (*v <= v_min && adjust_delta < 0.0f));
const bool is_just_activated = g.ActiveIdIsJustActivated;
const bool is_already_past_limits_and_pushing_outward = is_bounded && !is_wrapped && ((*v >= v_max && adjust_delta > 0.0f) || (*v <= v_min && adjust_delta < 0.0f));
if (is_just_activated || is_already_past_limits_and_pushing_outward)
{
g.DragCurrentAccum = 0.0f;
@@ -2409,13 +2413,24 @@ bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const
if (v_cur == (TYPE)-0)
v_cur = (TYPE)0;
// Clamp values (+ handle overflow/wrap-around for integer types)
if (*v != v_cur && is_clamped)
if (*v != v_cur && is_bounded)
{
if (v_cur < v_min || (v_cur > *v && adjust_delta < 0.0f && !is_floating_point))
v_cur = v_min;
if (v_cur > v_max || (v_cur < *v && adjust_delta > 0.0f && !is_floating_point))
v_cur = v_max;
if (is_wrapped)
{
// Wrap values
if (v_cur < v_min)
v_cur += v_max - v_min + (is_floating_point ? 0 : 1);
if (v_cur > v_max)
v_cur -= v_max - v_min + (is_floating_point ? 0 : 1);
}
else
{
// Clamp values + handle overflow/wrap-around for integer types.
if (v_cur < v_min || (v_cur > *v && adjust_delta < 0.0f && !is_floating_point))
v_cur = v_min;
if (v_cur > v_max || (v_cur < *v && adjust_delta > 0.0f && !is_floating_point))
v_cur = v_max;
}
}
// Apply result
@@ -2428,7 +2443,7 @@ bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const
bool ImGui::DragBehavior(ImGuiID id, ImGuiDataType data_type, void* p_v, float v_speed, const void* p_min, const void* p_max, const char* format, ImGuiSliderFlags flags)
{
// Read imgui.cpp "API BREAKING CHANGES" section for 1.78 if you hit this assert.
IM_ASSERT((flags == 1 || (flags & ImGuiSliderFlags_InvalidMask_) == 0) && "Invalid ImGuiSliderFlags flags! Has the 'float power' argument been mistakenly cast to flags? Call function with ImGuiSliderFlags_Logarithmic flags instead.");
IM_ASSERT((flags == 1 || (flags & ImGuiSliderFlags_InvalidMask_) == 0) && "Invalid ImGuiSliderFlags flags! Has the legacy 'float power' argument been mistakenly cast to flags? Call function with ImGuiSliderFlags_Logarithmic flags instead.");
ImGuiContext& g = *GImGui;
if (g.ActiveId == id)
@@ -3021,7 +3036,8 @@ bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_typ
bool ImGui::SliderBehavior(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, void* p_v, const void* p_min, const void* p_max, const char* format, ImGuiSliderFlags flags, ImRect* out_grab_bb)
{
// Read imgui.cpp "API BREAKING CHANGES" section for 1.78 if you hit this assert.
IM_ASSERT((flags == 1 || (flags & ImGuiSliderFlags_InvalidMask_) == 0) && "Invalid ImGuiSliderFlags flag! Has the 'float power' argument been mistakenly cast to flags? Call function with ImGuiSliderFlags_Logarithmic flags instead.");
IM_ASSERT((flags == 1 || (flags & ImGuiSliderFlags_InvalidMask_) == 0) && "Invalid ImGuiSliderFlags flags! Has the legacy 'float power' argument been mistakenly cast to flags? Call function with ImGuiSliderFlags_Logarithmic flags instead.");
IM_ASSERT((flags & ImGuiSliderFlags_WrapAround) == 0); // Not supported by SliderXXX(), only by DragXXX()
switch (data_type)
{
@@ -7435,9 +7451,8 @@ bool ImGui::BeginViewportSideBar(const char* name, ImGuiViewport* viewport_p, Im
}
window_flags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoDocking;
SetNextWindowViewport(viewport->ID); // Enforce viewport so we don't create our own viewport when ImGuiConfigFlags_ViewportsNoMerge is set.
// Create window
SetNextWindowViewport(viewport->ID); // Enforce viewport so we don't create our own viewport when ImGuiConfigFlags_ViewportsNoMerge is set.
PushStyleColor(ImGuiCol_WindowShadow, ImVec4(0, 0, 0, 0));
PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
PushStyleVar(ImGuiStyleVar_WindowMinSize, ImVec2(0, 0)); // Lift normal size constraint
@@ -7938,7 +7953,9 @@ bool ImGui::BeginTabBar(const char* str_id, ImGuiTabBarFlags flags)
tab_bar->ID = id;
tab_bar->SeparatorMinX = tab_bar->BarRect.Min.x - IM_TRUNC(window->WindowPadding.x * 0.5f);
tab_bar->SeparatorMaxX = tab_bar->BarRect.Max.x + IM_TRUNC(window->WindowPadding.x * 0.5f);
return BeginTabBarEx(tab_bar, tab_bar_bb, flags | ImGuiTabBarFlags_IsFocused);
//if (g.NavWindow && IsWindowChildOf(g.NavWindow, window, false, false))
flags |= ImGuiTabBarFlags_IsFocused;
return BeginTabBarEx(tab_bar, tab_bar_bb, flags);
}
bool ImGui::BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& tab_bar_bb, ImGuiTabBarFlags flags)
@@ -7993,7 +8010,7 @@ bool ImGui::BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& tab_bar_bb, ImG
// Draw separator
// (it would be misleading to draw this in EndTabBar() suggesting that it may be drawn over tabs, as tab bar are appendable)
const ImU32 col = GetColorU32((flags & ImGuiTabBarFlags_IsFocused) ? ImGuiCol_TabActive : ImGuiCol_TabUnfocusedActive);
const ImU32 col = GetColorU32((flags & ImGuiTabBarFlags_IsFocused) ? ImGuiCol_TabSelected : ImGuiCol_TabDimmedSelected);
if (g.Style.TabBarBorderSize > 0.0f)
{
const float y = tab_bar->BarRect.Max.y;
@@ -8949,8 +8966,16 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open,
// Render tab shape
ImDrawList* display_draw_list = window->DrawList;
const ImU32 tab_col = GetColorU32((held || hovered) ? ImGuiCol_TabHovered : tab_contents_visible ? (tab_bar_focused ? ImGuiCol_TabActive : ImGuiCol_TabUnfocusedActive) : (tab_bar_focused ? ImGuiCol_Tab : ImGuiCol_TabUnfocused));
const ImU32 tab_col = GetColorU32((held || hovered) ? ImGuiCol_TabHovered : tab_contents_visible ? (tab_bar_focused ? ImGuiCol_TabSelected : ImGuiCol_TabDimmedSelected) : (tab_bar_focused ? ImGuiCol_Tab : ImGuiCol_TabDimmed));
TabItemBackground(display_draw_list, bb, flags, tab_col);
if (tab_contents_visible && (tab_bar->Flags & ImGuiTabBarFlags_DrawSelectedOverline))
{
float x_offset = IM_TRUNC(0.4f * style.TabRounding);
if (x_offset < 2.0f * g.CurrentDpiScale)
x_offset = 0.0f;
float y_offset = 1.0f * g.CurrentDpiScale;
display_draw_list->AddLine(bb.GetTL() + ImVec2(x_offset, y_offset), bb.GetTR() + ImVec2(-x_offset, y_offset), GetColorU32(tab_bar_focused ? ImGuiCol_TabSelectedOverline : ImGuiCol_TabDimmedSelectedOverline), 2.0f * g.CurrentDpiScale);
}
RenderNavHighlight(bb, id);
// Select with right mouse button. This is so the common idiom for context menu automatically highlight the current widget.

View File

@@ -357,7 +357,7 @@ namespace
case FT_PIXEL_MODE_BGRA:
{
// FIXME: Converting pre-multiplied alpha to straight. Doesn't smell good.
#define DE_MULTIPLY(color, alpha) (ImU32)(255.0f * (float)color / (float)alpha + 0.5f)
#define DE_MULTIPLY(color, alpha) ImMin((ImU32)(255.0f * (float)color / (float)(alpha + FLT_MIN) + 0.5f), 255u)
if (multiply_table == nullptr)
{
for (uint32_t y = 0; y < h; y++, src += src_pitch, dst += dst_pitch)
@@ -671,8 +671,8 @@ bool ImFontAtlasBuildWithFreeTypeEx(FT_Library ft_library, ImFontAtlas* atlas, u
{
ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i];
// IMHEX PATCH BEGIN
if (src_tmp.GlyphsCount == 0)
continue;
// if (src_tmp.GlyphsCount == 0)
// continue;
// IMHEX PATCH END
// When merging fonts with MergeMode=true:

View File

@@ -60,7 +60,7 @@ target_compile_definitions(main PRIVATE IMHEX_PROJECT_NAME="${PROJECT_NAME}")
target_link_libraries(main PRIVATE libromfs-imhex libimhex libwolv ${LIBBACKTRACE_LIBRARIES} LLVMDemangle)
if (WIN32)
target_link_libraries(main PRIVATE usp10 wsock32 ws2_32 Dwmapi.lib)
target_link_libraries(main PRIVATE usp10 wsock32 ws2_32 Dwmapi.lib Winmm.lib)
else ()
target_link_libraries(main PRIVATE pthread)
endif ()

View File

@@ -31,14 +31,30 @@ namespace hex::init {
return true;
}
static bool isSubPathWritable(std::fs::path path) {
for (u32 i = 0; i < 128; i++) {
if (hex::fs::isPathWritable(path))
return true;
auto parentPath = path.parent_path();
if (parentPath == path)
break;
path = std::move(parentPath);
}
return false;
}
bool createDirectories() {
bool result = true;
// Try to create all default directories
for (auto path : paths::All) {
for (auto &folder : path->write()) {
for (auto &folder : path->all()) {
try {
wolv::io::fs::createDirectories(folder);
if (isSubPathWritable(folder.parent_path()))
wolv::io::fs::createDirectories(folder);
} catch (...) {
log::error("Failed to create folder {}!", wolv::util::toUTF8String(folder));
result = false;

View File

@@ -5,6 +5,7 @@
#include <hex/api/project_file_manager.hpp>
#include <hex/api/imhex_api.hpp>
#include <hex/api/event_manager.hpp>
#include <hex/api/task_manager.hpp>
#include <hex/helpers/utils_macos.hpp>
#include <hex/helpers/logger.hpp>
@@ -65,7 +66,9 @@ namespace hex {
});
EventProviderDirtied::subscribe([this](prv::Provider *) {
macosMarkContentEdited(m_window);
TaskManager::doLater([this] {
macosMarkContentEdited(m_window);
});
});
ProjectFile::registerHandler({
@@ -75,7 +78,10 @@ namespace hex {
return true;
},
.store = [this](const std::fs::path &, Tar &) {
macosMarkContentEdited(m_window, false);
TaskManager::doLater([this] {
macosMarkContentEdited(m_window, false);
});
return true;
}
});

View File

@@ -7,6 +7,9 @@
#include <hex/api/event_manager.hpp>
#include <imgui.h>
#include <imgui_internal.h>
// Function used by c++ to get the size of the html canvas
EM_JS(int, canvas_get_width, (), {
return Module.canvas.width;
@@ -22,6 +25,10 @@ EM_JS(void, resizeCanvas, (), {
js_resizeCanvas();
});
EM_JS(void, fixCanvasInPlace, (), {
document.getElementById('canvas').classList.add('canvas-fixed');
});
EM_JS(void, setupThemeListener, (), {
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', event => {
Module._handleThemeChange();
@@ -37,6 +44,27 @@ extern "C" void handleThemeChange() {
hex::EventOSThemeChanged::post();
}
EM_JS(void, setupInputModeListener, (), {
Module.canvas.addEventListener('mousedown', function() {
Module._enterMouseMode();
});
Module.canvas.addEventListener('touchstart', function() {
Module._enterTouchMode();
});
});
EMSCRIPTEN_KEEPALIVE
extern "C" void enterMouseMode() {
ImGui::GetIO().AddMouseSourceEvent(ImGuiMouseSource_Mouse);
}
EMSCRIPTEN_KEEPALIVE
extern "C" void enterTouchMode() {
ImGui::GetIO().AddMouseSourceEvent(ImGuiMouseSource_TouchScreen);
}
namespace hex {
void nativeErrorMessage(const std::string &message) {
@@ -64,12 +92,17 @@ namespace hex {
return;
alert("Failed to load permanent file system: "+err);
});
// Center splash screen
document.getElementById('canvas').classList.remove('canvas-fixed');
});
}
void Window::setupNativeWindow() {
resizeCanvas();
setupThemeListener();
setupInputModeListener();
fixCanvasInPlace();
bool themeFollowSystem = ImHexApi::System::usesSystemThemeDetection();
EventOSThemeChanged::subscribe(this, [themeFollowSystem] {
@@ -87,6 +120,7 @@ namespace hex {
glfwSetWindowRefreshCallback(m_window, [](GLFWwindow *window) {
auto win = static_cast<Window *>(glfwGetWindowUserPointer(window));
resizeCanvas();
win->fullFrame();
});

View File

@@ -5,7 +5,7 @@
#include "messaging.hpp"
#include <hex/helpers/utils.hpp>
#include <hex/helpers/utils.hpp>
#include <hex/helpers/logger.hpp>
#include <hex/helpers/default_paths.hpp>
@@ -24,6 +24,7 @@
#include <wrl/client.h>
#include <fcntl.h>
#include <shellapi.h>
#include <timeapi.h>
#include <cstdio>
@@ -160,7 +161,50 @@ namespace hex {
rect = client;
}
return 0;
// This code tries to avoid DWM flickering when resizing the window
// It's not perfect, but it's really the best we can do.
LARGE_INTEGER performanceFrequency = {};
QueryPerformanceFrequency(&performanceFrequency);
TIMECAPS tc = {};
timeGetDevCaps(&tc, sizeof(tc));
const auto granularity = tc.wPeriodMin;
timeBeginPeriod(tc.wPeriodMin);
DWM_TIMING_INFO dti = {};
dti.cbSize = sizeof(dti);
::DwmGetCompositionTimingInfo(nullptr, &dti);
LARGE_INTEGER end = {};
QueryPerformanceCounter(&end);
const auto period = dti.qpcRefreshPeriod;
const i64 delta = dti.qpcVBlank - end.QuadPart;
i64 sleepTicks = 0;
i64 sleepMilliSeconds = 0;
if (delta >= 0) {
sleepTicks = delta / period;
} else {
sleepTicks = -1 + delta / period;
}
sleepMilliSeconds = delta - (period * sleepTicks);
const double sleepTime = (1000.0 * double(sleepMilliSeconds) / double(performanceFrequency.QuadPart));
Sleep(DWORD(std::round(sleepTime)));
timeEndPeriod(granularity);
return WVR_REDRAW;
}
case WM_ERASEBKGND:
return 1;
case WM_WINDOWPOSCHANGING: {
// Make sure that windows discards the entire client area when resizing to avoid flickering
const auto windowPos = reinterpret_cast<LPWINDOWPOS>(lParam);
windowPos->flags |= SWP_NOCOPYBITS;
break;
}
case WM_NCHITTEST: {
// Handle window resizing and moving
@@ -562,8 +606,20 @@ namespace hex {
ImHexApi::System::impl::setMainWindowSize(width, height);
});
DwmEnableMMCSS(TRUE);
{
constexpr BOOL value = TRUE;
DwmSetWindowAttribute(hwnd, DWMWA_NCRENDERING_ENABLED, &value, sizeof(value));
}
{
constexpr DWMNCRENDERINGPOLICY value = DWMNCRP_ENABLED;
DwmSetWindowAttribute(hwnd, DWMWA_NCRENDERING_POLICY, &value, sizeof(value));
}
glfwSetWindowRefreshCallback(m_window, [](GLFWwindow *window) {
auto win = static_cast<Window *>(glfwGetWindowUserPointer(window));
win->fullFrame();
DwmFlush();
});
@@ -575,6 +631,7 @@ namespace hex {
// Remove WS_POPUP style from the window to make various window management tools work
auto hwnd = glfwGetWin32Window(m_window);
::SetWindowLong(hwnd, GWL_STYLE, (GetWindowLong(hwnd, GWL_STYLE) | WS_OVERLAPPEDWINDOW) & ~WS_POPUP);
::SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_COMPOSITED | WS_EX_LAYERED);
if (!ImHexApi::System::impl::isWindowResizable()) {
if (glfwGetWindowAttrib(m_window, GLFW_MAXIMIZED)) {

View File

@@ -194,6 +194,16 @@ namespace hex {
while (!glfwWindowShouldClose(m_window)) {
m_lastStartFrameTime = glfwGetTime();
{
int x = 0, y = 0;
int width = 0, height = 0;
glfwGetWindowPos(m_window, &x, &y);
glfwGetWindowSize(m_window, &width, &height);
ImHexApi::System::impl::setMainWindowPosition(x, y);
ImHexApi::System::impl::setMainWindowSize(width, height);
}
// Determine if the application should be in long sleep mode
bool shouldLongSleep = !m_unlockFrameRate;
@@ -800,7 +810,6 @@ namespace hex {
{
int width = 0, height = 0;
glfwGetWindowSize(m_window, &width, &height);
glfwSetWindowSize(m_window, width, height);
if (initialWindowProperties.has_value()) {
width = initialWindowProperties->width;
@@ -834,7 +843,8 @@ namespace hex {
if (macosIsWindowBeingResizedByUser(window)) {
ImGui::GetIO().MousePos = ImVec2();
}
#else
#elif defined(OS_WEB)
win->fullFrame();
#endif
});
@@ -963,6 +973,9 @@ namespace hex {
style.IndentSpacing = 10.0F;
style.DisplaySafeAreaPadding = ImVec2(0.0F, 0.0F);
style.Colors[ImGuiCol_TabSelectedOverline] = ImVec4(0.0F, 0.0F, 0.0F, 0.0F);
style.Colors[ImGuiCol_TabDimmedSelectedOverline] = ImVec4(0.0F, 0.0F, 0.0F, 0.0F);
// Install custom settings handler
{
ImGuiSettingsHandler handler;

View File

@@ -2,6 +2,11 @@ cmake_minimum_required(VERSION 3.16)
include(ImHexPlugin)
find_file(DEFAULT_MAGIC_FILE_PATH magic.mgc HINTS ${LIBMAGIC_INCLUDE_DIR}/../share/misc)
if (EXISTS ${DEFAULT_MAGIC_FILE_PATH})
add_romfs_resource(${DEFAULT_MAGIC_FILE_PATH} always_auto_extract/magic/magic.mgc)
endif ()
add_imhex_plugin(
NAME
builtin
@@ -122,11 +127,6 @@ add_imhex_plugin(
LLVMDemangle
)
find_file(DEFAULT_MAGIC_FILE_PATH magic.mgc HINTS ${LIBMAGIC_INCLUDE_DIR}/../share/misc)
if (DEFAULT_MAGIC_FILE_PATH)
add_romfs_resource(${DEFAULT_MAGIC_FILE_PATH} always_auto_extract/magic/magic.mgc)
endif ()
if (WIN32)
target_link_libraries(builtin PRIVATE setupapi)
endif ()

View File

@@ -91,6 +91,7 @@ namespace hex::plugin::builtin {
PerProvider<std::optional<u64>> m_selectionStart, m_selectionEnd;
PerProvider<std::map<u64, color_t>> m_foregroundHighlights, m_backgroundHighlights;
PerProvider<std::set<Region>> m_hoverHighlights;
};
}

View File

@@ -644,12 +644,6 @@ namespace hex::plugin::builtin {
static void createHelpMenu() {
ContentRegistry::Interface::registerMainMenuItem("hex.builtin.menu.help", 6000);
ContentRegistry::Interface::addMenuItem({ "hex.builtin.menu.help", "Interactive Help"}, 10000, Shortcut::None, []{
TutorialManager::startHelpHover();
});
TutorialManager::addInteractiveHelpLink({ View::toWindowName("hex.builtin.view.pattern_data.name") }, "https://google.com");
}

View File

@@ -54,9 +54,9 @@ namespace hex::plugin::builtin {
{ "resize-grip-active", ImGuiCol_ResizeGripActive },
{ "tab", ImGuiCol_Tab },
{ "tab-hovered", ImGuiCol_TabHovered },
{ "tab-active", ImGuiCol_TabActive },
{ "tab-unfocused", ImGuiCol_TabUnfocused },
{ "tab-unfocused-active", ImGuiCol_TabUnfocusedActive },
{ "tab-active", ImGuiCol_TabSelected },
{ "tab-unfocused", ImGuiCol_TabDimmed },
{ "tab-unfocused-active", ImGuiCol_TabDimmedSelected },
{ "docking-preview", ImGuiCol_DockingPreview },
{ "docking-empty-background", ImGuiCol_DockingEmptyBg },
{ "plot-lines", ImGuiCol_PlotLines },

View File

@@ -412,7 +412,8 @@ namespace hex::plugin::builtin {
ContentRegistry::Interface::addToolbarItem([] {
for (const auto &menuItem : ContentRegistry::Interface::impl::getToolbarMenuItems()) {
if (menuItem->unlocalizedNames.back().get() == ContentRegistry::Interface::impl::SeparatorValue) {
const auto &unlocalizedItemName = menuItem->unlocalizedNames.back();
if (unlocalizedItemName.get() == ContentRegistry::Interface::impl::SeparatorValue) {
ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
continue;
}
@@ -421,6 +422,8 @@ namespace hex::plugin::builtin {
if (ImGuiExt::ToolBarButton(menuItem->icon.glyph.c_str(), ImGuiExt::GetCustomColorVec4(ImGuiCustomCol(menuItem->icon.color)))) {
menuItem->callback();
}
ImGuiExt::InfoTooltip(Lang(unlocalizedItemName));
ImGui::EndDisabled();
}
});
@@ -439,8 +442,8 @@ namespace hex::plugin::builtin {
{
auto providers = ImHexApi::Provider::getProviders();
ImGui::PushStyleColor(ImGuiCol_TabActive, ImGui::GetColorU32(ImGuiCol_MenuBarBg));
ImGui::PushStyleColor(ImGuiCol_TabUnfocusedActive, ImGui::GetColorU32(ImGuiCol_MenuBarBg));
ImGui::PushStyleColor(ImGuiCol_TabSelected, ImGui::GetColorU32(ImGuiCol_MenuBarBg));
ImGui::PushStyleColor(ImGuiCol_TabDimmedSelected, ImGui::GetColorU32(ImGuiCol_MenuBarBg));
auto providerSelectorVisible = ImGui::BeginTabBar("provider_switcher", ImGuiTabBarFlags_FittingPolicyScroll | ImGuiTabBarFlags_Reorderable | ImGuiTabBarFlags_AutoSelectNewTabs);
ImGui::PopStyleColor(2);
@@ -489,7 +492,7 @@ namespace hex::plugin::builtin {
break;
}
if (ImGui::IsMouseDown(ImGuiMouseButton_Right) && ImGui::IsItemHovered()) {
if (ImGui::IsMouseDown(ImGuiMouseButton_Right) && ImGui::IsItemHovered() && !ImGui::IsMouseDragging(ImGuiMouseButton_Right)) {
rightClickedProvider = tabProvider;
RequestOpenPopup::post("ProviderMenu");
}

View File

@@ -343,6 +343,7 @@ namespace hex::plugin::builtin {
Library { "file", "file", "https://github.com/file/file" },
Library { "glfw", "glfw", "https://github.com/glfw/glfw" },
Library { "llvm", "llvm-project", "https://github.com/llvm/llvm-project" },
Library { "Boost.Regex", "John Maddock", "https://github.com/boostorg/regex" },
};
constexpr static auto drawTable = [](const char *category, const auto &libraries) {

View File

@@ -103,7 +103,7 @@ namespace hex::plugin::builtin {
ImGui::Separator();
// Draw the results
if (ImGui::BeginChild("##results", ImGui::GetContentRegionAvail(), false, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_NavFlattened)) {
if (ImGui::BeginChild("##results", ImGui::GetContentRegionAvail(), ImGuiChildFlags_NavFlattened, ImGuiWindowFlags_AlwaysVerticalScrollbar)) {
for (const auto &[displayResult, matchedCommand, callback] : m_lastResults) {
ImGui::PushTabStop(true);
ON_SCOPE_EXIT { ImGui::PopTabStop(); };

View File

@@ -597,7 +597,7 @@ namespace hex::plugin::builtin {
void ViewDataProcessor::drawContextMenus(ViewDataProcessor::Workspace &workspace) {
// Handle the right click context menus
if (ImGui::IsMouseDown(ImGuiMouseButton_Right) && ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows)) {
if (ImGui::IsMouseDown(ImGuiMouseButton_Right) && ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows) && !ImGui::IsMouseDragging(ImGuiMouseButton_Right)) {
// Clear selections
ImNodes::ClearNodeSelection();
ImNodes::ClearLinkSelection();

View File

@@ -493,16 +493,8 @@ namespace hex::plugin::builtin {
});
m_hexEditor.setBackgroundHighlightCallback([this](u64 address, const u8 *data, size_t size) -> std::optional<color_t> {
bool hovered = false;
for (const auto &[id, hoverFunction] : ImHexApi::HexEditor::impl::getHoveringFunctions()) {
if (hoverFunction(m_hexEditor.getProvider(), address, data, size)) {
hovered = true;
break;
}
}
if (auto highlight = m_backgroundHighlights->find(address); highlight != m_backgroundHighlights->end()) {
if (hovered)
if (std::ranges::any_of(*m_hoverHighlights, [region = Region(address, size)](const Region &highlight) { return highlight.overlaps(region); }))
return ImAlphaBlendColors(highlight->second, 0xA0FFFFFF);
else
return highlight->second;
@@ -527,6 +519,14 @@ namespace hex::plugin::builtin {
return result;
});
m_hexEditor.setHoverChangedCallback([this](u64 address, size_t size) {
m_hoverHighlights->clear();
for (const auto &[id, hoverFunction] : ImHexApi::HexEditor::impl::getHoveringFunctions()) {
auto highlightedAddresses = hoverFunction(m_hexEditor.getProvider(), address, size);
m_hoverHighlights->merge(highlightedAddresses);
}
});
m_hexEditor.setTooltipCallback([](u64 address, const u8 *data, size_t size) {
for (const auto &[id, callback] : ImHexApi::HexEditor::impl::getTooltipFunctions()) {
callback(address, data, size);
@@ -608,7 +608,7 @@ namespace hex::plugin::builtin {
m_currentPopupHasHovered = false;
}
m_currentPopupHover = ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem | ImGuiHoveredFlags_RootAndChildWindows);
m_currentPopupHover = ImGui::IsWindowHovered(ImGuiHoveredFlags_RectOnly | ImGuiHoveredFlags_RootAndChildWindows);
m_currentPopupDetached = !ImGui::GetCurrentWindow()->ViewportOwned;
m_currentPopupHasHovered |= m_currentPopupHover;
@@ -629,7 +629,7 @@ namespace hex::plugin::builtin {
ImGui::PopStyleVar();
// Right click menu
if (ImGui::IsMouseDown(ImGuiMouseButton_Right) && ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows) && !ImGui::IsAnyItemHovered())
if (ImGui::IsMouseDown(ImGuiMouseButton_Right) && ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows) && !ImGui::IsAnyItemHovered() && !ImGui::IsMouseDragging(ImGuiMouseButton_Right))
RequestOpenPopup::post("hex.builtin.menu.edit");
}

View File

@@ -37,8 +37,8 @@ namespace hex::plugin::builtin {
(*m_patternDrawer)->jumpToPattern(pattern);
});
ImHexApi::HexEditor::addHoverHighlightProvider([this](const prv::Provider *, u64 address, const u8 *, size_t size) {
return m_hoveredPatternRegion.overlaps(Region { address, size });
ImHexApi::HexEditor::addHoverHighlightProvider([this](const prv::Provider *, u64, size_t) -> std::set<Region> {
return { m_hoveredPatternRegion };
});
m_patternDrawer.setOnCreateCallback([this](const prv::Provider *provider, auto &drawer) {

View File

@@ -231,7 +231,7 @@ namespace hex::plugin::builtin {
m_textEditor.Render("hex.builtin.view.pattern_editor.name"_lang, textEditorSize, true);
TextEditor::FindReplaceHandler *findReplaceHandler = m_textEditor.GetFindReplaceHandler();
if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) {
if (ImGui::IsMouseDown(ImGuiMouseButton_Right) && ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows) && !ImGui::IsMouseDragging(ImGuiMouseButton_Right)) {
ImGui::OpenPopup("##pattern_editor_context_menu");
}
@@ -1689,6 +1689,7 @@ namespace hex::plugin::builtin {
});
ON_SCOPE_EXIT {
runtime.getInternals().evaluator->setDebugMode(false);
*m_lastEvaluationOutVars = runtime.getOutVariables();
*m_sections = runtime.getSections();
@@ -1911,24 +1912,23 @@ namespace hex::plugin::builtin {
return color;
});
ImHexApi::HexEditor::addHoverHighlightProvider([this](const prv::Provider *provider, u64 address, const u8 *, size_t) {
if (!m_parentHighlightingEnabled) return false;
ImHexApi::HexEditor::addHoverHighlightProvider([this](const prv::Provider *, u64 address, size_t size) {
std::set<Region> result;
if (!m_parentHighlightingEnabled)
return result;
const auto &runtime = ContentRegistry::PatternLanguage::getRuntime();
if (auto hoveredRegion = ImHexApi::HexEditor::getHoveredRegion(provider)) {
for (const auto &pattern : runtime.getPatternsAtAddress(hoveredRegion->getStartAddress())) {
const pl::ptrn::Pattern * checkPattern = pattern;
if (auto parent = checkPattern->getParent(); parent != nullptr)
checkPattern = parent;
const auto hoveredRegion = Region { address, size };
for (const auto &pattern : runtime.getPatternsAtAddress(hoveredRegion.getStartAddress())) {
const pl::ptrn::Pattern * checkPattern = pattern;
if (auto parent = checkPattern->getParent(); parent != nullptr)
checkPattern = parent;
if (checkPattern->getOffset() <= address && checkPattern->getOffset() + checkPattern->getSize() > address) {
return true;
}
}
result.emplace(checkPattern->getOffset(), checkPattern->getSize());
}
return false;
return result;
});
ImHexApi::HexEditor::addTooltipProvider([this](u64 address, const u8 *data, size_t size) {

View File

@@ -372,7 +372,7 @@ namespace hex::plugin::builtin {
void drawWelcomeScreen() {
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0);
ImGui::PushStyleColor(ImGuiCol_WindowShadow, 0x00);
if (ImGui::Begin("ImHexDockSpace")) {
if (ImGui::Begin("ImHexDockSpace", nullptr, ImGuiWindowFlags_NoBringToFrontOnFocus)) {
if (!ImHexApi::Provider::isValid()) {
static auto title = []{
std::array<char, 256> title = {};
@@ -388,7 +388,7 @@ namespace hex::plugin::builtin {
ImGui::SetNextWindowSize(ImGui::GetContentRegionAvail() + scaled({ 0, 10 }));
ImGui::SetNextWindowPos(ImGui::GetCursorScreenPos() - ImVec2(0, ImGui::GetStyle().FramePadding.y + 2_scaled));
ImGui::SetNextWindowViewport(ImGui::GetMainViewport()->ID);
if (ImGui::Begin("Welcome Screen", nullptr, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove)) {
if (ImGui::Begin("Welcome Screen", nullptr, ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove)) {
ImGui::BringWindowToDisplayBack(ImGui::GetCurrentWindowRead());
drawWelcomeScreenBackground();
@@ -436,7 +436,7 @@ namespace hex::plugin::builtin {
void drawNoViewsBackground() {
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0);
ImGui::PushStyleColor(ImGuiCol_WindowShadow, 0x00);
if (ImGui::Begin("ImHexDockSpace")) {
if (ImGui::Begin("ImHexDockSpace", nullptr, ImGuiWindowFlags_NoBringToFrontOnFocus)) {
static std::array<char, 256> title;
ImFormatString(title.data(), title.size(), "%s/DockSpace_%08X", ImGui::GetCurrentWindowRead()->Name, ImGui::GetID("ImHexMainDock"));
if (ImGui::Begin(title.data())) {
@@ -447,7 +447,7 @@ namespace hex::plugin::builtin {
ImGui::SetNextWindowSize(ImGui::GetContentRegionAvail() + scaled({ 0, 10 }));
ImGui::SetNextWindowPos(ImGui::GetCursorScreenPos() - ImVec2(0, ImGui::GetStyle().FramePadding.y + 2_scaled));
ImGui::SetNextWindowViewport(ImGui::GetMainViewport()->ID);
if (ImGui::Begin("Welcome Screen", nullptr, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove)) {
if (ImGui::Begin("Welcome Screen", nullptr, ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove)) {
auto imageSize = scaled(ImVec2(350, 350));
auto imagePos = (ImGui::GetContentRegionAvail() - imageSize) / 2;

View File

@@ -146,7 +146,7 @@ namespace hex::plugin::builtin {
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImGui::GetColorU32(ImGuiCol_ScrollbarGrabActive));
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImGui::GetColorU32(ImGuiCol_ScrollbarGrabHovered));
const auto windowSize = ImHexApi::System::getMainWindowSize();
const auto windowSize = ImGui::GetWindowSize();
auto searchBoxSize = ImVec2(s_showSearchBar ? windowSize.x / 2.5 : ImGui::CalcTextSize(s_windowTitle.c_str()).x, titleBarHeight);
auto searchBoxPos = ImVec2((windowSize / 2 - searchBoxSize / 2).x, 0);
auto titleBarButtonPosY = 0.0F;
@@ -284,12 +284,10 @@ namespace hex::plugin::builtin {
}
void defineMenu(const UnlocalizedString &menuName) {
ImGui::GetStyle().TouchExtraPadding = scaled(ImVec2(0, 2));
if (ImGui::BeginMenu(Lang(menuName))) {
populateMenu(menuName);
ImGui::EndMenu();
}
ImGui::GetStyle().TouchExtraPadding = ImVec2(0, 0);
}
void drawMenu() {

View File

@@ -26,20 +26,18 @@ add_imhex_plugin(
ui
fonts
FEATURES
ZLIB
BZIP2
LIBLZMA
ZSTD
ZLIB "ZLib support"
BZIP2 "Bzip2 support"
LIBLZMA "LZMA support"
ZSTD "zstd Support"
)
find_package(ZSTD)
if(ZSTD_FOUND)
set(LIBRARIES ${LIBRARIES} "${ZSTD_LIBRARY}")
message(STATUS "Enabling decompression support using ZSTD (${ZSTD_VERSION})")
enable_plugin_feature(ZSTD)
endif()
set(LIBLZMA_HAS_AUTO_DECODER 1)
set(LIBLZMA_HAS_EASY_ENCODER 1)
set(LIBLZMA_HAS_LZMA_PRESET 1)
addOptionalLibrary(ZLIB ZLIB)
addOptionalLibrary(BZip2 BZip2)
addOptionalLibrary(LibLZMA LibLZMA)
addOptionalLibrary(ZSTD zstd)
target_link_libraries(decompress PRIVATE ${LIBRARIES})

View File

@@ -14,13 +14,6 @@ namespace hex::plugin::decompress {
using namespace hex;
using namespace hex::plugin::decompress;
IMHEX_DEFINE_PLUGIN_FEATURES() {
{ "bzip2 Support", IMHEX_FEATURE_ENABLED(BZIP2) },
{ "zlib Support", IMHEX_FEATURE_ENABLED(ZLIB) },
{ "LZMA Support", IMHEX_FEATURE_ENABLED(LIBLZMA) },
{ "zstd Support", IMHEX_FEATURE_ENABLED(ZSTD) },
};
IMHEX_PLUGIN_SETUP("Decompressing", "WerWolv", "Support for decompressing data") {
hex::log::debug("Using romfs: '{}'", romfs::name());

View File

@@ -152,8 +152,11 @@ namespace hex::fonts {
return m_fontAtlas->Build();
}
[[nodiscard]] ImFontAtlas* getAtlas() const {
return m_fontAtlas;
[[nodiscard]] ImFontAtlas* takeAtlas() {
auto result = m_fontAtlas;
m_fontAtlas = nullptr;
return result;
}
float calculateFontDescend(const ImHexApi::Fonts::Font &font, float fontSize) const {
@@ -331,7 +334,7 @@ namespace hex::fonts {
const bool result = fontAtlas.build();
if (result) {
// Set the font atlas if the build was successful
ImHexApi::Fonts::impl::setFontAtlas(fontAtlas.getAtlas());
ImHexApi::Fonts::impl::setFontAtlas(fontAtlas.takeAtlas());
return true;
}

View File

@@ -3,9 +3,12 @@ cmake_minimum_required(VERSION 3.16)
include(ImHexPlugin)
find_package(CoreClrEmbed)
add_library(dotnet INTERFACE)
if (CoreClrEmbed_FOUND)
set(IMHEX_DOTNET_SCRIPT_SUPPORT ON)
target_compile_definitions(dotnet INTERFACE IMHEX_DOTNET_RUNTIME_VERSION="${CoreClrEmbed_VERSION}")
add_library(nethost SHARED IMPORTED)
target_include_directories(nethost INTERFACE "${CoreClrEmbed_INCLUDE_DIRS}")
get_filename_component(CoreClrEmbed_FOLDER ${CoreClrEmbed_SHARED_LIBRARIES} DIRECTORY)
@@ -21,6 +24,18 @@ if (CoreClrEmbed_FOUND)
if (IMHEX_BUNDLE_DOTNET)
install(FILES ${CoreClrEmbed_SHARED_LIBRARIES} DESTINATION ${CMAKE_INSTALL_LIBDIR})
endif()
message(STATUS "Enabling .NET Scripting support!")
target_link_directories(dotnet INTERFACE ${CoreClrEmbed_FOLDER})
target_include_directories(dotnet INTERFACE ${CoreClrEmbed_INCLUDE_DIRS})
target_compile_definitions(dotnet INTERFACE IMHEX_DOTNET_SCRIPT_SUPPORT=1)
target_sources(dotnet INTERFACE
source/loaders/dotnet/dotnet_loader.cpp
)
add_subdirectory(support/dotnet)
add_dependencies(dotnet AssemblyLoader)
endif()
add_subdirectory(support/c)
@@ -40,20 +55,5 @@ add_imhex_plugin(
c_api
fonts
ui
)
if (IMHEX_DOTNET_SCRIPT_SUPPORT)
message(STATUS "Enabling .NET Scripting support!")
target_link_directories(script_loader PRIVATE ${CoreClrEmbed_FOLDER})
target_include_directories(script_loader PRIVATE ${CoreClrEmbed_INCLUDE_DIRS})
target_compile_definitions(script_loader PRIVATE IMHEX_DOTNET_SCRIPT_SUPPORT=1)
target_sources(script_loader PRIVATE
source/loaders/dotnet/dotnet_loader.cpp
)
add_subdirectory(support/dotnet)
add_dependencies(script_loader AssemblyLoader)
endif()
dotnet
)

View File

@@ -13,6 +13,7 @@
#include <nethost.h>
#include <coreclr_delegates.h>
#include <hostfxr.h>
#include <imgui.h>
#include <hex/api/plugin_manager.hpp>
@@ -110,13 +111,7 @@ namespace hex::script::loader {
= getExport<hostfxr_set_error_writer_fn>(hostfxrLibrary, "hostfxr_set_error_writer");
}
hostfxr_set_error_writer([] HOSTFXR_CALLTYPE (const char_t *message) {
#if defined(OS_WINDOWS)
log::error("{}", utf16ToUtf8(message));
#else
log::error("{}", message);
#endif
});
hostfxr_set_error_writer([] HOSTFXR_CALLTYPE (const char_t *) { });
return
hostfxr_initialize_for_runtime_config != nullptr &&
@@ -137,7 +132,12 @@ namespace hex::script::loader {
};
if (result > 2 || ctx == nullptr) {
throw std::runtime_error(hex::format("Failed to initialize command line 0x{:X}", result));
if (result == /* FrameworkMissingFailure */ 0x80008096) {
log::warn("ImHex has built-in support for .NET scripts and extensions. However, these can only be used when the .NET runtime is installed.");
log::warn("Please install version {} or later of the .NET runtime if you plan to use them. Otherwise this error can be safely ignored.", IMHEX_DOTNET_RUNTIME_VERSION);
}
throw std::runtime_error(hex::format("Command line init failed 0x{:X}", result));
}
#if defined (OS_WINDOWS)
@@ -146,6 +146,14 @@ namespace hex::script::loader {
hostfxr_set_runtime_property_value(ctx, STRING("PINVOKE_OVERRIDE"), hex::format("{}", (void*)pInvokeOverride).c_str());
#endif
hostfxr_set_error_writer([] HOSTFXR_CALLTYPE (const char_t *message) {
#if defined(OS_WINDOWS)
log::error("{}", utf16ToUtf8(message));
#else
log::error("{}", message);
#endif
});
result = hostfxr_get_runtime_delegate(
ctx,
hostfxr_delegate_type::hdt_load_assembly_and_get_function_pointer,

View File

@@ -21,8 +21,6 @@ using ScriptLoaders = std::tuple<
#endif
>;
IMHEX_DEFINE_PLUGIN_FEATURES(){ };
namespace {
ScriptLoaders s_loaders;

View File

@@ -270,6 +270,10 @@ namespace hex::ui {
m_backgroundColorCallback = callback;
}
void setHoverChangedCallback(const std::function<void(u64, size_t)> &callback) {
m_hoverChangedCallback = callback;
}
void setTooltipCallback(const std::function<void(u64, const u8 *, size_t)> &callback) {
m_tooltipCallback = callback;
}
@@ -372,6 +376,7 @@ namespace hex::ui {
static std::optional<color_t> defaultColorCallback(u64, const u8 *, size_t) { return std::nullopt; }
static void defaultTooltipCallback(u64, const u8 *, size_t) { }
std::function<std::optional<color_t>(u64, const u8 *, size_t)> m_foregroundColorCallback = defaultColorCallback, m_backgroundColorCallback = defaultColorCallback;
std::function<void(u64, size_t)> m_hoverChangedCallback = [](auto, auto){ };
std::function<void(u64, const u8 *, size_t)> m_tooltipCallback = defaultTooltipCallback;
Mode m_mode = Mode::Overwrite;

View File

@@ -666,7 +666,11 @@ namespace hex::ui {
ImGuiExt::TextFormatted("{:?>{}}", "", maxCharsPerCell);
if (cellHovered) {
hoveredCell = { byteAddress, bytesPerCell };
Region newHoveredCell = { byteAddress, bytesPerCell };
if (hoveredCell != newHoveredCell) {
hoveredCell = newHoveredCell;
m_hoverChangedCallback(hoveredCell.address, hoveredCell.size);
}
}
ImGui::PopItemWidth();
@@ -725,7 +729,11 @@ namespace hex::ui {
this->drawCell(byteAddress, &bytes[x], 1, cellHovered, CellType::ASCII);
if (cellHovered) {
hoveredCell = { byteAddress, bytesPerCell };
Region newHoveredCell = { byteAddress, bytesPerCell };
if (hoveredCell != newHoveredCell) {
hoveredCell = newHoveredCell;
m_hoverChangedCallback(hoveredCell.address, hoveredCell.size);
}
}
ImGui::PopItemWidth();
@@ -813,7 +821,11 @@ namespace hex::ui {
this->handleSelection(address, data.advance, &bytes[address % m_bytesPerRow], cellHovered);
if (cellHovered) {
hoveredCell = { address, data.advance };
Region newHoveredCell = { address, data.advance };
if (hoveredCell != newHoveredCell) {
hoveredCell = newHoveredCell;
m_hoverChangedCallback(hoveredCell.address, hoveredCell.size);
}
}
}
}

View File

@@ -141,13 +141,42 @@ namespace hex::ui {
void drawSizeColumnForBitfieldMember(const pl::ptrn::PatternBitfieldMember &pattern) {
ImGui::TableNextColumn();
if (pattern.getBitSize() == 1)
ImGuiExt::TextFormatted("1 bit");
else
ImGuiExt::TextFormatted("{0} bits", pattern.getBitSize());
auto bits = pattern.getBitSize();
auto bytes = bits / 8;
bits = bits % 8;
std::string text;
if (bytes != 0) {
if (bytes == 1)
text += hex::format("{0} byte", bytes);
else
text += hex::format("{0} bytes", bytes);
if (bits != 0)
text += ", ";
}
if (bits != 0) {
if (bits == 1)
text += hex::format("{0} bit", bits);
else
text += hex::format("{0} bits", bits);
}
if (bytes == 0 && bits == 0) {
text = "0 bytes";
}
ImGui::TextUnformatted(text.c_str());
}
void drawSizeColumn(const pl::ptrn::Pattern& pattern) {
if (pattern.isPatternLocal()) {
ImGui::TableNextColumn();
return;
}
if (auto *bitfieldMember = dynamic_cast<const pl::ptrn::PatternBitfieldMember*>(&pattern); bitfieldMember != nullptr && bitfieldMember->getParentBitfield() != nullptr)
drawSizeColumnForBitfieldMember(*bitfieldMember);
else {
@@ -209,6 +238,12 @@ namespace hex::ui {
void PatternDrawer::updateFilter() {
m_filteredPatterns.clear();
if (m_filter.path.empty()) {
m_filteredPatterns = m_sortedPatterns;
return;
}
std::vector<std::string> treePath;
for (auto &pattern : m_sortedPatterns) {
traversePatternTree(*pattern, treePath, [this, &treePath](auto &pattern){
@@ -1032,10 +1067,20 @@ namespace hex::ui {
ImGui::TableNextColumn();
drawOffsetColumns(pattern);
if (!pattern.isLocal()) {
ImGui::TableNextColumn();
ImGuiExt::TextFormatted("0x{0:08X}", startOffset);
ImGui::TableNextColumn();
ImGuiExt::TextFormatted("0x{0:08X}", endOffset + endSize - (endSize == 0 ? 0 : 1));
} else {
ImGui::TableNextColumn();
ImGuiExt::TextFormatted("[{}]", "hex.ui.pattern_drawer.local"_lang);
ImGui::TableNextColumn();
ImGuiExt::TextFormatted("[{}]", "hex.ui.pattern_drawer.local"_lang);
}
ImGui::TableNextColumn();
ImGuiExt::TextFormatted("0x{0:04X}", chunkSize);
ImGuiExt::TextFormatted("{0} {1}", chunkSize, chunkSize == 1 ? "byte" : "bytes");
ImGui::TableNextColumn();
ImGuiExt::TextFormattedColored(TextEditor::GetPalette()[u32(TextEditor::PaletteIndex::KnownIdentifier)], "{0}", pattern.getTypeName());
ImGui::SameLine(0, 0);
@@ -1131,24 +1176,26 @@ namespace hex::ui {
if (!sortSpecs->SpecsDirty && !sortedPatterns.empty()) {
return true;
}
sortedPatterns.clear();
std::transform(patterns.begin(), patterns.end(), std::back_inserter(sortedPatterns), [](const std::shared_ptr<pl::ptrn::Pattern> &pattern) {
return pattern.get();
});
std::sort(sortedPatterns.begin(), sortedPatterns.end(), [this, &sortSpecs](const pl::ptrn::Pattern *left, const pl::ptrn::Pattern *right) -> bool {
return this->sortPatterns(sortSpecs, left, right);
});
if (!m_favoritesUpdateTask.isRunning()) {
sortedPatterns.clear();
std::transform(patterns.begin(), patterns.end(), std::back_inserter(sortedPatterns), [](const std::shared_ptr<pl::ptrn::Pattern> &pattern) {
return pattern.get();
});
for (auto &pattern : sortedPatterns) {
pattern->sort([this, &sortSpecs](const pl::ptrn::Pattern *left, const pl::ptrn::Pattern *right){
std::stable_sort(sortedPatterns.begin(), sortedPatterns.end(), [this, &sortSpecs](const pl::ptrn::Pattern *left, const pl::ptrn::Pattern *right) -> bool {
return this->sortPatterns(sortSpecs, left, right);
});
for (auto &pattern : sortedPatterns) {
pattern->sort([this, &sortSpecs](const pl::ptrn::Pattern *left, const pl::ptrn::Pattern *right){
return this->sortPatterns(sortSpecs, left, right);
});
}
sortSpecs->SpecsDirty = false;
}
sortSpecs->SpecsDirty = false;
return true;
}