Imported ImNodes
This commit is contained in:
parent
75eb1fc143
commit
97ec4ea413
3
.vscode/c_cpp_properties.json
vendored
3
.vscode/c_cpp_properties.json
vendored
@ -6,7 +6,8 @@
|
||||
"${workspaceFolder}/**",
|
||||
"${workspaceFolder}/Inc",
|
||||
"${workspaceFolder}/Lib/imgui-1.92.4-docking",
|
||||
"${workspaceFolder}/Lib/imgui-1.92.4-docking/backends"
|
||||
"${workspaceFolder}/Lib/imgui-1.92.4-docking/backends",
|
||||
"${workspaceFolder}/Lib/imnodes-master-b2ec254"
|
||||
],
|
||||
"defines": [
|
||||
"UNICODE",
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
#define __UI_LAYOUT__
|
||||
|
||||
#include "imgui.h"
|
||||
#include "imnodes.h"
|
||||
|
||||
// UI布局
|
||||
void UI_Layout();
|
||||
|
||||
39
Lib/imnodes-master-b2ec254/.clang-format
Normal file
39
Lib/imnodes-master-b2ec254/.clang-format
Normal file
@ -0,0 +1,39 @@
|
||||
---
|
||||
AccessModifierOffset: -4
|
||||
AlignAfterOpenBracket: 'AlwaysBreak'
|
||||
AlignConsecutiveDeclarations: 'true'
|
||||
AllowAllParametersOfDeclarationOnNextLine: 'false'
|
||||
AllowShortFunctionsOnASingleLine: 'true'
|
||||
AlwaysBreakBeforeMultilineStrings: 'true'
|
||||
AlwaysBreakTemplateDeclarations: 'true'
|
||||
BinPackArguments: 'false'
|
||||
BinPackParameters: 'false'
|
||||
BraceWrapping: {
|
||||
AfterCaseLabel: 'true'
|
||||
AfterClass: 'true'
|
||||
AfterControlStatement: 'true'
|
||||
AfterEnum: 'true'
|
||||
AfterFunction: 'true'
|
||||
AfterNamespace: 'true'
|
||||
AfterStruct: 'true'
|
||||
AfterUnion: 'true'
|
||||
BeforeCatch: 'true'
|
||||
BeforeElse: 'true'
|
||||
IndentBraces: 'false'
|
||||
}
|
||||
BreakBeforeBraces: Custom
|
||||
ColumnLimit: 100
|
||||
Cpp11BracedListStyle: 'true'
|
||||
DerivePointerAlignment: 'false'
|
||||
IndentCaseLabels: 'false'
|
||||
IndentWidth: 4
|
||||
PenaltyExcessCharacter: 100000000
|
||||
PenaltyReturnTypeOnItsOwnLine: 100000000
|
||||
PointerAlignment: Left
|
||||
PointerBindsToType: 'true'
|
||||
SortIncludes: 'false'
|
||||
SpaceAfterTemplateKeyword: 'false'
|
||||
SpaceBeforeParens: ControlStatements
|
||||
TabWidth: 8
|
||||
UseTab: Never
|
||||
...
|
||||
33
Lib/imnodes-master-b2ec254/.clang-tidy
Normal file
33
Lib/imnodes-master-b2ec254/.clang-tidy
Normal file
@ -0,0 +1,33 @@
|
||||
# Apply this style by doing
|
||||
#
|
||||
# clang-tidy -fix-errors -config= <source-files>
|
||||
#
|
||||
# Running the command without -fix-errors will generate warnings about each
|
||||
# style violation but won't change them.
|
||||
|
||||
Checks: '-*,readability-identifier-naming'
|
||||
CheckOptions:
|
||||
- key: readability-identifier-naming.ClassCase
|
||||
value: CamelCase
|
||||
- key: readability-identifier-naming.EnumCase
|
||||
value: CamelCase
|
||||
- key: readability-identifier-naming.FunctionCase
|
||||
value: CamelCase
|
||||
- key: readability-identifier-naming.MemberCase
|
||||
value: CamelCase
|
||||
- key: readability-identifier-naming.MethodCase
|
||||
value: CamelCase
|
||||
- key: readability-identifier-naming.NamespaceCase
|
||||
value: CamelCase
|
||||
- key: readability-identifier-naming.ParameterCase
|
||||
value: lower_case
|
||||
- key: readability-identifier-naming.PrivateMemberCase
|
||||
value: CamelCase
|
||||
- key: readability-identifier-naming.PrivateMemberPrefix
|
||||
value: '_'
|
||||
- key: readability-identifier-naming.StaticConstantCase
|
||||
value: UPPER_CASE
|
||||
- key: readability-identifier-naming.StructCase
|
||||
value: CamelCase
|
||||
- key: readability-identifier-naming.VariableCase
|
||||
value: lower_case
|
||||
24
Lib/imnodes-master-b2ec254/.github/workflows/build.yaml
vendored
Normal file
24
Lib/imnodes-master-b2ec254/.github/workflows/build.yaml
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
name: Build
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: [macos-latest, windows-latest]
|
||||
runs-on: ${{ matrix.platform }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
- name: Setup vcpkg
|
||||
uses: lukka/run-vcpkg@v11
|
||||
with:
|
||||
vcpkgDirectory: ${{ github.workspace}}/vcpkg
|
||||
runVcpkgInstall: true
|
||||
- name: CMake generate
|
||||
run: cmake -B build-release/ -S . -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=${{ github.workspace}}/vcpkg/scripts/buildsystems/vcpkg.cmake
|
||||
- name: CMake build
|
||||
run: cmake --build build-release/ -j
|
||||
529
Lib/imnodes-master-b2ec254/.gitignore
vendored
Normal file
529
Lib/imnodes-master-b2ec254/.gitignore
vendored
Normal file
@ -0,0 +1,529 @@
|
||||
### Local build ###
|
||||
build*/
|
||||
|
||||
### ImGui ###
|
||||
**.ini
|
||||
|
||||
# Created by https://www.toptal.com/developers/gitignore/api/sublimetext
|
||||
# Edit at https://www.toptal.com/developers/gitignore?templates=sublimetext
|
||||
|
||||
### SublimeText ###
|
||||
# Cache files for Sublime Text
|
||||
*.tmlanguage.cache
|
||||
*.tmPreferences.cache
|
||||
*.stTheme.cache
|
||||
|
||||
# Workspace files are user-specific
|
||||
*.sublime-workspace
|
||||
|
||||
# Project files should be checked into the repository, unless a significant
|
||||
# proportion of contributors will probably not be using Sublime Text
|
||||
*.sublime-project
|
||||
|
||||
# SFTP configuration file
|
||||
sftp-config.json
|
||||
sftp-config-alt*.json
|
||||
|
||||
# Package control specific files
|
||||
Package Control.last-run
|
||||
Package Control.ca-list
|
||||
Package Control.ca-bundle
|
||||
Package Control.system-ca-bundle
|
||||
Package Control.cache/
|
||||
Package Control.ca-certs/
|
||||
Package Control.merged-ca-bundle
|
||||
Package Control.user-ca-bundle
|
||||
oscrypto-ca-bundle.crt
|
||||
bh_unicode_properties.cache
|
||||
|
||||
# Sublime-github package stores a github token in this file
|
||||
# https://packagecontrol.io/packages/sublime-github
|
||||
GitHub.sublime-settings
|
||||
|
||||
# End of https://www.toptal.com/developers/gitignore/api/sublimetext
|
||||
|
||||
# Created by https://www.gitignore.io/api/c,c++
|
||||
|
||||
### C ###
|
||||
# Prerequisites
|
||||
*.d
|
||||
|
||||
# Object files
|
||||
*.o
|
||||
*.ko
|
||||
*.obj
|
||||
*.elf
|
||||
|
||||
# Linker output
|
||||
*.ilk
|
||||
*.map
|
||||
*.exp
|
||||
|
||||
# Precompiled Headers
|
||||
*.gch
|
||||
*.pch
|
||||
|
||||
# Libraries
|
||||
*.lib
|
||||
*.a
|
||||
*.la
|
||||
*.lo
|
||||
|
||||
# Shared objects (inc. Windows DLLs)
|
||||
*.dll
|
||||
*.so
|
||||
*.so.*
|
||||
*.dylib
|
||||
|
||||
# Executables
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
*.i*86
|
||||
*.x86_64
|
||||
*.hex
|
||||
|
||||
# Debug files
|
||||
*.dSYM/
|
||||
*.su
|
||||
*.idb
|
||||
*.pdb
|
||||
|
||||
# Kernel Module Compile Results
|
||||
*.mod*
|
||||
*.cmd
|
||||
.tmp_versions/
|
||||
modules.order
|
||||
Module.symvers
|
||||
Mkfile.old
|
||||
dkms.conf
|
||||
|
||||
### C++ ###
|
||||
# Prerequisites
|
||||
|
||||
# Compiled Object files
|
||||
*.slo
|
||||
|
||||
# Precompiled Headers
|
||||
|
||||
# Compiled Dynamic libraries
|
||||
|
||||
# Fortran module files
|
||||
*.mod
|
||||
*.smod
|
||||
|
||||
# Compiled Static libraries
|
||||
*.lai
|
||||
|
||||
# Executables
|
||||
|
||||
|
||||
# End of https://www.gitignore.io/api/c,c++
|
||||
|
||||
# Created by https://www.gitignore.io/api/visualstudiocode
|
||||
|
||||
### VisualStudioCode ###
|
||||
.vscode/*
|
||||
|
||||
|
||||
# End of https://www.gitignore.io/api/visualstudiocode
|
||||
|
||||
# Created by https://www.gitignore.io/api/premake-gmake
|
||||
|
||||
### premake-gmake ###
|
||||
Makefile
|
||||
*.make
|
||||
obj/
|
||||
|
||||
|
||||
# End of https://www.gitignore.io/api/premake-gmake
|
||||
|
||||
|
||||
# Created by https://www.gitignore.io/api/visualstudio
|
||||
# Edit at https://www.gitignore.io/?templates=visualstudio
|
||||
|
||||
### VisualStudio ###
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
##
|
||||
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
||||
|
||||
# User-specific files
|
||||
*.rsuser
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
|
||||
# Mono auto generated files
|
||||
mono_crash.*
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
x64/
|
||||
x86/
|
||||
[Aa][Rr][Mm]/
|
||||
[Aa][Rr][Mm]64/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Ll]og/
|
||||
|
||||
# Visual Studio 2015/2017 cache/options directory
|
||||
.vs/
|
||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||
#wwwroot/
|
||||
|
||||
# Visual Studio 2017 auto generated files
|
||||
Generated\ Files/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
||||
# NUnit
|
||||
*.VisualState.xml
|
||||
TestResult.xml
|
||||
nunit-*.xml
|
||||
|
||||
# Build Results of an ATL Project
|
||||
[Dd]ebugPS/
|
||||
[Rr]eleasePS/
|
||||
dlldata.c
|
||||
|
||||
# Benchmark Results
|
||||
BenchmarkDotNet.Artifacts/
|
||||
|
||||
# .NET Core
|
||||
project.lock.json
|
||||
project.fragment.lock.json
|
||||
artifacts/
|
||||
|
||||
# StyleCop
|
||||
StyleCopReport.xml
|
||||
|
||||
# Files built by Visual Studio
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_h.h
|
||||
*.ilk
|
||||
*.obj
|
||||
*.iobj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.ipdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*_wpftmp.csproj
|
||||
*.log
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.svclog
|
||||
*.scc
|
||||
|
||||
# Chutzpah Test files
|
||||
_Chutzpah*
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opendb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
*.VC.db
|
||||
*.VC.VC.opendb
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
*.sap
|
||||
|
||||
# Visual Studio Trace Files
|
||||
*.e2e
|
||||
|
||||
# TFS 2012 Local Workspace
|
||||
$tf/
|
||||
|
||||
# Guidance Automation Toolkit
|
||||
*.gpState
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
*.DotSettings.user
|
||||
|
||||
# JustCode is a .NET coding add-in
|
||||
.JustCode
|
||||
|
||||
# TeamCity is a build add-in
|
||||
_TeamCity*
|
||||
|
||||
# DotCover is a Code Coverage Tool
|
||||
*.dotCover
|
||||
|
||||
# AxoCover is a Code Coverage Tool
|
||||
.axoCover/*
|
||||
!.axoCover/settings.json
|
||||
|
||||
# Visual Studio code coverage results
|
||||
*.coverage
|
||||
*.coveragexml
|
||||
|
||||
# NCrunch
|
||||
_NCrunch_*
|
||||
.*crunch*.local.xml
|
||||
nCrunchTemp_*
|
||||
|
||||
# MightyMoose
|
||||
*.mm.*
|
||||
AutoTest.Net/
|
||||
|
||||
# Web workbench (sass)
|
||||
.sass-cache/
|
||||
|
||||
# Installshield output folder
|
||||
[Ee]xpress/
|
||||
|
||||
# DocProject is a documentation generator add-in
|
||||
DocProject/buildhelp/
|
||||
DocProject/Help/*.HxT
|
||||
DocProject/Help/*.HxC
|
||||
DocProject/Help/*.hhc
|
||||
DocProject/Help/*.hhk
|
||||
DocProject/Help/*.hhp
|
||||
DocProject/Help/Html2
|
||||
DocProject/Help/html
|
||||
|
||||
# Click-Once directory
|
||||
publish/
|
||||
|
||||
# Publish Web Output
|
||||
*.[Pp]ublish.xml
|
||||
*.azurePubxml
|
||||
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||
# but database connection strings (with potential passwords) will be unencrypted
|
||||
*.pubxml
|
||||
*.publishproj
|
||||
|
||||
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||
# in these scripts will be unencrypted
|
||||
PublishScripts/
|
||||
|
||||
# NuGet Packages
|
||||
*.nupkg
|
||||
# NuGet Symbol Packages
|
||||
*.snupkg
|
||||
# The packages folder can be ignored because of Package Restore
|
||||
**/[Pp]ackages/*
|
||||
# except build/, which is used as an MSBuild target.
|
||||
!**/[Pp]ackages/build/
|
||||
# Uncomment if necessary however generally it will be regenerated when needed
|
||||
#!**/[Pp]ackages/repositories.config
|
||||
# NuGet v3's project.json files produces more ignorable files
|
||||
*.nuget.props
|
||||
*.nuget.targets
|
||||
|
||||
# Microsoft Azure Build Output
|
||||
csx/
|
||||
*.build.csdef
|
||||
|
||||
# Microsoft Azure Emulator
|
||||
ecf/
|
||||
rcf/
|
||||
|
||||
# Windows Store app package directories and files
|
||||
AppPackages/
|
||||
BundleArtifacts/
|
||||
Package.StoreAssociation.xml
|
||||
_pkginfo.txt
|
||||
*.appx
|
||||
*.appxbundle
|
||||
*.appxupload
|
||||
|
||||
# Visual Studio cache files
|
||||
# files ending in .cache can be ignored
|
||||
*.[Cc]ache
|
||||
# but keep track of directories ending in .cache
|
||||
!?*.[Cc]ache/
|
||||
|
||||
# Others
|
||||
ClientBin/
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.dbproj.schemaview
|
||||
*.jfm
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
orleans.codegen.cs
|
||||
|
||||
# Including strong name files can present a security risk
|
||||
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||
#*.snk
|
||||
|
||||
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||
#bower_components/
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
# Backup & report files from converting an old project file
|
||||
# to a newer Visual Studio version. Backup files are not needed,
|
||||
# because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
UpgradeLog*.htm
|
||||
ServiceFabricBackup/
|
||||
*.rptproj.bak
|
||||
|
||||
# SQL Server files
|
||||
*.mdf
|
||||
*.ldf
|
||||
*.ndf
|
||||
|
||||
# Business Intelligence projects
|
||||
*.rdl.data
|
||||
*.bim.layout
|
||||
*.bim_*.settings
|
||||
*.rptproj.rsuser
|
||||
*- [Bb]ackup.rdl
|
||||
*- [Bb]ackup ([0-9]).rdl
|
||||
*- [Bb]ackup ([0-9][0-9]).rdl
|
||||
|
||||
# Microsoft Fakes
|
||||
FakesAssemblies/
|
||||
|
||||
# GhostDoc plugin setting file
|
||||
*.GhostDoc.xml
|
||||
|
||||
# Node.js Tools for Visual Studio
|
||||
.ntvs_analysis.dat
|
||||
node_modules/
|
||||
|
||||
# Visual Studio 6 build log
|
||||
*.plg
|
||||
|
||||
# Visual Studio 6 workspace options file
|
||||
*.opt
|
||||
|
||||
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||
*.vbw
|
||||
|
||||
# Visual Studio LightSwitch build output
|
||||
**/*.HTMLClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/ModelManifest.xml
|
||||
**/*.Server/GeneratedArtifacts
|
||||
**/*.Server/ModelManifest.xml
|
||||
_Pvt_Extensions
|
||||
|
||||
# Paket dependency manager
|
||||
.paket/paket.exe
|
||||
paket-files/
|
||||
|
||||
# FAKE - F# Make
|
||||
.fake/
|
||||
|
||||
# CodeRush personal settings
|
||||
.cr/personal
|
||||
|
||||
# Python Tools for Visual Studio (PTVS)
|
||||
__pycache__/
|
||||
*.pyc
|
||||
|
||||
# Cake - Uncomment if you are using it
|
||||
# tools/**
|
||||
# !tools/packages.config
|
||||
|
||||
# Tabs Studio
|
||||
*.tss
|
||||
|
||||
# Telerik's JustMock configuration file
|
||||
*.jmconfig
|
||||
|
||||
# BizTalk build output
|
||||
*.btp.cs
|
||||
*.btm.cs
|
||||
*.odx.cs
|
||||
*.xsd.cs
|
||||
|
||||
# OpenCover UI analysis results
|
||||
OpenCover/
|
||||
|
||||
# Azure Stream Analytics local run output
|
||||
ASALocalRun/
|
||||
|
||||
# MSBuild Binary and Structured Log
|
||||
*.binlog
|
||||
|
||||
# NVidia Nsight GPU debugger configuration file
|
||||
*.nvuser
|
||||
|
||||
# MFractors (Xamarin productivity tool) working folder
|
||||
.mfractor/
|
||||
|
||||
# Local History for Visual Studio
|
||||
.localhistory/
|
||||
|
||||
# BeatPulse healthcheck temp database
|
||||
healthchecksdb
|
||||
|
||||
# Backup folder for Package Reference Convert tool in Visual Studio 2017
|
||||
MigrationBackup/
|
||||
|
||||
# End of https://www.gitignore.io/api/visualstudio
|
||||
|
||||
# Created by https://www.toptal.com/developers/gitignore/api/vcpkg
|
||||
# Edit at https://www.toptal.com/developers/gitignore?templates=vcpkg
|
||||
|
||||
### vcpkg ###
|
||||
# Vcpkg
|
||||
|
||||
## Manifest Mode
|
||||
vcpkg_installed/
|
||||
|
||||
# End of https://www.toptal.com/developers/gitignore/api/vcpkg
|
||||
|
||||
|
||||
# Created by https://www.toptal.com/developers/gitignore/api/cmake
|
||||
# Edit at https://www.toptal.com/developers/gitignore?templates=cmake
|
||||
|
||||
### CMake ###
|
||||
CMakeLists.txt.user
|
||||
CMakeCache.txt
|
||||
CMakeFiles
|
||||
CMakeScripts
|
||||
Testing
|
||||
Makefile
|
||||
cmake_install.cmake
|
||||
install_manifest.txt
|
||||
compile_commands.json
|
||||
CTestTestfile.cmake
|
||||
_deps
|
||||
|
||||
### CMake Patch ###
|
||||
# External projects
|
||||
*-prefix/
|
||||
|
||||
# End of https://www.toptal.com/developers/gitignore/api/cmake
|
||||
3
Lib/imnodes-master-b2ec254/.gitmodules
vendored
Normal file
3
Lib/imnodes-master-b2ec254/.gitmodules
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
[submodule "vcpkg"]
|
||||
path = vcpkg
|
||||
url = https://github.com/microsoft/vcpkg.git
|
||||
107
Lib/imnodes-master-b2ec254/CMakeLists.txt
Normal file
107
Lib/imnodes-master-b2ec254/CMakeLists.txt
Normal file
@ -0,0 +1,107 @@
|
||||
cmake_minimum_required(VERSION 3.15)
|
||||
|
||||
project(imnodes)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED True)
|
||||
|
||||
|
||||
# determine whether this is a standalone project or included by other projects
|
||||
if (NOT DEFINED IMNODES_STANDALONE_PROJECT)
|
||||
if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
|
||||
set(IMNODES_STANDALONE_PROJECT ON)
|
||||
else()
|
||||
set(IMNODES_STANDALONE_PROJECT OFF)
|
||||
endif ()
|
||||
endif()
|
||||
|
||||
# cmake options
|
||||
option(IMNODES_EXAMPLES "Build examples" ${IMNODES_STANDALONE_PROJECT})
|
||||
|
||||
# allow custom imgui target name since this can vary because imgui doesn't natively include a CMakeLists.txt
|
||||
if(NOT DEFINED IMNODES_IMGUI_TARGET_NAME)
|
||||
find_package(imgui CONFIG REQUIRED)
|
||||
set(IMNODES_IMGUI_TARGET_NAME imgui::imgui)
|
||||
endif()
|
||||
|
||||
|
||||
if(MSVC)
|
||||
add_compile_definitions(SDL_MAIN_HANDLED)
|
||||
add_compile_options(/WX)
|
||||
# replace existing /W to avoid warning
|
||||
if(CMAKE_CXX_FLAGS MATCHES "/W[0-4]")
|
||||
string(REGEX REPLACE "/W[0-4]" "/W4" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
||||
else()
|
||||
add_compile_options(/W4)
|
||||
endif()
|
||||
else()
|
||||
add_compile_options(-Wall -Wextra -Wpedantic -Werror)
|
||||
endif()
|
||||
|
||||
# Imnodes
|
||||
|
||||
add_library(imnodes)
|
||||
target_sources(imnodes PRIVATE
|
||||
imnodes.h
|
||||
imnodes_internal.h
|
||||
imnodes.cpp)
|
||||
target_include_directories(imnodes PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
target_link_libraries(imnodes PUBLIC ${IMNODES_IMGUI_TARGET_NAME})
|
||||
|
||||
# Example projects
|
||||
if(IMNODES_EXAMPLES)
|
||||
|
||||
find_package(SDL2 CONFIG REQUIRED)
|
||||
|
||||
add_executable(colornode
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/imnodes.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/example/main.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/example/color_node_editor.cpp)
|
||||
target_link_libraries(colornode imnodes SDL2::SDL2)
|
||||
if (APPLE)
|
||||
target_link_libraries(colornode "-framework OpenGL")
|
||||
elseif(MSVC)
|
||||
target_link_libraries(colornode "opengl32")
|
||||
else()
|
||||
target_link_libraries(colornode X11 Xext GL)
|
||||
endif()
|
||||
|
||||
add_executable(multieditor
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/imnodes.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/example/main.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/example/multi_editor.cpp)
|
||||
target_link_libraries(multieditor imnodes SDL2::SDL2)
|
||||
if (APPLE)
|
||||
target_link_libraries(multieditor "-framework OpenGL")
|
||||
elseif(MSVC)
|
||||
target_link_libraries(multieditor "opengl32")
|
||||
else()
|
||||
target_link_libraries(multieditor X11 Xext GL)
|
||||
endif()
|
||||
|
||||
add_executable(saveload
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/imnodes.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/example/main.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/example/save_load.cpp)
|
||||
target_link_libraries(saveload imnodes SDL2::SDL2)
|
||||
if (APPLE)
|
||||
target_link_libraries(saveload "-framework OpenGL")
|
||||
elseif(MSVC)
|
||||
target_link_libraries(saveload "opengl32")
|
||||
else()
|
||||
target_link_libraries(saveload X11 Xext GL)
|
||||
endif()
|
||||
|
||||
add_executable(hello
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/imnodes.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/example/main.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/example/hello.cpp)
|
||||
target_link_libraries(hello imnodes SDL2::SDL2)
|
||||
if (APPLE)
|
||||
target_link_libraries(hello "-framework OpenGL")
|
||||
elseif(MSVC)
|
||||
target_link_libraries(hello "opengl32")
|
||||
else()
|
||||
target_link_libraries(hello X11 Xext GL)
|
||||
endif()
|
||||
endif()
|
||||
21
Lib/imnodes-master-b2ec254/LICENSE.md
Normal file
21
Lib/imnodes-master-b2ec254/LICENSE.md
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019 Johann Muszynski
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
264
Lib/imnodes-master-b2ec254/README.md
Normal file
264
Lib/imnodes-master-b2ec254/README.md
Normal file
@ -0,0 +1,264 @@
|
||||
<h1 align="center">imnodes</h1>
|
||||
|
||||
<p align="center">A small, dependency-free node editor extension for <a href="https://github.com/ocornut/imgui">dear imgui</a>.</p>
|
||||
|
||||
<p align="center">
|
||||
<img src="https://raw.githubusercontent.com/Nelarius/imnodes/master/img/imnodes.gif?token=ADH_jEpqbBrw0nH-BUmOip490dyO2CnRks5cVZllwA%3D%3D">
|
||||
</p>
|
||||
|
||||
[](https://github.com/nelarius/imnodes/actions?workflow=Build)
|
||||
|
||||
Imnodes aims to provide a simple, immediate-mode interface for creating a node editor within an ImGui window. Imnodes provides simple, customizable building blocks that a user needs to build their node editor.
|
||||
|
||||
Features:
|
||||
|
||||
* Create nodes, links, and pins in an immediate-mode style. The user controls all the state.
|
||||
* Nest ImGui widgets inside nodes
|
||||
* Simple distribution, just copy-paste `imnodes.h`, `imnodes_internal.h`, and `imnodes.cpp` into your project along side ImGui.
|
||||
|
||||
## Examples
|
||||
|
||||
This repository includes a few example files, under `example/`. They are intended as simple examples giving you an idea of what you can build with imnodes.
|
||||
|
||||
If you need to build the examples, you can use the provided CMake script to do so.
|
||||
|
||||
```bash
|
||||
# Initialize the vcpkg submodule
|
||||
$ git submodule update --init
|
||||
# Run the generation step and build
|
||||
$ cmake -B build-release/ -S . -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=vcpkg/scripts/buildsystems/vcpkg.cmake
|
||||
$ cmake --build build-release -- -j
|
||||
```
|
||||
|
||||
Note that this has not been tested on Linux and is likely to fail on the platform.
|
||||
|
||||
## A brief tour
|
||||
|
||||
Here is a small overview of how the extension is used. For more information on example usage, scroll to the bottom of the README.
|
||||
|
||||
Before anything can be done, the library must be initialized. This can be done at the same time as `dear imgui` initialization.
|
||||
|
||||
```cpp
|
||||
ImGui::CreateContext();
|
||||
ImNodes::CreateContext();
|
||||
|
||||
// elsewhere in the code...
|
||||
ImNodes::DestroyContext();
|
||||
ImGui::DestroyContext();
|
||||
```
|
||||
|
||||
The node editor is a workspace which contains nodes. The node editor must be instantiated within a window, like any other UI element.
|
||||
|
||||
```cpp
|
||||
ImGui::Begin("node editor");
|
||||
|
||||
ImNodes::BeginNodeEditor();
|
||||
ImNodes::EndNodeEditor();
|
||||
|
||||
ImGui::End();
|
||||
```
|
||||
|
||||
Now you should have a workspace with a grid visible in the window. An empty node can now be instantiated:
|
||||
|
||||
```cpp
|
||||
const int hardcoded_node_id = 1;
|
||||
|
||||
ImNodes::BeginNodeEditor();
|
||||
|
||||
ImNodes::BeginNode(hardcoded_node_id);
|
||||
ImGui::Dummy(ImVec2(80.0f, 45.0f));
|
||||
ImNodes::EndNode();
|
||||
|
||||
ImNodes::EndNodeEditor();
|
||||
```
|
||||
|
||||
Nodes, like windows in `dear imgui` must be uniquely identified. But we can't use the node titles for identification, because it should be possible to have many nodes of the same name in the workspace. Instead, you just use integers for identification.
|
||||
|
||||
Attributes are the UI content of the node. An attribute will have a pin (the little circle) on either side of the node. There are two types of attributes: input, and output attributes. Input attribute pins are on the left side of the node, and output attribute pins are on the right. Like nodes, pins must be uniquely identified.
|
||||
|
||||
```cpp
|
||||
ImNodes::BeginNode(hardcoded_node_id);
|
||||
|
||||
const int output_attr_id = 2;
|
||||
ImNodes::BeginOutputAttribute(output_attr_id);
|
||||
// in between Begin|EndAttribute calls, you can call ImGui
|
||||
// UI functions
|
||||
ImGui::Text("output pin");
|
||||
ImNodes::EndOutputAttribute();
|
||||
|
||||
ImNodes::EndNode();
|
||||
```
|
||||
|
||||
The extension doesn't really care what is in the attribute. It just renders the pin for the attribute, and allows the user to create links between pins.
|
||||
|
||||
A title bar can be added to the node using `BeginNodeTitleBar` and `EndNodeTitleBar`. Like attributes, you place your title bar's content between the function calls. Note that these functions have to be called before adding attributes or other `dear imgui` UI elements to the node, since the node's layout is built in order, top-to-bottom.
|
||||
|
||||
```cpp
|
||||
ImNodes::BeginNode(hardcoded_node_id);
|
||||
|
||||
ImNodes::BeginNodeTitleBar();
|
||||
ImGui::TextUnformatted("output node");
|
||||
ImNodes::EndNodeTitleBar();
|
||||
|
||||
// pins and other node UI content omitted...
|
||||
|
||||
ImNodes::EndNode();
|
||||
```
|
||||
|
||||
The user has to render their own links between nodes as well. A link is a curve which connects two attributes. A link is just a pair of attribute ids. And like nodes and attributes, links too have to be identified by unique integer values:
|
||||
|
||||
```cpp
|
||||
std::vector<std::pair<int, int>> links;
|
||||
// elsewhere in the code...
|
||||
for (int i = 0; i < links.size(); ++i)
|
||||
{
|
||||
const std::pair<int, int> p = links[i];
|
||||
// in this case, we just use the array index of the link
|
||||
// as the unique identifier
|
||||
ImNodes::Link(i, p.first, p.second);
|
||||
}
|
||||
```
|
||||
|
||||
After `EndNodeEditor` has been called, you can check if a link was created during the frame with the function call `IsLinkCreated`:
|
||||
|
||||
```cpp
|
||||
int start_attr, end_attr;
|
||||
if (ImNodes::IsLinkCreated(&start_attr, &end_attr))
|
||||
{
|
||||
links.push_back(std::make_pair(start_attr, end_attr));
|
||||
}
|
||||
```
|
||||
|
||||
In addition to checking for new links, you can also check whether UI elements are being hovered over by the mouse cursor:
|
||||
|
||||
```cpp
|
||||
int node_id;
|
||||
if (ImNodes::IsNodeHovered(&node_id))
|
||||
{
|
||||
node_hovered = node_id;
|
||||
}
|
||||
```
|
||||
|
||||
You can also check to see if any node has been selected. Nodes can be clicked on, or they can be selected by clicking and dragging the box selector over them.
|
||||
|
||||
```cpp
|
||||
// Note that since many nodes can be selected at once, we first need to query the number of
|
||||
// selected nodes before getting them.
|
||||
const int num_selected_nodes = ImNodes::NumSelectedNodes();
|
||||
if (num_selected_nodes > 0)
|
||||
{
|
||||
std::vector<int> selected_nodes;
|
||||
selected_nodes.resize(num_selected_nodes);
|
||||
ImNodes::GetSelectedNodes(selected_nodes.data());
|
||||
}
|
||||
```
|
||||
|
||||
See `imnodes.h` for more UI event-related functions.
|
||||
|
||||
Like `dear imgui`, the style of the UI can be changed. You can set the color style of individual nodes, pins, and links mid-frame by calling `ImNodes::PushColorStyle` and `ImNodes::PopColorStyle`.
|
||||
|
||||
```cpp
|
||||
// set the titlebar color of an individual node
|
||||
ImNodes::PushColorStyle(
|
||||
ImNodesCol_TitleBar, IM_COL32(11, 109, 191, 255));
|
||||
ImNodes::PushColorStyle(
|
||||
ImNodesCol_TitleBarSelected, IM_COL32(81, 148, 204, 255));
|
||||
|
||||
ImNodes::BeginNode(hardcoded_node_id);
|
||||
// node internals here...
|
||||
ImNodes::EndNode();
|
||||
|
||||
ImNodes::PopColorStyle();
|
||||
ImNodes::PopColorStyle();
|
||||
```
|
||||
|
||||
If the style is not being set mid-frame, `ImNodes::GetStyle` can be called instead, and the values can be set into the style array directly.
|
||||
|
||||
```cpp
|
||||
// set the titlebar color for all nodes
|
||||
ImNodesStyle& style = ImNodes::GetStyle();
|
||||
style.colors[ImNodesCol_TitleBar] = IM_COL32(232, 27, 86, 255);
|
||||
style.colors[ImNodesCol_TitleBarSelected] = IM_COL32(241, 108, 146, 255);
|
||||
```
|
||||
|
||||
To handle quicker navigation of large graphs you can use an interactive mini-map overlay. The mini-map can be zoomed and scrolled. Editor nodes will track the panning of the mini-map accordingly.
|
||||
|
||||
```cpp
|
||||
ImGui::Begin("node editor");
|
||||
|
||||
ImNodes::BeginNodeEditor();
|
||||
|
||||
// add nodes...
|
||||
|
||||
// must be called right before EndNodeEditor
|
||||
ImNodes::MiniMap();
|
||||
ImNodes::EndNodeEditor();
|
||||
|
||||
ImGui::End();
|
||||
```
|
||||
|
||||
The relative sizing and corner location of the mini-map in the editor space can be specified like so:
|
||||
|
||||
```cpp
|
||||
// MiniMap is a square region with a side length that is 20% the largest editor canvas dimension
|
||||
// See ImNodesMiniMapLocation_ for other corner locations
|
||||
ImNodes::MiniMap(0.2f, ImNodesMiniMapLocation_TopRight);
|
||||
```
|
||||
|
||||
The mini-map also supports limited node hovering customization through a user-defined callback.
|
||||
```cpp
|
||||
// User callback
|
||||
void mini_map_node_hovering_callback(int node_id, void* user_data)
|
||||
{
|
||||
ImGui::SetTooltip("This is node %d", node_id);
|
||||
}
|
||||
|
||||
// Later on...
|
||||
ImNodes::MiniMap(0.2f, ImNodesMiniMapLocation_TopRight, mini_map_node_hovering_callback, custom_user_data);
|
||||
|
||||
// 'custom_user_data' can be used to supply extra information needed for drawing within the callback
|
||||
```
|
||||
|
||||
## Customizing ImNodes
|
||||
|
||||
ImNodes can be customized by providing an `imnodes_config.h` header and specifying defining `IMNODES_USER_CONFIG=imnodes_config.h` when compiling.
|
||||
|
||||
It is currently possible to override the type of the minimap hovering callback function. This is useful when generating bindings for another language.
|
||||
|
||||
Here's an example imnodes_config.h, which generates a pybind wrapper for the callback.
|
||||
```cpp
|
||||
#pragma once
|
||||
|
||||
#include <pybind11/functional.h>
|
||||
|
||||
namespace pybind11 {
|
||||
|
||||
inline bool PyWrapper_Check(PyObject *o) { return true; }
|
||||
|
||||
class wrapper : public object {
|
||||
public:
|
||||
PYBIND11_OBJECT_DEFAULT(wrapper, object, PyWrapper_Check)
|
||||
wrapper(void* x) { m_ptr = (PyObject*)x; }
|
||||
explicit operator bool() const { return m_ptr != nullptr && m_ptr != Py_None; }
|
||||
};
|
||||
|
||||
} //namespace pybind11
|
||||
|
||||
namespace py = pybind11;
|
||||
|
||||
#define ImNodesMiniMapNodeHoveringCallback py::wrapper
|
||||
|
||||
#define ImNodesMiniMapNodeHoveringCallbackUserData py::wrapper
|
||||
```
|
||||
|
||||
## Known issues
|
||||
|
||||
* `ImGui::Separator()` spans the current window span. As a result, using a separator inside a node will result in the separator spilling out of the node into the node editor grid.
|
||||
|
||||
## Further information
|
||||
|
||||
See the `examples/` directory to see library usage in greater detail.
|
||||
|
||||
* simple.cpp is a simple hello-world style program which displays two nodes
|
||||
* save_load.cpp is enables you to add and remove nodes and links, and serializes/deserializes them, so that the program state is retained between restarting the program
|
||||
* color_node_editor.cpp is a more complete example, which shows how a simple node editor is implemented with a graph.
|
||||
715
Lib/imnodes-master-b2ec254/example/color_node_editor.cpp
Normal file
715
Lib/imnodes-master-b2ec254/example/color_node_editor.cpp
Normal file
@ -0,0 +1,715 @@
|
||||
#include "node_editor.h"
|
||||
#include "graph.h"
|
||||
|
||||
#include <imnodes.h>
|
||||
#include <imgui.h>
|
||||
|
||||
#include <SDL2/SDL_timer.h>
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <chrono>
|
||||
#include <cmath>
|
||||
#include <vector>
|
||||
|
||||
namespace example
|
||||
{
|
||||
namespace
|
||||
{
|
||||
enum class NodeType
|
||||
{
|
||||
add,
|
||||
multiply,
|
||||
output,
|
||||
sine,
|
||||
time,
|
||||
value
|
||||
};
|
||||
|
||||
struct Node
|
||||
{
|
||||
NodeType type;
|
||||
float value;
|
||||
|
||||
explicit Node(const NodeType t) : type(t), value(0.f) {}
|
||||
|
||||
Node(const NodeType t, const float v) : type(t), value(v) {}
|
||||
};
|
||||
|
||||
template<class T>
|
||||
T clamp(T x, T a, T b)
|
||||
{
|
||||
return std::min(b, std::max(x, a));
|
||||
}
|
||||
|
||||
static float current_time_seconds = 0.f;
|
||||
static bool emulate_three_button_mouse = false;
|
||||
|
||||
ImU32 evaluate(const Graph<Node>& graph, const int root_node)
|
||||
{
|
||||
std::stack<int> postorder;
|
||||
dfs_traverse(
|
||||
graph, root_node, [&postorder](const int node_id) -> void { postorder.push(node_id); });
|
||||
|
||||
std::stack<float> value_stack;
|
||||
while (!postorder.empty())
|
||||
{
|
||||
const int id = postorder.top();
|
||||
postorder.pop();
|
||||
const Node node = graph.node(id);
|
||||
|
||||
switch (node.type)
|
||||
{
|
||||
case NodeType::add:
|
||||
{
|
||||
const float rhs = value_stack.top();
|
||||
value_stack.pop();
|
||||
const float lhs = value_stack.top();
|
||||
value_stack.pop();
|
||||
value_stack.push(lhs + rhs);
|
||||
}
|
||||
break;
|
||||
case NodeType::multiply:
|
||||
{
|
||||
const float rhs = value_stack.top();
|
||||
value_stack.pop();
|
||||
const float lhs = value_stack.top();
|
||||
value_stack.pop();
|
||||
value_stack.push(rhs * lhs);
|
||||
}
|
||||
break;
|
||||
case NodeType::sine:
|
||||
{
|
||||
const float x = value_stack.top();
|
||||
value_stack.pop();
|
||||
const float res = std::abs(std::sin(x));
|
||||
value_stack.push(res);
|
||||
}
|
||||
break;
|
||||
case NodeType::time:
|
||||
{
|
||||
value_stack.push(current_time_seconds);
|
||||
}
|
||||
break;
|
||||
case NodeType::value:
|
||||
{
|
||||
// If the edge does not have an edge connecting to another node, then just use the value
|
||||
// at this node. It means the node's input pin has not been connected to anything and
|
||||
// the value comes from the node's UI.
|
||||
if (graph.num_edges_from_node(id) == 0ull)
|
||||
{
|
||||
value_stack.push(node.value);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// The final output node isn't evaluated in the loop -- instead we just pop
|
||||
// the three values which should be in the stack.
|
||||
assert(value_stack.size() == 3ull);
|
||||
const int b = static_cast<int>(255.f * clamp(value_stack.top(), 0.f, 1.f) + 0.5f);
|
||||
value_stack.pop();
|
||||
const int g = static_cast<int>(255.f * clamp(value_stack.top(), 0.f, 1.f) + 0.5f);
|
||||
value_stack.pop();
|
||||
const int r = static_cast<int>(255.f * clamp(value_stack.top(), 0.f, 1.f) + 0.5f);
|
||||
value_stack.pop();
|
||||
|
||||
return IM_COL32(r, g, b, 255);
|
||||
}
|
||||
|
||||
class ColorNodeEditor
|
||||
{
|
||||
public:
|
||||
ColorNodeEditor()
|
||||
: graph_(), nodes_(), root_node_id_(-1),
|
||||
minimap_location_(ImNodesMiniMapLocation_BottomRight)
|
||||
{
|
||||
}
|
||||
|
||||
void show()
|
||||
{
|
||||
// Update timer context
|
||||
current_time_seconds = 0.001f * SDL_GetTicks();
|
||||
|
||||
auto flags = ImGuiWindowFlags_MenuBar;
|
||||
|
||||
// The node editor window
|
||||
ImGui::Begin("color node editor", NULL, flags);
|
||||
|
||||
if (ImGui::BeginMenuBar())
|
||||
{
|
||||
if (ImGui::BeginMenu("Mini-map"))
|
||||
{
|
||||
const char* names[] = {
|
||||
"Top Left",
|
||||
"Top Right",
|
||||
"Bottom Left",
|
||||
"Bottom Right",
|
||||
};
|
||||
int locations[] = {
|
||||
ImNodesMiniMapLocation_TopLeft,
|
||||
ImNodesMiniMapLocation_TopRight,
|
||||
ImNodesMiniMapLocation_BottomLeft,
|
||||
ImNodesMiniMapLocation_BottomRight,
|
||||
};
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
bool selected = minimap_location_ == locations[i];
|
||||
if (ImGui::MenuItem(names[i], NULL, &selected))
|
||||
minimap_location_ = locations[i];
|
||||
}
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
if (ImGui::BeginMenu("Style"))
|
||||
{
|
||||
if (ImGui::MenuItem("Classic"))
|
||||
{
|
||||
ImGui::StyleColorsClassic();
|
||||
ImNodes::StyleColorsClassic();
|
||||
}
|
||||
if (ImGui::MenuItem("Dark"))
|
||||
{
|
||||
ImGui::StyleColorsDark();
|
||||
ImNodes::StyleColorsDark();
|
||||
}
|
||||
if (ImGui::MenuItem("Light"))
|
||||
{
|
||||
ImGui::StyleColorsLight();
|
||||
ImNodes::StyleColorsLight();
|
||||
}
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
ImGui::EndMenuBar();
|
||||
}
|
||||
|
||||
ImGui::TextUnformatted("Edit the color of the output color window using nodes.");
|
||||
ImGui::Columns(2);
|
||||
ImGui::TextUnformatted("A -- add node");
|
||||
ImGui::TextUnformatted("X -- delete selected node or link");
|
||||
ImGui::NextColumn();
|
||||
if (ImGui::Checkbox("emulate_three_button_mouse", &emulate_three_button_mouse))
|
||||
{
|
||||
ImNodes::GetIO().EmulateThreeButtonMouse.Modifier =
|
||||
emulate_three_button_mouse ? &ImGui::GetIO().KeyAlt : NULL;
|
||||
}
|
||||
ImGui::Columns(1);
|
||||
|
||||
ImNodes::BeginNodeEditor();
|
||||
|
||||
// Handle new nodes
|
||||
// These are driven by the user, so we place this code before rendering the nodes
|
||||
{
|
||||
const bool open_popup = ImGui::IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows) &&
|
||||
ImNodes::IsEditorHovered() && ImGui::IsKeyReleased(ImGuiKey_A);
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(8.f, 8.f));
|
||||
if (!ImGui::IsAnyItemHovered() && open_popup)
|
||||
{
|
||||
ImGui::OpenPopup("add node");
|
||||
}
|
||||
|
||||
if (ImGui::BeginPopup("add node"))
|
||||
{
|
||||
const ImVec2 click_pos = ImGui::GetMousePosOnOpeningCurrentPopup();
|
||||
|
||||
if (ImGui::MenuItem("add"))
|
||||
{
|
||||
const Node value(NodeType::value, 0.f);
|
||||
const Node op(NodeType::add);
|
||||
|
||||
UiNode ui_node;
|
||||
ui_node.type = UiNodeType::add;
|
||||
ui_node.ui.add.lhs = graph_.insert_node(value);
|
||||
ui_node.ui.add.rhs = graph_.insert_node(value);
|
||||
ui_node.id = graph_.insert_node(op);
|
||||
|
||||
graph_.insert_edge(ui_node.id, ui_node.ui.add.lhs);
|
||||
graph_.insert_edge(ui_node.id, ui_node.ui.add.rhs);
|
||||
|
||||
nodes_.push_back(ui_node);
|
||||
ImNodes::SetNodeScreenSpacePos(ui_node.id, click_pos);
|
||||
}
|
||||
|
||||
if (ImGui::MenuItem("multiply"))
|
||||
{
|
||||
const Node value(NodeType::value, 0.f);
|
||||
const Node op(NodeType::multiply);
|
||||
|
||||
UiNode ui_node;
|
||||
ui_node.type = UiNodeType::multiply;
|
||||
ui_node.ui.multiply.lhs = graph_.insert_node(value);
|
||||
ui_node.ui.multiply.rhs = graph_.insert_node(value);
|
||||
ui_node.id = graph_.insert_node(op);
|
||||
|
||||
graph_.insert_edge(ui_node.id, ui_node.ui.multiply.lhs);
|
||||
graph_.insert_edge(ui_node.id, ui_node.ui.multiply.rhs);
|
||||
|
||||
nodes_.push_back(ui_node);
|
||||
ImNodes::SetNodeScreenSpacePos(ui_node.id, click_pos);
|
||||
}
|
||||
|
||||
if (ImGui::MenuItem("output") && root_node_id_ == -1)
|
||||
{
|
||||
const Node value(NodeType::value, 0.f);
|
||||
const Node out(NodeType::output);
|
||||
|
||||
UiNode ui_node;
|
||||
ui_node.type = UiNodeType::output;
|
||||
ui_node.ui.output.r = graph_.insert_node(value);
|
||||
ui_node.ui.output.g = graph_.insert_node(value);
|
||||
ui_node.ui.output.b = graph_.insert_node(value);
|
||||
ui_node.id = graph_.insert_node(out);
|
||||
|
||||
graph_.insert_edge(ui_node.id, ui_node.ui.output.r);
|
||||
graph_.insert_edge(ui_node.id, ui_node.ui.output.g);
|
||||
graph_.insert_edge(ui_node.id, ui_node.ui.output.b);
|
||||
|
||||
nodes_.push_back(ui_node);
|
||||
ImNodes::SetNodeScreenSpacePos(ui_node.id, click_pos);
|
||||
root_node_id_ = ui_node.id;
|
||||
}
|
||||
|
||||
if (ImGui::MenuItem("sine"))
|
||||
{
|
||||
const Node value(NodeType::value, 0.f);
|
||||
const Node op(NodeType::sine);
|
||||
|
||||
UiNode ui_node;
|
||||
ui_node.type = UiNodeType::sine;
|
||||
ui_node.ui.sine.input = graph_.insert_node(value);
|
||||
ui_node.id = graph_.insert_node(op);
|
||||
|
||||
graph_.insert_edge(ui_node.id, ui_node.ui.sine.input);
|
||||
|
||||
nodes_.push_back(ui_node);
|
||||
ImNodes::SetNodeScreenSpacePos(ui_node.id, click_pos);
|
||||
}
|
||||
|
||||
if (ImGui::MenuItem("time"))
|
||||
{
|
||||
UiNode ui_node;
|
||||
ui_node.type = UiNodeType::time;
|
||||
ui_node.id = graph_.insert_node(Node(NodeType::time));
|
||||
|
||||
nodes_.push_back(ui_node);
|
||||
ImNodes::SetNodeScreenSpacePos(ui_node.id, click_pos);
|
||||
}
|
||||
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
ImGui::PopStyleVar();
|
||||
}
|
||||
|
||||
for (const UiNode& node : nodes_)
|
||||
{
|
||||
switch (node.type)
|
||||
{
|
||||
case UiNodeType::add:
|
||||
{
|
||||
const float node_width = 100.f;
|
||||
ImNodes::BeginNode(node.id);
|
||||
|
||||
ImNodes::BeginNodeTitleBar();
|
||||
ImGui::TextUnformatted("add");
|
||||
ImNodes::EndNodeTitleBar();
|
||||
{
|
||||
ImNodes::BeginInputAttribute(node.ui.add.lhs);
|
||||
const float label_width = ImGui::CalcTextSize("left").x;
|
||||
ImGui::TextUnformatted("left");
|
||||
if (graph_.num_edges_from_node(node.ui.add.lhs) == 0ull)
|
||||
{
|
||||
ImGui::SameLine();
|
||||
ImGui::PushItemWidth(node_width - label_width);
|
||||
ImGui::DragFloat("##hidelabel", &graph_.node(node.ui.add.lhs).value, 0.01f);
|
||||
ImGui::PopItemWidth();
|
||||
}
|
||||
ImNodes::EndInputAttribute();
|
||||
}
|
||||
|
||||
{
|
||||
ImNodes::BeginInputAttribute(node.ui.add.rhs);
|
||||
const float label_width = ImGui::CalcTextSize("right").x;
|
||||
ImGui::TextUnformatted("right");
|
||||
if (graph_.num_edges_from_node(node.ui.add.rhs) == 0ull)
|
||||
{
|
||||
ImGui::SameLine();
|
||||
ImGui::PushItemWidth(node_width - label_width);
|
||||
ImGui::DragFloat("##hidelabel", &graph_.node(node.ui.add.rhs).value, 0.01f);
|
||||
ImGui::PopItemWidth();
|
||||
}
|
||||
ImNodes::EndInputAttribute();
|
||||
}
|
||||
|
||||
ImGui::Spacing();
|
||||
|
||||
{
|
||||
ImNodes::BeginOutputAttribute(node.id);
|
||||
const float label_width = ImGui::CalcTextSize("result").x;
|
||||
ImGui::Indent(node_width - label_width);
|
||||
ImGui::TextUnformatted("result");
|
||||
ImNodes::EndOutputAttribute();
|
||||
}
|
||||
|
||||
ImNodes::EndNode();
|
||||
}
|
||||
break;
|
||||
case UiNodeType::multiply:
|
||||
{
|
||||
const float node_width = 100.0f;
|
||||
ImNodes::BeginNode(node.id);
|
||||
|
||||
ImNodes::BeginNodeTitleBar();
|
||||
ImGui::TextUnformatted("multiply");
|
||||
ImNodes::EndNodeTitleBar();
|
||||
|
||||
{
|
||||
ImNodes::BeginInputAttribute(node.ui.multiply.lhs);
|
||||
const float label_width = ImGui::CalcTextSize("left").x;
|
||||
ImGui::TextUnformatted("left");
|
||||
if (graph_.num_edges_from_node(node.ui.multiply.lhs) == 0ull)
|
||||
{
|
||||
ImGui::SameLine();
|
||||
ImGui::PushItemWidth(node_width - label_width);
|
||||
ImGui::DragFloat(
|
||||
"##hidelabel", &graph_.node(node.ui.multiply.lhs).value, 0.01f);
|
||||
ImGui::PopItemWidth();
|
||||
}
|
||||
ImNodes::EndInputAttribute();
|
||||
}
|
||||
|
||||
{
|
||||
ImNodes::BeginInputAttribute(node.ui.multiply.rhs);
|
||||
const float label_width = ImGui::CalcTextSize("right").x;
|
||||
ImGui::TextUnformatted("right");
|
||||
if (graph_.num_edges_from_node(node.ui.multiply.rhs) == 0ull)
|
||||
{
|
||||
ImGui::SameLine();
|
||||
ImGui::PushItemWidth(node_width - label_width);
|
||||
ImGui::DragFloat(
|
||||
"##hidelabel", &graph_.node(node.ui.multiply.rhs).value, 0.01f);
|
||||
ImGui::PopItemWidth();
|
||||
}
|
||||
ImNodes::EndInputAttribute();
|
||||
}
|
||||
|
||||
ImGui::Spacing();
|
||||
|
||||
{
|
||||
ImNodes::BeginOutputAttribute(node.id);
|
||||
const float label_width = ImGui::CalcTextSize("result").x;
|
||||
ImGui::Indent(node_width - label_width);
|
||||
ImGui::TextUnformatted("result");
|
||||
ImNodes::EndOutputAttribute();
|
||||
}
|
||||
|
||||
ImNodes::EndNode();
|
||||
}
|
||||
break;
|
||||
case UiNodeType::output:
|
||||
{
|
||||
const float node_width = 100.0f;
|
||||
ImNodes::PushColorStyle(ImNodesCol_TitleBar, IM_COL32(11, 109, 191, 255));
|
||||
ImNodes::PushColorStyle(ImNodesCol_TitleBarHovered, IM_COL32(45, 126, 194, 255));
|
||||
ImNodes::PushColorStyle(ImNodesCol_TitleBarSelected, IM_COL32(81, 148, 204, 255));
|
||||
ImNodes::BeginNode(node.id);
|
||||
|
||||
ImNodes::BeginNodeTitleBar();
|
||||
ImGui::TextUnformatted("output");
|
||||
ImNodes::EndNodeTitleBar();
|
||||
|
||||
ImGui::Dummy(ImVec2(node_width, 0.f));
|
||||
{
|
||||
ImNodes::BeginInputAttribute(node.ui.output.r);
|
||||
const float label_width = ImGui::CalcTextSize("r").x;
|
||||
ImGui::TextUnformatted("r");
|
||||
if (graph_.num_edges_from_node(node.ui.output.r) == 0ull)
|
||||
{
|
||||
ImGui::SameLine();
|
||||
ImGui::PushItemWidth(node_width - label_width);
|
||||
ImGui::DragFloat(
|
||||
"##hidelabel", &graph_.node(node.ui.output.r).value, 0.01f, 0.f, 1.0f);
|
||||
ImGui::PopItemWidth();
|
||||
}
|
||||
ImNodes::EndInputAttribute();
|
||||
}
|
||||
|
||||
ImGui::Spacing();
|
||||
|
||||
{
|
||||
ImNodes::BeginInputAttribute(node.ui.output.g);
|
||||
const float label_width = ImGui::CalcTextSize("g").x;
|
||||
ImGui::TextUnformatted("g");
|
||||
if (graph_.num_edges_from_node(node.ui.output.g) == 0ull)
|
||||
{
|
||||
ImGui::SameLine();
|
||||
ImGui::PushItemWidth(node_width - label_width);
|
||||
ImGui::DragFloat(
|
||||
"##hidelabel", &graph_.node(node.ui.output.g).value, 0.01f, 0.f, 1.f);
|
||||
ImGui::PopItemWidth();
|
||||
}
|
||||
ImNodes::EndInputAttribute();
|
||||
}
|
||||
|
||||
ImGui::Spacing();
|
||||
|
||||
{
|
||||
ImNodes::BeginInputAttribute(node.ui.output.b);
|
||||
const float label_width = ImGui::CalcTextSize("b").x;
|
||||
ImGui::TextUnformatted("b");
|
||||
if (graph_.num_edges_from_node(node.ui.output.b) == 0ull)
|
||||
{
|
||||
ImGui::SameLine();
|
||||
ImGui::PushItemWidth(node_width - label_width);
|
||||
ImGui::DragFloat(
|
||||
"##hidelabel", &graph_.node(node.ui.output.b).value, 0.01f, 0.f, 1.0f);
|
||||
ImGui::PopItemWidth();
|
||||
}
|
||||
ImNodes::EndInputAttribute();
|
||||
}
|
||||
ImNodes::EndNode();
|
||||
ImNodes::PopColorStyle();
|
||||
ImNodes::PopColorStyle();
|
||||
ImNodes::PopColorStyle();
|
||||
}
|
||||
break;
|
||||
case UiNodeType::sine:
|
||||
{
|
||||
const float node_width = 100.0f;
|
||||
ImNodes::BeginNode(node.id);
|
||||
|
||||
ImNodes::BeginNodeTitleBar();
|
||||
ImGui::TextUnformatted("sine");
|
||||
ImNodes::EndNodeTitleBar();
|
||||
|
||||
{
|
||||
ImNodes::BeginInputAttribute(node.ui.sine.input);
|
||||
const float label_width = ImGui::CalcTextSize("number").x;
|
||||
ImGui::TextUnformatted("number");
|
||||
if (graph_.num_edges_from_node(node.ui.sine.input) == 0ull)
|
||||
{
|
||||
ImGui::SameLine();
|
||||
ImGui::PushItemWidth(node_width - label_width);
|
||||
ImGui::DragFloat(
|
||||
"##hidelabel",
|
||||
&graph_.node(node.ui.sine.input).value,
|
||||
0.01f,
|
||||
0.f,
|
||||
1.0f);
|
||||
ImGui::PopItemWidth();
|
||||
}
|
||||
ImNodes::EndInputAttribute();
|
||||
}
|
||||
|
||||
ImGui::Spacing();
|
||||
|
||||
{
|
||||
ImNodes::BeginOutputAttribute(node.id);
|
||||
const float label_width = ImGui::CalcTextSize("output").x;
|
||||
ImGui::Indent(node_width - label_width);
|
||||
ImGui::TextUnformatted("output");
|
||||
ImNodes::EndOutputAttribute();
|
||||
}
|
||||
|
||||
ImNodes::EndNode();
|
||||
}
|
||||
break;
|
||||
case UiNodeType::time:
|
||||
{
|
||||
ImNodes::BeginNode(node.id);
|
||||
|
||||
ImNodes::BeginNodeTitleBar();
|
||||
ImGui::TextUnformatted("time");
|
||||
ImNodes::EndNodeTitleBar();
|
||||
|
||||
ImNodes::BeginOutputAttribute(node.id);
|
||||
ImGui::Text("output");
|
||||
ImNodes::EndOutputAttribute();
|
||||
|
||||
ImNodes::EndNode();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& edge : graph_.edges())
|
||||
{
|
||||
// If edge doesn't start at value, then it's an internal edge, i.e.
|
||||
// an edge which links a node's operation to its input. We don't
|
||||
// want to render node internals with visible links.
|
||||
if (graph_.node(edge.from).type != NodeType::value)
|
||||
continue;
|
||||
|
||||
ImNodes::Link(edge.id, edge.from, edge.to);
|
||||
}
|
||||
|
||||
ImNodes::MiniMap(0.2f, minimap_location_);
|
||||
ImNodes::EndNodeEditor();
|
||||
|
||||
// Handle new links
|
||||
// These are driven by Imnodes, so we place the code after EndNodeEditor().
|
||||
|
||||
{
|
||||
int start_attr, end_attr;
|
||||
if (ImNodes::IsLinkCreated(&start_attr, &end_attr))
|
||||
{
|
||||
const NodeType start_type = graph_.node(start_attr).type;
|
||||
const NodeType end_type = graph_.node(end_attr).type;
|
||||
|
||||
const bool valid_link = start_type != end_type;
|
||||
if (valid_link)
|
||||
{
|
||||
// Ensure the edge is always directed from the value to
|
||||
// whatever produces the value
|
||||
if (start_type != NodeType::value)
|
||||
{
|
||||
std::swap(start_attr, end_attr);
|
||||
}
|
||||
graph_.insert_edge(start_attr, end_attr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle deleted links
|
||||
|
||||
{
|
||||
int link_id;
|
||||
if (ImNodes::IsLinkDestroyed(&link_id))
|
||||
{
|
||||
graph_.erase_edge(link_id);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
const int num_selected = ImNodes::NumSelectedLinks();
|
||||
if (num_selected > 0 && ImGui::IsKeyReleased(ImGuiKey_X))
|
||||
{
|
||||
static std::vector<int> selected_links;
|
||||
selected_links.resize(static_cast<size_t>(num_selected));
|
||||
ImNodes::GetSelectedLinks(selected_links.data());
|
||||
for (const int edge_id : selected_links)
|
||||
{
|
||||
graph_.erase_edge(edge_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
const int num_selected = ImNodes::NumSelectedNodes();
|
||||
if (num_selected > 0 && ImGui::IsKeyReleased(ImGuiKey_X))
|
||||
{
|
||||
static std::vector<int> selected_nodes;
|
||||
selected_nodes.resize(static_cast<size_t>(num_selected));
|
||||
ImNodes::GetSelectedNodes(selected_nodes.data());
|
||||
for (const int node_id : selected_nodes)
|
||||
{
|
||||
graph_.erase_node(node_id);
|
||||
auto iter = std::find_if(
|
||||
nodes_.begin(), nodes_.end(), [node_id](const UiNode& node) -> bool {
|
||||
return node.id == node_id;
|
||||
});
|
||||
// Erase any additional internal nodes
|
||||
switch (iter->type)
|
||||
{
|
||||
case UiNodeType::add:
|
||||
graph_.erase_node(iter->ui.add.lhs);
|
||||
graph_.erase_node(iter->ui.add.rhs);
|
||||
break;
|
||||
case UiNodeType::multiply:
|
||||
graph_.erase_node(iter->ui.multiply.lhs);
|
||||
graph_.erase_node(iter->ui.multiply.rhs);
|
||||
break;
|
||||
case UiNodeType::output:
|
||||
graph_.erase_node(iter->ui.output.r);
|
||||
graph_.erase_node(iter->ui.output.g);
|
||||
graph_.erase_node(iter->ui.output.b);
|
||||
root_node_id_ = -1;
|
||||
break;
|
||||
case UiNodeType::sine:
|
||||
graph_.erase_node(iter->ui.sine.input);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
nodes_.erase(iter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::End();
|
||||
|
||||
// The color output window
|
||||
|
||||
const ImU32 color =
|
||||
root_node_id_ != -1 ? evaluate(graph_, root_node_id_) : IM_COL32(255, 20, 147, 255);
|
||||
ImGui::PushStyleColor(ImGuiCol_WindowBg, color);
|
||||
ImGui::Begin("output color");
|
||||
ImGui::End();
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
|
||||
private:
|
||||
enum class UiNodeType
|
||||
{
|
||||
add,
|
||||
multiply,
|
||||
output,
|
||||
sine,
|
||||
time,
|
||||
};
|
||||
|
||||
struct UiNode
|
||||
{
|
||||
UiNodeType type;
|
||||
// The identifying id of the ui node. For add, multiply, sine, and time
|
||||
// this is the "operation" node id. The additional input nodes are
|
||||
// stored in the structs.
|
||||
int id;
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
int lhs, rhs;
|
||||
} add;
|
||||
|
||||
struct
|
||||
{
|
||||
int lhs, rhs;
|
||||
} multiply;
|
||||
|
||||
struct
|
||||
{
|
||||
int r, g, b;
|
||||
} output;
|
||||
|
||||
struct
|
||||
{
|
||||
int input;
|
||||
} sine;
|
||||
} ui;
|
||||
};
|
||||
|
||||
Graph<Node> graph_;
|
||||
std::vector<UiNode> nodes_;
|
||||
int root_node_id_;
|
||||
ImNodesMiniMapLocation minimap_location_;
|
||||
};
|
||||
|
||||
static ColorNodeEditor color_editor;
|
||||
} // namespace
|
||||
|
||||
void NodeEditorInitialize()
|
||||
{
|
||||
ImNodesIO& io = ImNodes::GetIO();
|
||||
io.LinkDetachWithModifierClick.Modifier = &ImGui::GetIO().KeyCtrl;
|
||||
}
|
||||
|
||||
void NodeEditorShow() { color_editor.show(); }
|
||||
|
||||
void NodeEditorShutdown() {}
|
||||
} // namespace example
|
||||
357
Lib/imnodes-master-b2ec254/example/graph.h
Normal file
357
Lib/imnodes-master-b2ec254/example/graph.h
Normal file
@ -0,0 +1,357 @@
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <iterator>
|
||||
#include <stack>
|
||||
#include <stddef.h>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace example
|
||||
{
|
||||
template<typename ElementType>
|
||||
struct Span
|
||||
{
|
||||
using iterator = ElementType*;
|
||||
|
||||
template<typename Container>
|
||||
Span(Container& c) : begin_(c.data()), end_(begin_ + c.size())
|
||||
{
|
||||
}
|
||||
|
||||
iterator begin() const { return begin_; }
|
||||
iterator end() const { return end_; }
|
||||
|
||||
private:
|
||||
iterator begin_;
|
||||
iterator end_;
|
||||
};
|
||||
|
||||
template<typename ElementType>
|
||||
class IdMap
|
||||
{
|
||||
public:
|
||||
using iterator = typename std::vector<ElementType>::iterator;
|
||||
using const_iterator = typename std::vector<ElementType>::const_iterator;
|
||||
|
||||
// Iterators
|
||||
|
||||
const_iterator begin() const { return elements_.begin(); }
|
||||
const_iterator end() const { return elements_.end(); }
|
||||
|
||||
// Element access
|
||||
|
||||
Span<const ElementType> elements() const { return elements_; }
|
||||
|
||||
// Capacity
|
||||
|
||||
bool empty() const { return sorted_ids_.empty(); }
|
||||
size_t size() const { return sorted_ids_.size(); }
|
||||
|
||||
// Modifiers
|
||||
|
||||
std::pair<iterator, bool> insert(int id, const ElementType& element);
|
||||
std::pair<iterator, bool> insert(int id, ElementType&& element);
|
||||
size_t erase(int id);
|
||||
void clear();
|
||||
|
||||
// Lookup
|
||||
|
||||
iterator find(int id);
|
||||
const_iterator find(int id) const;
|
||||
bool contains(int id) const;
|
||||
|
||||
private:
|
||||
std::vector<ElementType> elements_;
|
||||
std::vector<int> sorted_ids_;
|
||||
};
|
||||
|
||||
template<typename ElementType>
|
||||
std::pair<typename IdMap<ElementType>::iterator, bool> IdMap<ElementType>::insert(
|
||||
const int id,
|
||||
const ElementType& element)
|
||||
{
|
||||
auto lower_bound = std::lower_bound(sorted_ids_.begin(), sorted_ids_.end(), id);
|
||||
|
||||
if (lower_bound != sorted_ids_.end() && id == *lower_bound)
|
||||
{
|
||||
return std::make_pair(
|
||||
std::next(elements_.begin(), std::distance(sorted_ids_.begin(), lower_bound)), false);
|
||||
}
|
||||
|
||||
auto insert_element_at =
|
||||
std::next(elements_.begin(), std::distance(sorted_ids_.begin(), lower_bound));
|
||||
|
||||
sorted_ids_.insert(lower_bound, id);
|
||||
return std::make_pair(elements_.insert(insert_element_at, element), true);
|
||||
}
|
||||
|
||||
template<typename ElementType>
|
||||
std::pair<typename IdMap<ElementType>::iterator, bool> IdMap<ElementType>::insert(
|
||||
const int id,
|
||||
ElementType&& element)
|
||||
{
|
||||
auto lower_bound = std::lower_bound(sorted_ids_.begin(), sorted_ids_.end(), id);
|
||||
|
||||
if (lower_bound != sorted_ids_.end() && id == *lower_bound)
|
||||
{
|
||||
return std::make_pair(
|
||||
std::next(elements_.begin(), std::distance(sorted_ids_.begin(), lower_bound)), false);
|
||||
}
|
||||
|
||||
auto insert_element_at =
|
||||
std::next(elements_.begin(), std::distance(sorted_ids_.begin(), lower_bound));
|
||||
|
||||
sorted_ids_.insert(lower_bound, id);
|
||||
return std::make_pair(elements_.insert(insert_element_at, std::move(element)), true);
|
||||
}
|
||||
|
||||
template<typename ElementType>
|
||||
size_t IdMap<ElementType>::erase(const int id)
|
||||
{
|
||||
auto lower_bound = std::lower_bound(sorted_ids_.begin(), sorted_ids_.end(), id);
|
||||
|
||||
if (lower_bound == sorted_ids_.end() || id != *lower_bound)
|
||||
{
|
||||
return 0ull;
|
||||
}
|
||||
|
||||
auto erase_element_at =
|
||||
std::next(elements_.begin(), std::distance(sorted_ids_.begin(), lower_bound));
|
||||
|
||||
sorted_ids_.erase(lower_bound);
|
||||
elements_.erase(erase_element_at);
|
||||
|
||||
return 1ull;
|
||||
}
|
||||
|
||||
template<typename ElementType>
|
||||
void IdMap<ElementType>::clear()
|
||||
{
|
||||
elements_.clear();
|
||||
sorted_ids_.clear();
|
||||
}
|
||||
|
||||
template<typename ElementType>
|
||||
typename IdMap<ElementType>::iterator IdMap<ElementType>::find(const int id)
|
||||
{
|
||||
const auto lower_bound = std::lower_bound(sorted_ids_.cbegin(), sorted_ids_.cend(), id);
|
||||
return (lower_bound == sorted_ids_.cend() || *lower_bound != id)
|
||||
? elements_.end()
|
||||
: std::next(elements_.begin(), std::distance(sorted_ids_.cbegin(), lower_bound));
|
||||
}
|
||||
|
||||
template<typename ElementType>
|
||||
typename IdMap<ElementType>::const_iterator IdMap<ElementType>::find(const int id) const
|
||||
{
|
||||
const auto lower_bound = std::lower_bound(sorted_ids_.cbegin(), sorted_ids_.cend(), id);
|
||||
return (lower_bound == sorted_ids_.cend() || *lower_bound != id)
|
||||
? elements_.cend()
|
||||
: std::next(elements_.cbegin(), std::distance(sorted_ids_.cbegin(), lower_bound));
|
||||
}
|
||||
|
||||
template<typename ElementType>
|
||||
bool IdMap<ElementType>::contains(const int id) const
|
||||
{
|
||||
const auto lower_bound = std::lower_bound(sorted_ids_.cbegin(), sorted_ids_.cend(), id);
|
||||
|
||||
if (lower_bound == sorted_ids_.cend())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return *lower_bound == id;
|
||||
}
|
||||
|
||||
// a very simple directional graph
|
||||
template<typename NodeType>
|
||||
class Graph
|
||||
{
|
||||
public:
|
||||
Graph() : current_id_(0), nodes_(), edges_from_node_(), node_neighbors_(), edges_() {}
|
||||
|
||||
struct Edge
|
||||
{
|
||||
int id;
|
||||
int from, to;
|
||||
|
||||
Edge() = default;
|
||||
Edge(const int id, const int f, const int t) : id(id), from(f), to(t) {}
|
||||
|
||||
inline int opposite(const int n) const { return n == from ? to : from; }
|
||||
inline bool contains(const int n) const { return n == from || n == to; }
|
||||
};
|
||||
|
||||
// Element access
|
||||
|
||||
NodeType& node(int node_id);
|
||||
const NodeType& node(int node_id) const;
|
||||
Span<const int> neighbors(int node_id) const;
|
||||
Span<const Edge> edges() const;
|
||||
|
||||
// Capacity
|
||||
|
||||
size_t num_edges_from_node(int node_id) const;
|
||||
|
||||
// Modifiers
|
||||
|
||||
int insert_node(const NodeType& node);
|
||||
void erase_node(int node_id);
|
||||
|
||||
int insert_edge(int from, int to);
|
||||
void erase_edge(int edge_id);
|
||||
|
||||
private:
|
||||
int current_id_;
|
||||
// These contains map to the node id
|
||||
IdMap<NodeType> nodes_;
|
||||
IdMap<int> edges_from_node_;
|
||||
IdMap<std::vector<int>> node_neighbors_;
|
||||
|
||||
// This container maps to the edge id
|
||||
IdMap<Edge> edges_;
|
||||
};
|
||||
|
||||
template<typename NodeType>
|
||||
NodeType& Graph<NodeType>::node(const int id)
|
||||
{
|
||||
return const_cast<NodeType&>(static_cast<const Graph*>(this)->node(id));
|
||||
}
|
||||
|
||||
template<typename NodeType>
|
||||
const NodeType& Graph<NodeType>::node(const int id) const
|
||||
{
|
||||
const auto iter = nodes_.find(id);
|
||||
assert(iter != nodes_.end());
|
||||
return *iter;
|
||||
}
|
||||
|
||||
template<typename NodeType>
|
||||
Span<const int> Graph<NodeType>::neighbors(int node_id) const
|
||||
{
|
||||
const auto iter = node_neighbors_.find(node_id);
|
||||
assert(iter != node_neighbors_.end());
|
||||
return *iter;
|
||||
}
|
||||
|
||||
template<typename NodeType>
|
||||
Span<const typename Graph<NodeType>::Edge> Graph<NodeType>::edges() const
|
||||
{
|
||||
return edges_.elements();
|
||||
}
|
||||
|
||||
template<typename NodeType>
|
||||
size_t Graph<NodeType>::num_edges_from_node(const int id) const
|
||||
{
|
||||
auto iter = edges_from_node_.find(id);
|
||||
assert(iter != edges_from_node_.end());
|
||||
return *iter;
|
||||
}
|
||||
|
||||
template<typename NodeType>
|
||||
int Graph<NodeType>::insert_node(const NodeType& node)
|
||||
{
|
||||
const int id = current_id_++;
|
||||
assert(!nodes_.contains(id));
|
||||
nodes_.insert(id, node);
|
||||
edges_from_node_.insert(id, 0);
|
||||
node_neighbors_.insert(id, std::vector<int>());
|
||||
return id;
|
||||
}
|
||||
|
||||
template<typename NodeType>
|
||||
void Graph<NodeType>::erase_node(const int id)
|
||||
{
|
||||
|
||||
// first, remove any potential dangling edges
|
||||
{
|
||||
static std::vector<int> edges_to_erase;
|
||||
|
||||
for (const Edge& edge : edges_.elements())
|
||||
{
|
||||
if (edge.contains(id))
|
||||
{
|
||||
edges_to_erase.push_back(edge.id);
|
||||
}
|
||||
}
|
||||
|
||||
for (const int edge_id : edges_to_erase)
|
||||
{
|
||||
erase_edge(edge_id);
|
||||
}
|
||||
|
||||
edges_to_erase.clear();
|
||||
}
|
||||
|
||||
nodes_.erase(id);
|
||||
edges_from_node_.erase(id);
|
||||
node_neighbors_.erase(id);
|
||||
}
|
||||
|
||||
template<typename NodeType>
|
||||
int Graph<NodeType>::insert_edge(const int from, const int to)
|
||||
{
|
||||
const int id = current_id_++;
|
||||
assert(!edges_.contains(id));
|
||||
assert(nodes_.contains(from));
|
||||
assert(nodes_.contains(to));
|
||||
edges_.insert(id, Edge(id, from, to));
|
||||
|
||||
// update neighbor count
|
||||
assert(edges_from_node_.contains(from));
|
||||
*edges_from_node_.find(from) += 1;
|
||||
// update neighbor list
|
||||
assert(node_neighbors_.contains(from));
|
||||
node_neighbors_.find(from)->push_back(to);
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
template<typename NodeType>
|
||||
void Graph<NodeType>::erase_edge(const int edge_id)
|
||||
{
|
||||
// This is a bit lazy, we find the pointer here, but we refind it when we erase the edge based
|
||||
// on id key.
|
||||
assert(edges_.contains(edge_id));
|
||||
const Edge& edge = *edges_.find(edge_id);
|
||||
|
||||
// update neighbor count
|
||||
assert(edges_from_node_.contains(edge.from));
|
||||
int& edge_count = *edges_from_node_.find(edge.from);
|
||||
assert(edge_count > 0);
|
||||
edge_count -= 1;
|
||||
|
||||
// update neighbor list
|
||||
{
|
||||
assert(node_neighbors_.contains(edge.from));
|
||||
auto neighbors = node_neighbors_.find(edge.from);
|
||||
auto iter = std::find(neighbors->begin(), neighbors->end(), edge.to);
|
||||
assert(iter != neighbors->end());
|
||||
neighbors->erase(iter);
|
||||
}
|
||||
|
||||
edges_.erase(edge_id);
|
||||
}
|
||||
|
||||
template<typename NodeType, typename Visitor>
|
||||
void dfs_traverse(const Graph<NodeType>& graph, const int start_node, Visitor visitor)
|
||||
{
|
||||
std::stack<int> stack;
|
||||
|
||||
stack.push(start_node);
|
||||
|
||||
while (!stack.empty())
|
||||
{
|
||||
const int current_node = stack.top();
|
||||
stack.pop();
|
||||
|
||||
visitor(current_node);
|
||||
|
||||
for (const int neighbor : graph.neighbors(current_node))
|
||||
{
|
||||
stack.push(neighbor);
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace example
|
||||
48
Lib/imnodes-master-b2ec254/example/hello.cpp
Normal file
48
Lib/imnodes-master-b2ec254/example/hello.cpp
Normal file
@ -0,0 +1,48 @@
|
||||
#include "node_editor.h"
|
||||
#include <imnodes.h>
|
||||
#include <imgui.h>
|
||||
|
||||
namespace example
|
||||
{
|
||||
namespace
|
||||
{
|
||||
class HelloWorldNodeEditor
|
||||
{
|
||||
public:
|
||||
void show()
|
||||
{
|
||||
ImGui::Begin("simple node editor");
|
||||
|
||||
ImNodes::BeginNodeEditor();
|
||||
ImNodes::BeginNode(1);
|
||||
|
||||
ImNodes::BeginNodeTitleBar();
|
||||
ImGui::TextUnformatted("simple node :)");
|
||||
ImNodes::EndNodeTitleBar();
|
||||
|
||||
ImNodes::BeginInputAttribute(2);
|
||||
ImGui::Text("input");
|
||||
ImNodes::EndInputAttribute();
|
||||
|
||||
ImNodes::BeginOutputAttribute(3);
|
||||
ImGui::Indent(40);
|
||||
ImGui::Text("output");
|
||||
ImNodes::EndOutputAttribute();
|
||||
|
||||
ImNodes::EndNode();
|
||||
ImNodes::EndNodeEditor();
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
};
|
||||
|
||||
static HelloWorldNodeEditor editor;
|
||||
} // namespace
|
||||
|
||||
void NodeEditorInitialize() { ImNodes::SetNodeGridSpacePos(1, ImVec2(200.0f, 200.0f)); }
|
||||
|
||||
void NodeEditorShow() { editor.show(); }
|
||||
|
||||
void NodeEditorShutdown() {}
|
||||
|
||||
} // namespace example
|
||||
133
Lib/imnodes-master-b2ec254/example/main.cpp
Normal file
133
Lib/imnodes-master-b2ec254/example/main.cpp
Normal file
@ -0,0 +1,133 @@
|
||||
#include "node_editor.h"
|
||||
|
||||
#include <imgui.h>
|
||||
#include <imgui_impl_sdl2.h>
|
||||
#include <imgui_impl_opengl3.h>
|
||||
#include <imnodes.h>
|
||||
#include <SDL2/SDL.h>
|
||||
#if defined(IMGUI_IMPL_OPENGL_ES2)
|
||||
#include <SDL2/SDL_opengles2.h>
|
||||
#else
|
||||
#include <SDL2/SDL_opengl.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_GAMECONTROLLER) != 0)
|
||||
{
|
||||
printf("Error: %s\n", SDL_GetError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Decide GL+GLSL versions
|
||||
#if defined(IMGUI_IMPL_OPENGL_ES2)
|
||||
// GL ES 2.0 + GLSL 100
|
||||
const char* glsl_version = "#version 100";
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
|
||||
#elif defined(__APPLE__)
|
||||
// GL 3.2 Core + GLSL 150
|
||||
const char* glsl_version = "#version 150";
|
||||
SDL_GL_SetAttribute(
|
||||
SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG); // Always required on Mac
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
|
||||
#else
|
||||
// GL 3.0 + GLSL 130
|
||||
const char* glsl_version = "#version 130";
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
|
||||
#endif
|
||||
|
||||
// Create window with graphics context
|
||||
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
|
||||
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
|
||||
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
|
||||
SDL_WindowFlags window_flags =
|
||||
(SDL_WindowFlags)(SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI);
|
||||
SDL_Window* window = SDL_CreateWindow(
|
||||
"Dear ImGui SDL2+OpenGL3 example",
|
||||
SDL_WINDOWPOS_CENTERED,
|
||||
SDL_WINDOWPOS_CENTERED,
|
||||
1280,
|
||||
720,
|
||||
window_flags);
|
||||
SDL_GLContext gl_context = SDL_GL_CreateContext(window);
|
||||
SDL_GL_MakeCurrent(window, gl_context);
|
||||
SDL_GL_SetSwapInterval(1); // Enable vsync
|
||||
|
||||
// Setup Dear ImGui context
|
||||
IMGUI_CHECKVERSION();
|
||||
ImGui::CreateContext();
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
(void)io;
|
||||
|
||||
ImNodes::CreateContext();
|
||||
example::NodeEditorInitialize();
|
||||
|
||||
// Setup Dear ImGui style
|
||||
ImGui::StyleColorsDark();
|
||||
// ImGui::StyleColorsClassic();
|
||||
ImNodes::StyleColorsDark();
|
||||
|
||||
// Setup Platform/Renderer backends
|
||||
ImGui_ImplSDL2_InitForOpenGL(window, gl_context);
|
||||
ImGui_ImplOpenGL3_Init(glsl_version);
|
||||
|
||||
ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);
|
||||
|
||||
// Main loop
|
||||
bool done = false;
|
||||
while (!done)
|
||||
{
|
||||
SDL_Event event;
|
||||
while (SDL_PollEvent(&event))
|
||||
{
|
||||
ImGui_ImplSDL2_ProcessEvent(&event);
|
||||
if (event.type == SDL_QUIT)
|
||||
done = true;
|
||||
if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_CLOSE &&
|
||||
event.window.windowID == SDL_GetWindowID(window))
|
||||
done = true;
|
||||
}
|
||||
|
||||
// Start the Dear ImGui frame
|
||||
ImGui_ImplOpenGL3_NewFrame();
|
||||
ImGui_ImplSDL2_NewFrame();
|
||||
ImGui::NewFrame();
|
||||
|
||||
example::NodeEditorShow();
|
||||
|
||||
// Rendering
|
||||
ImGui::Render();
|
||||
glViewport(0, 0, (int)io.DisplaySize.x, (int)io.DisplaySize.y);
|
||||
glClearColor(
|
||||
clear_color.x * clear_color.w,
|
||||
clear_color.y * clear_color.w,
|
||||
clear_color.z * clear_color.w,
|
||||
clear_color.w);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
||||
SDL_GL_SwapWindow(window);
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
ImGui_ImplOpenGL3_Shutdown();
|
||||
ImGui_ImplSDL2_Shutdown();
|
||||
example::NodeEditorShutdown();
|
||||
ImNodes::DestroyContext();
|
||||
ImGui::DestroyContext();
|
||||
|
||||
SDL_GL_DeleteContext(gl_context);
|
||||
SDL_DestroyWindow(window);
|
||||
SDL_Quit();
|
||||
|
||||
return 0;
|
||||
}
|
||||
142
Lib/imnodes-master-b2ec254/example/multi_editor.cpp
Normal file
142
Lib/imnodes-master-b2ec254/example/multi_editor.cpp
Normal file
@ -0,0 +1,142 @@
|
||||
#include "node_editor.h"
|
||||
#include <imnodes.h>
|
||||
#include <imgui.h>
|
||||
#include <SDL_scancode.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
namespace example
|
||||
{
|
||||
namespace
|
||||
{
|
||||
struct Node
|
||||
{
|
||||
int id;
|
||||
float value;
|
||||
|
||||
Node(const int i, const float v) : id(i), value(v) {}
|
||||
};
|
||||
|
||||
struct Link
|
||||
{
|
||||
int id;
|
||||
int start_attr, end_attr;
|
||||
};
|
||||
|
||||
struct Editor
|
||||
{
|
||||
ImNodesEditorContext* context = nullptr;
|
||||
std::vector<Node> nodes;
|
||||
std::vector<Link> links;
|
||||
int current_id = 0;
|
||||
};
|
||||
|
||||
void show_editor(const char* editor_name, Editor& editor)
|
||||
{
|
||||
ImNodes::EditorContextSet(editor.context);
|
||||
|
||||
ImGui::Begin(editor_name);
|
||||
ImGui::TextUnformatted("A -- add node");
|
||||
|
||||
ImNodes::BeginNodeEditor();
|
||||
|
||||
if (ImGui::IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows) &&
|
||||
ImNodes::IsEditorHovered() && ImGui::IsKeyReleased(ImGuiKey_A))
|
||||
{
|
||||
const int node_id = ++editor.current_id;
|
||||
ImNodes::SetNodeScreenSpacePos(node_id, ImGui::GetMousePos());
|
||||
ImNodes::SnapNodeToGrid(node_id);
|
||||
editor.nodes.push_back(Node(node_id, 0.f));
|
||||
}
|
||||
|
||||
for (Node& node : editor.nodes)
|
||||
{
|
||||
ImNodes::BeginNode(node.id);
|
||||
|
||||
ImNodes::BeginNodeTitleBar();
|
||||
ImGui::TextUnformatted("node");
|
||||
ImNodes::EndNodeTitleBar();
|
||||
|
||||
ImNodes::BeginInputAttribute(node.id << 8);
|
||||
ImGui::TextUnformatted("input");
|
||||
ImNodes::EndInputAttribute();
|
||||
|
||||
ImNodes::BeginStaticAttribute(node.id << 16);
|
||||
ImGui::PushItemWidth(120.0f);
|
||||
ImGui::DragFloat("value", &node.value, 0.01f);
|
||||
ImGui::PopItemWidth();
|
||||
ImNodes::EndStaticAttribute();
|
||||
|
||||
ImNodes::BeginOutputAttribute(node.id << 24);
|
||||
const float text_width = ImGui::CalcTextSize("output").x;
|
||||
ImGui::Indent(120.f + ImGui::CalcTextSize("value").x - text_width);
|
||||
ImGui::TextUnformatted("output");
|
||||
ImNodes::EndOutputAttribute();
|
||||
|
||||
ImNodes::EndNode();
|
||||
}
|
||||
|
||||
for (const Link& link : editor.links)
|
||||
{
|
||||
ImNodes::Link(link.id, link.start_attr, link.end_attr);
|
||||
}
|
||||
|
||||
ImNodes::EndNodeEditor();
|
||||
|
||||
{
|
||||
Link link;
|
||||
if (ImNodes::IsLinkCreated(&link.start_attr, &link.end_attr))
|
||||
{
|
||||
link.id = ++editor.current_id;
|
||||
editor.links.push_back(link);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
int link_id;
|
||||
if (ImNodes::IsLinkDestroyed(&link_id))
|
||||
{
|
||||
auto iter = std::find_if(
|
||||
editor.links.begin(), editor.links.end(), [link_id](const Link& link) -> bool {
|
||||
return link.id == link_id;
|
||||
});
|
||||
assert(iter != editor.links.end());
|
||||
editor.links.erase(iter);
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
Editor editor1;
|
||||
Editor editor2;
|
||||
} // namespace
|
||||
|
||||
void NodeEditorInitialize()
|
||||
{
|
||||
editor1.context = ImNodes::EditorContextCreate();
|
||||
editor2.context = ImNodes::EditorContextCreate();
|
||||
ImNodes::PushAttributeFlag(ImNodesAttributeFlags_EnableLinkDetachWithDragClick);
|
||||
|
||||
ImNodesIO& io = ImNodes::GetIO();
|
||||
io.LinkDetachWithModifierClick.Modifier = &ImGui::GetIO().KeyCtrl;
|
||||
io.MultipleSelectModifier.Modifier = &ImGui::GetIO().KeyCtrl;
|
||||
|
||||
ImNodesStyle& style = ImNodes::GetStyle();
|
||||
style.Flags |= ImNodesStyleFlags_GridLinesPrimary | ImNodesStyleFlags_GridSnapping;
|
||||
}
|
||||
|
||||
void NodeEditorShow()
|
||||
{
|
||||
show_editor("editor1", editor1);
|
||||
show_editor("editor2", editor2);
|
||||
}
|
||||
|
||||
void NodeEditorShutdown()
|
||||
{
|
||||
ImNodes::PopAttributeFlag();
|
||||
ImNodes::EditorContextFree(editor1.context);
|
||||
ImNodes::EditorContextFree(editor2.context);
|
||||
}
|
||||
} // namespace example
|
||||
8
Lib/imnodes-master-b2ec254/example/node_editor.h
Normal file
8
Lib/imnodes-master-b2ec254/example/node_editor.h
Normal file
@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
namespace example
|
||||
{
|
||||
void NodeEditorInitialize();
|
||||
void NodeEditorShow();
|
||||
void NodeEditorShutdown();
|
||||
} // namespace example
|
||||
206
Lib/imnodes-master-b2ec254/example/save_load.cpp
Normal file
206
Lib/imnodes-master-b2ec254/example/save_load.cpp
Normal file
@ -0,0 +1,206 @@
|
||||
#include "node_editor.h"
|
||||
|
||||
#include <imnodes.h>
|
||||
#include <imgui.h>
|
||||
#include <SDL_keycode.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <fstream>
|
||||
#include <ios> // for std::streamsize
|
||||
#include <stddef.h>
|
||||
#include <vector>
|
||||
|
||||
namespace example
|
||||
{
|
||||
namespace
|
||||
{
|
||||
struct Node
|
||||
{
|
||||
int id;
|
||||
float value;
|
||||
|
||||
Node() = default;
|
||||
|
||||
Node(const int i, const float v) : id(i), value(v) {}
|
||||
};
|
||||
|
||||
struct Link
|
||||
{
|
||||
int id;
|
||||
int start_attr, end_attr;
|
||||
};
|
||||
|
||||
class SaveLoadEditor
|
||||
{
|
||||
public:
|
||||
SaveLoadEditor() : nodes_(), links_(), current_id_(0) {}
|
||||
|
||||
void show()
|
||||
{
|
||||
ImGui::Begin("Save & load example");
|
||||
ImGui::TextUnformatted("A -- add node");
|
||||
ImGui::TextUnformatted(
|
||||
"Close the executable and rerun it -- your nodes should be exactly "
|
||||
"where you left them!");
|
||||
|
||||
ImNodes::BeginNodeEditor();
|
||||
|
||||
if (ImGui::IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows) &&
|
||||
ImNodes::IsEditorHovered() && ImGui::IsKeyReleased(ImGuiKey_A))
|
||||
{
|
||||
const int node_id = ++current_id_;
|
||||
ImNodes::SetNodeScreenSpacePos(node_id, ImGui::GetMousePos());
|
||||
nodes_.push_back(Node(node_id, 0.f));
|
||||
}
|
||||
|
||||
for (Node& node : nodes_)
|
||||
{
|
||||
ImNodes::BeginNode(node.id);
|
||||
|
||||
ImNodes::BeginNodeTitleBar();
|
||||
ImGui::TextUnformatted("node");
|
||||
ImNodes::EndNodeTitleBar();
|
||||
|
||||
ImNodes::BeginInputAttribute(node.id << 8);
|
||||
ImGui::TextUnformatted("input");
|
||||
ImNodes::EndInputAttribute();
|
||||
|
||||
ImNodes::BeginStaticAttribute(node.id << 16);
|
||||
ImGui::PushItemWidth(120.f);
|
||||
ImGui::DragFloat("value", &node.value, 0.01f);
|
||||
ImGui::PopItemWidth();
|
||||
ImNodes::EndStaticAttribute();
|
||||
|
||||
ImNodes::BeginOutputAttribute(node.id << 24);
|
||||
const float text_width = ImGui::CalcTextSize("output").x;
|
||||
ImGui::Indent(120.f + ImGui::CalcTextSize("value").x - text_width);
|
||||
ImGui::TextUnformatted("output");
|
||||
ImNodes::EndOutputAttribute();
|
||||
|
||||
ImNodes::EndNode();
|
||||
}
|
||||
|
||||
for (const Link& link : links_)
|
||||
{
|
||||
ImNodes::Link(link.id, link.start_attr, link.end_attr);
|
||||
}
|
||||
|
||||
ImNodes::EndNodeEditor();
|
||||
|
||||
{
|
||||
Link link;
|
||||
if (ImNodes::IsLinkCreated(&link.start_attr, &link.end_attr))
|
||||
{
|
||||
link.id = ++current_id_;
|
||||
links_.push_back(link);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
int link_id;
|
||||
if (ImNodes::IsLinkDestroyed(&link_id))
|
||||
{
|
||||
auto iter =
|
||||
std::find_if(links_.begin(), links_.end(), [link_id](const Link& link) -> bool {
|
||||
return link.id == link_id;
|
||||
});
|
||||
assert(iter != links_.end());
|
||||
links_.erase(iter);
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
void save()
|
||||
{
|
||||
// Save the internal imnodes state
|
||||
ImNodes::SaveCurrentEditorStateToIniFile("save_load.ini");
|
||||
|
||||
// Dump our editor state as bytes into a file
|
||||
|
||||
std::fstream fout(
|
||||
"save_load.bytes", std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
|
||||
|
||||
// copy the node vector to file
|
||||
const size_t num_nodes = nodes_.size();
|
||||
fout.write(
|
||||
reinterpret_cast<const char*>(&num_nodes),
|
||||
static_cast<std::streamsize>(sizeof(size_t)));
|
||||
fout.write(
|
||||
reinterpret_cast<const char*>(nodes_.data()),
|
||||
static_cast<std::streamsize>(sizeof(Node) * num_nodes));
|
||||
|
||||
// copy the link vector to file
|
||||
const size_t num_links = links_.size();
|
||||
fout.write(
|
||||
reinterpret_cast<const char*>(&num_links),
|
||||
static_cast<std::streamsize>(sizeof(size_t)));
|
||||
fout.write(
|
||||
reinterpret_cast<const char*>(links_.data()),
|
||||
static_cast<std::streamsize>(sizeof(Link) * num_links));
|
||||
|
||||
// copy the current_id to file
|
||||
fout.write(
|
||||
reinterpret_cast<const char*>(¤t_id_), static_cast<std::streamsize>(sizeof(int)));
|
||||
}
|
||||
|
||||
void load()
|
||||
{
|
||||
// Load the internal imnodes state
|
||||
ImNodes::LoadCurrentEditorStateFromIniFile("save_load.ini");
|
||||
|
||||
// Load our editor state into memory
|
||||
|
||||
std::fstream fin("save_load.bytes", std::ios_base::in | std::ios_base::binary);
|
||||
|
||||
if (!fin.is_open())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// copy nodes into memory
|
||||
size_t num_nodes;
|
||||
fin.read(reinterpret_cast<char*>(&num_nodes), static_cast<std::streamsize>(sizeof(size_t)));
|
||||
nodes_.resize(num_nodes);
|
||||
fin.read(
|
||||
reinterpret_cast<char*>(nodes_.data()),
|
||||
static_cast<std::streamsize>(sizeof(Node) * num_nodes));
|
||||
|
||||
// copy links into memory
|
||||
size_t num_links;
|
||||
fin.read(reinterpret_cast<char*>(&num_links), static_cast<std::streamsize>(sizeof(size_t)));
|
||||
links_.resize(num_links);
|
||||
fin.read(
|
||||
reinterpret_cast<char*>(links_.data()),
|
||||
static_cast<std::streamsize>(sizeof(Link) * num_links));
|
||||
|
||||
// copy current_id into memory
|
||||
fin.read(reinterpret_cast<char*>(¤t_id_), static_cast<std::streamsize>(sizeof(int)));
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<Node> nodes_;
|
||||
std::vector<Link> links_;
|
||||
int current_id_;
|
||||
};
|
||||
|
||||
static SaveLoadEditor editor;
|
||||
} // namespace
|
||||
|
||||
void NodeEditorInitialize()
|
||||
{
|
||||
ImNodes::GetIO().LinkDetachWithModifierClick.Modifier = &ImGui::GetIO().KeyCtrl;
|
||||
ImNodes::PushAttributeFlag(ImNodesAttributeFlags_EnableLinkDetachWithDragClick);
|
||||
editor.load();
|
||||
}
|
||||
|
||||
void NodeEditorShow() { editor.show(); }
|
||||
|
||||
void NodeEditorShutdown()
|
||||
{
|
||||
ImNodes::PopAttributeFlag();
|
||||
editor.save();
|
||||
}
|
||||
} // namespace example
|
||||
BIN
Lib/imnodes-master-b2ec254/img/imnodes.gif
Normal file
BIN
Lib/imnodes-master-b2ec254/img/imnodes.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.4 MiB |
3265
Lib/imnodes-master-b2ec254/imnodes.cpp
Normal file
3265
Lib/imnodes-master-b2ec254/imnodes.cpp
Normal file
File diff suppressed because it is too large
Load Diff
438
Lib/imnodes-master-b2ec254/imnodes.h
Normal file
438
Lib/imnodes-master-b2ec254/imnodes.h
Normal file
@ -0,0 +1,438 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <imgui.h>
|
||||
|
||||
#ifdef IMNODES_USER_CONFIG
|
||||
#include IMNODES_USER_CONFIG
|
||||
#endif
|
||||
|
||||
#ifndef IMNODES_NAMESPACE
|
||||
#define IMNODES_NAMESPACE ImNodes
|
||||
#endif
|
||||
|
||||
typedef int ImNodesCol; // -> enum ImNodesCol_
|
||||
typedef int ImNodesStyleVar; // -> enum ImNodesStyleVar_
|
||||
typedef int ImNodesStyleFlags; // -> enum ImNodesStyleFlags_
|
||||
typedef int ImNodesPinShape; // -> enum ImNodesPinShape_
|
||||
typedef int ImNodesAttributeFlags; // -> enum ImNodesAttributeFlags_
|
||||
typedef int ImNodesMiniMapLocation; // -> enum ImNodesMiniMapLocation_
|
||||
|
||||
enum ImNodesCol_
|
||||
{
|
||||
ImNodesCol_NodeBackground = 0,
|
||||
ImNodesCol_NodeBackgroundHovered,
|
||||
ImNodesCol_NodeBackgroundSelected,
|
||||
ImNodesCol_NodeOutline,
|
||||
ImNodesCol_TitleBar,
|
||||
ImNodesCol_TitleBarHovered,
|
||||
ImNodesCol_TitleBarSelected,
|
||||
ImNodesCol_Link,
|
||||
ImNodesCol_LinkHovered,
|
||||
ImNodesCol_LinkSelected,
|
||||
ImNodesCol_Pin,
|
||||
ImNodesCol_PinHovered,
|
||||
ImNodesCol_BoxSelector,
|
||||
ImNodesCol_BoxSelectorOutline,
|
||||
ImNodesCol_GridBackground,
|
||||
ImNodesCol_GridLine,
|
||||
ImNodesCol_GridLinePrimary,
|
||||
ImNodesCol_MiniMapBackground,
|
||||
ImNodesCol_MiniMapBackgroundHovered,
|
||||
ImNodesCol_MiniMapOutline,
|
||||
ImNodesCol_MiniMapOutlineHovered,
|
||||
ImNodesCol_MiniMapNodeBackground,
|
||||
ImNodesCol_MiniMapNodeBackgroundHovered,
|
||||
ImNodesCol_MiniMapNodeBackgroundSelected,
|
||||
ImNodesCol_MiniMapNodeOutline,
|
||||
ImNodesCol_MiniMapLink,
|
||||
ImNodesCol_MiniMapLinkSelected,
|
||||
ImNodesCol_MiniMapCanvas,
|
||||
ImNodesCol_MiniMapCanvasOutline,
|
||||
ImNodesCol_COUNT
|
||||
};
|
||||
|
||||
enum ImNodesStyleVar_
|
||||
{
|
||||
ImNodesStyleVar_GridSpacing = 0,
|
||||
ImNodesStyleVar_NodeCornerRounding,
|
||||
ImNodesStyleVar_NodePadding,
|
||||
ImNodesStyleVar_NodeBorderThickness,
|
||||
ImNodesStyleVar_LinkThickness,
|
||||
ImNodesStyleVar_LinkLineSegmentsPerLength,
|
||||
ImNodesStyleVar_LinkHoverDistance,
|
||||
ImNodesStyleVar_PinCircleRadius,
|
||||
ImNodesStyleVar_PinQuadSideLength,
|
||||
ImNodesStyleVar_PinTriangleSideLength,
|
||||
ImNodesStyleVar_PinLineThickness,
|
||||
ImNodesStyleVar_PinHoverRadius,
|
||||
ImNodesStyleVar_PinOffset,
|
||||
ImNodesStyleVar_MiniMapPadding,
|
||||
ImNodesStyleVar_MiniMapOffset,
|
||||
ImNodesStyleVar_COUNT
|
||||
};
|
||||
|
||||
enum ImNodesStyleFlags_
|
||||
{
|
||||
ImNodesStyleFlags_None = 0,
|
||||
ImNodesStyleFlags_NodeOutline = 1 << 0,
|
||||
ImNodesStyleFlags_GridLines = 1 << 2,
|
||||
ImNodesStyleFlags_GridLinesPrimary = 1 << 3,
|
||||
ImNodesStyleFlags_GridSnapping = 1 << 4
|
||||
};
|
||||
|
||||
enum ImNodesPinShape_
|
||||
{
|
||||
ImNodesPinShape_Circle,
|
||||
ImNodesPinShape_CircleFilled,
|
||||
ImNodesPinShape_Triangle,
|
||||
ImNodesPinShape_TriangleFilled,
|
||||
ImNodesPinShape_Quad,
|
||||
ImNodesPinShape_QuadFilled
|
||||
};
|
||||
|
||||
// This enum controls the way the attribute pins behave.
|
||||
enum ImNodesAttributeFlags_
|
||||
{
|
||||
ImNodesAttributeFlags_None = 0,
|
||||
// Allow detaching a link by left-clicking and dragging the link at a pin it is connected to.
|
||||
// NOTE: the user has to actually delete the link for this to work. A deleted link can be
|
||||
// detected by calling IsLinkDestroyed() after EndNodeEditor().
|
||||
ImNodesAttributeFlags_EnableLinkDetachWithDragClick = 1 << 0,
|
||||
// Visual snapping of an in progress link will trigger IsLink Created/Destroyed events. Allows
|
||||
// for previewing the creation of a link while dragging it across attributes. See here for demo:
|
||||
// https://github.com/Nelarius/imnodes/issues/41#issuecomment-647132113 NOTE: the user has to
|
||||
// actually delete the link for this to work. A deleted link can be detected by calling
|
||||
// IsLinkDestroyed() after EndNodeEditor().
|
||||
ImNodesAttributeFlags_EnableLinkCreationOnSnap = 1 << 1
|
||||
};
|
||||
|
||||
struct ImNodesIO
|
||||
{
|
||||
struct EmulateThreeButtonMouse
|
||||
{
|
||||
EmulateThreeButtonMouse();
|
||||
|
||||
// The keyboard modifier to use in combination with mouse left click to pan the editor view.
|
||||
// Set to NULL by default. To enable this feature, set the modifier to point to a boolean
|
||||
// indicating the state of a modifier. For example,
|
||||
//
|
||||
// ImNodes::GetIO().EmulateThreeButtonMouse.Modifier = &ImGui::GetIO().KeyAlt;
|
||||
const bool* Modifier;
|
||||
} EmulateThreeButtonMouse;
|
||||
|
||||
struct LinkDetachWithModifierClick
|
||||
{
|
||||
LinkDetachWithModifierClick();
|
||||
|
||||
// Pointer to a boolean value indicating when the desired modifier is pressed. Set to NULL
|
||||
// by default. To enable the feature, set the modifier to point to a boolean indicating the
|
||||
// state of a modifier. For example,
|
||||
//
|
||||
// ImNodes::GetIO().LinkDetachWithModifierClick.Modifier = &ImGui::GetIO().KeyCtrl;
|
||||
//
|
||||
// Left-clicking a link with this modifier pressed will detach that link. NOTE: the user has
|
||||
// to actually delete the link for this to work. A deleted link can be detected by calling
|
||||
// IsLinkDestroyed() after EndNodeEditor().
|
||||
const bool* Modifier;
|
||||
} LinkDetachWithModifierClick;
|
||||
|
||||
struct MultipleSelectModifier
|
||||
{
|
||||
MultipleSelectModifier();
|
||||
|
||||
// Pointer to a boolean value indicating when the desired modifier is pressed. Set to NULL
|
||||
// by default. To enable the feature, set the modifier to point to a boolean indicating the
|
||||
// state of a modifier. For example,
|
||||
//
|
||||
// ImNodes::GetIO().MultipleSelectModifier.Modifier = &ImGui::GetIO().KeyCtrl;
|
||||
//
|
||||
// Left-clicking a node with this modifier pressed will add the node to the list of
|
||||
// currently selected nodes. If this value is NULL, the Ctrl key will be used.
|
||||
const bool* Modifier;
|
||||
} MultipleSelectModifier;
|
||||
|
||||
// Holding alt mouse button pans the node area, by default middle mouse button will be used
|
||||
// Set based on ImGuiMouseButton values
|
||||
int AltMouseButton;
|
||||
|
||||
// Panning speed when dragging an element and mouse is outside the main editor view.
|
||||
float AutoPanningSpeed;
|
||||
|
||||
ImNodesIO();
|
||||
};
|
||||
|
||||
struct ImNodesStyle
|
||||
{
|
||||
float GridSpacing;
|
||||
|
||||
float NodeCornerRounding;
|
||||
ImVec2 NodePadding;
|
||||
float NodeBorderThickness;
|
||||
|
||||
float LinkThickness;
|
||||
float LinkLineSegmentsPerLength;
|
||||
float LinkHoverDistance;
|
||||
|
||||
// The following variables control the look and behavior of the pins. The default size of each
|
||||
// pin shape is balanced to occupy approximately the same surface area on the screen.
|
||||
|
||||
// The circle radius used when the pin shape is either ImNodesPinShape_Circle or
|
||||
// ImNodesPinShape_CircleFilled.
|
||||
float PinCircleRadius;
|
||||
// The quad side length used when the shape is either ImNodesPinShape_Quad or
|
||||
// ImNodesPinShape_QuadFilled.
|
||||
float PinQuadSideLength;
|
||||
// The equilateral triangle side length used when the pin shape is either
|
||||
// ImNodesPinShape_Triangle or ImNodesPinShape_TriangleFilled.
|
||||
float PinTriangleSideLength;
|
||||
// The thickness of the line used when the pin shape is not filled.
|
||||
float PinLineThickness;
|
||||
// The radius from the pin's center position inside of which it is detected as being hovered
|
||||
// over.
|
||||
float PinHoverRadius;
|
||||
// Offsets the pins' positions from the edge of the node to the outside of the node.
|
||||
float PinOffset;
|
||||
|
||||
// Mini-map padding size between mini-map edge and mini-map content.
|
||||
ImVec2 MiniMapPadding;
|
||||
// Mini-map offset from the screen side.
|
||||
ImVec2 MiniMapOffset;
|
||||
|
||||
// By default, ImNodesStyleFlags_NodeOutline and ImNodesStyleFlags_Gridlines are enabled.
|
||||
ImNodesStyleFlags Flags;
|
||||
// Set these mid-frame using Push/PopColorStyle. You can index this color array with with a
|
||||
// ImNodesCol value.
|
||||
unsigned int Colors[ImNodesCol_COUNT];
|
||||
|
||||
ImNodesStyle();
|
||||
};
|
||||
|
||||
enum ImNodesMiniMapLocation_
|
||||
{
|
||||
ImNodesMiniMapLocation_BottomLeft,
|
||||
ImNodesMiniMapLocation_BottomRight,
|
||||
ImNodesMiniMapLocation_TopLeft,
|
||||
ImNodesMiniMapLocation_TopRight,
|
||||
};
|
||||
|
||||
struct ImGuiContext;
|
||||
struct ImVec2;
|
||||
|
||||
struct ImNodesContext;
|
||||
|
||||
// An editor context corresponds to a set of nodes in a single workspace (created with a single
|
||||
// Begin/EndNodeEditor pair)
|
||||
//
|
||||
// By default, the library creates an editor context behind the scenes, so using any of the imnodes
|
||||
// functions doesn't require you to explicitly create a context.
|
||||
struct ImNodesEditorContext;
|
||||
|
||||
// Callback type used to specify special behavior when hovering a node in the minimap
|
||||
#ifndef ImNodesMiniMapNodeHoveringCallback
|
||||
typedef void (*ImNodesMiniMapNodeHoveringCallback)(int, void*);
|
||||
#endif
|
||||
|
||||
#ifndef ImNodesMiniMapNodeHoveringCallbackUserData
|
||||
typedef void* ImNodesMiniMapNodeHoveringCallbackUserData;
|
||||
#endif
|
||||
|
||||
namespace IMNODES_NAMESPACE
|
||||
{
|
||||
// Call this function if you are compiling imnodes in to a dll, separate from ImGui. Calling this
|
||||
// function sets the GImGui global variable, which is not shared across dll boundaries.
|
||||
void SetImGuiContext(ImGuiContext* ctx);
|
||||
|
||||
ImNodesContext* CreateContext();
|
||||
void DestroyContext(ImNodesContext* ctx = NULL); // NULL = destroy current context
|
||||
ImNodesContext* GetCurrentContext();
|
||||
void SetCurrentContext(ImNodesContext* ctx);
|
||||
|
||||
ImNodesEditorContext* EditorContextCreate();
|
||||
void EditorContextFree(ImNodesEditorContext*);
|
||||
void EditorContextSet(ImNodesEditorContext*);
|
||||
ImVec2 EditorContextGetPanning();
|
||||
void EditorContextResetPanning(const ImVec2& pos);
|
||||
void EditorContextMoveToNode(const int node_id);
|
||||
|
||||
ImNodesIO& GetIO();
|
||||
|
||||
// Returns the global style struct. See the struct declaration for default values.
|
||||
ImNodesStyle& GetStyle();
|
||||
// Style presets matching the dear imgui styles of the same name. If dest is NULL, the active
|
||||
// context's ImNodesStyle instance will be used as the destination.
|
||||
void StyleColorsDark(ImNodesStyle* dest = NULL); // on by default
|
||||
void StyleColorsClassic(ImNodesStyle* dest = NULL);
|
||||
void StyleColorsLight(ImNodesStyle* dest = NULL);
|
||||
|
||||
// The top-level function call. Call this before calling BeginNode/EndNode. Calling this function
|
||||
// will result the node editor grid workspace being rendered.
|
||||
void BeginNodeEditor();
|
||||
void EndNodeEditor();
|
||||
|
||||
// Add a navigable minimap to the editor; call before EndNodeEditor after all
|
||||
// nodes and links have been specified
|
||||
void MiniMap(
|
||||
const float minimap_size_fraction = 0.2f,
|
||||
const ImNodesMiniMapLocation location = ImNodesMiniMapLocation_TopLeft,
|
||||
const ImNodesMiniMapNodeHoveringCallback node_hovering_callback = NULL,
|
||||
const ImNodesMiniMapNodeHoveringCallbackUserData node_hovering_callback_data = NULL);
|
||||
|
||||
// Use PushColorStyle and PopColorStyle to modify ImNodesStyle::Colors mid-frame.
|
||||
void PushColorStyle(ImNodesCol item, unsigned int color);
|
||||
void PopColorStyle();
|
||||
void PushStyleVar(ImNodesStyleVar style_item, float value);
|
||||
void PushStyleVar(ImNodesStyleVar style_item, const ImVec2& value);
|
||||
void PopStyleVar(int count = 1);
|
||||
|
||||
// id can be any positive or negative integer, but INT_MIN is currently reserved for internal use.
|
||||
void BeginNode(int id);
|
||||
void EndNode();
|
||||
|
||||
ImVec2 GetNodeDimensions(int id);
|
||||
|
||||
// Place your node title bar content (such as the node title, using ImGui::Text) between the
|
||||
// following function calls. These functions have to be called before adding any attributes, or the
|
||||
// layout of the node will be incorrect.
|
||||
void BeginNodeTitleBar();
|
||||
void EndNodeTitleBar();
|
||||
|
||||
// Attributes are ImGui UI elements embedded within the node. Attributes can have pin shapes
|
||||
// rendered next to them. Links are created between pins.
|
||||
//
|
||||
// The activity status of an attribute can be checked via the IsAttributeActive() and
|
||||
// IsAnyAttributeActive() function calls. This is one easy way of checking for any changes made to
|
||||
// an attribute's drag float UI, for instance.
|
||||
//
|
||||
// Each attribute id must be unique.
|
||||
|
||||
// Create an input attribute block. The pin is rendered on left side.
|
||||
void BeginInputAttribute(int id, ImNodesPinShape shape = ImNodesPinShape_CircleFilled);
|
||||
void EndInputAttribute();
|
||||
// Create an output attribute block. The pin is rendered on the right side.
|
||||
void BeginOutputAttribute(int id, ImNodesPinShape shape = ImNodesPinShape_CircleFilled);
|
||||
void EndOutputAttribute();
|
||||
// Create a static attribute block. A static attribute has no pin, and therefore can't be linked to
|
||||
// anything. However, you can still use IsAttributeActive() and IsAnyAttributeActive() to check for
|
||||
// attribute activity.
|
||||
void BeginStaticAttribute(int id);
|
||||
void EndStaticAttribute();
|
||||
|
||||
// Push a single AttributeFlags value. By default, only AttributeFlags_None is set.
|
||||
void PushAttributeFlag(ImNodesAttributeFlags flag);
|
||||
void PopAttributeFlag();
|
||||
|
||||
// Render a link between attributes.
|
||||
// The attributes ids used here must match the ids used in Begin(Input|Output)Attribute function
|
||||
// calls. The order of start_attr and end_attr doesn't make a difference for rendering the link.
|
||||
void Link(int id, int start_attribute_id, int end_attribute_id);
|
||||
|
||||
// Enable or disable the ability to click and drag a specific node.
|
||||
void SetNodeDraggable(int node_id, const bool draggable);
|
||||
|
||||
// The node's position can be expressed in three coordinate systems:
|
||||
// * screen space coordinates, -- the origin is the upper left corner of the window.
|
||||
// * editor space coordinates -- the origin is the upper left corner of the node editor window
|
||||
// * grid space coordinates, -- the origin is the upper left corner of the node editor window,
|
||||
// translated by the current editor panning vector (see EditorContextGetPanning() and
|
||||
// EditorContextResetPanning())
|
||||
|
||||
// Use the following functions to get and set the node's coordinates in these coordinate systems.
|
||||
|
||||
void SetNodeScreenSpacePos(int node_id, const ImVec2& screen_space_pos);
|
||||
void SetNodeEditorSpacePos(int node_id, const ImVec2& editor_space_pos);
|
||||
void SetNodeGridSpacePos(int node_id, const ImVec2& grid_pos);
|
||||
|
||||
ImVec2 GetNodeScreenSpacePos(const int node_id);
|
||||
ImVec2 GetNodeEditorSpacePos(const int node_id);
|
||||
ImVec2 GetNodeGridSpacePos(const int node_id);
|
||||
|
||||
// If ImNodesStyleFlags_GridSnapping is enabled, snap the specified node's origin to the grid.
|
||||
void SnapNodeToGrid(int node_id);
|
||||
|
||||
// Returns true if the current node editor canvas is being hovered over by the mouse, and is not
|
||||
// blocked by any other windows.
|
||||
bool IsEditorHovered();
|
||||
// The following functions return true if a UI element is being hovered over by the mouse cursor.
|
||||
// Assigns the id of the UI element being hovered over to the function argument. Use these functions
|
||||
// after EndNodeEditor() has been called.
|
||||
bool IsNodeHovered(int* node_id);
|
||||
bool IsLinkHovered(int* link_id);
|
||||
bool IsPinHovered(int* attribute_id);
|
||||
|
||||
// Use The following two functions to query the number of selected nodes or links in the current
|
||||
// editor. Use after calling EndNodeEditor().
|
||||
int NumSelectedNodes();
|
||||
int NumSelectedLinks();
|
||||
// Get the selected node/link ids. The pointer argument should point to an integer array with at
|
||||
// least as many elements as the respective NumSelectedNodes/NumSelectedLinks function call
|
||||
// returned.
|
||||
void GetSelectedNodes(int* node_ids);
|
||||
void GetSelectedLinks(int* link_ids);
|
||||
// Clears the list of selected nodes/links. Useful if you want to delete a selected node or link.
|
||||
void ClearNodeSelection();
|
||||
void ClearLinkSelection();
|
||||
// Use the following functions to add or remove individual nodes or links from the current editors
|
||||
// selection. Note that all functions require the id to be an existing valid id for this editor.
|
||||
// Select-functions has the precondition that the object is currently considered unselected.
|
||||
// Clear-functions has the precondition that the object is currently considered selected.
|
||||
// Preconditions listed above can be checked via IsNodeSelected/IsLinkSelected if not already
|
||||
// known.
|
||||
void SelectNode(int node_id);
|
||||
void ClearNodeSelection(int node_id);
|
||||
bool IsNodeSelected(int node_id);
|
||||
void SelectLink(int link_id);
|
||||
void ClearLinkSelection(int link_id);
|
||||
bool IsLinkSelected(int link_id);
|
||||
|
||||
// Was the previous attribute active? This will continuously return true while the left mouse button
|
||||
// is being pressed over the UI content of the attribute.
|
||||
bool IsAttributeActive();
|
||||
// Was any attribute active? If so, sets the active attribute id to the output function argument.
|
||||
bool IsAnyAttributeActive(int* attribute_id = NULL);
|
||||
|
||||
// Use the following functions to query a change of state for an existing link, or new link. Call
|
||||
// these after EndNodeEditor().
|
||||
|
||||
// Did the user start dragging a new link from a pin?
|
||||
bool IsLinkStarted(int* started_at_attribute_id);
|
||||
// Did the user drop the dragged link before attaching it to a pin?
|
||||
// There are two different kinds of situations to consider when handling this event:
|
||||
// 1) a link which is created at a pin and then dropped
|
||||
// 2) an existing link which is detached from a pin and then dropped
|
||||
// Use the including_detached_links flag to control whether this function triggers when the user
|
||||
// detaches a link and drops it.
|
||||
bool IsLinkDropped(int* started_at_attribute_id = NULL, bool including_detached_links = true);
|
||||
// Did the user finish creating a new link?
|
||||
bool IsLinkCreated(
|
||||
int* started_at_attribute_id,
|
||||
int* ended_at_attribute_id,
|
||||
bool* created_from_snap = NULL);
|
||||
bool IsLinkCreated(
|
||||
int* started_at_node_id,
|
||||
int* started_at_attribute_id,
|
||||
int* ended_at_node_id,
|
||||
int* ended_at_attribute_id,
|
||||
bool* created_from_snap = NULL);
|
||||
|
||||
// Was an existing link detached from a pin by the user? The detached link's id is assigned to the
|
||||
// output argument link_id.
|
||||
bool IsLinkDestroyed(int* link_id);
|
||||
|
||||
// Use the following functions to write the editor context's state to a string, or directly to a
|
||||
// file. The editor context is serialized in the INI file format.
|
||||
|
||||
const char* SaveCurrentEditorStateToIniString(size_t* data_size = NULL);
|
||||
const char* SaveEditorStateToIniString(
|
||||
const ImNodesEditorContext* editor,
|
||||
size_t* data_size = NULL);
|
||||
|
||||
void LoadCurrentEditorStateFromIniString(const char* data, size_t data_size);
|
||||
void LoadEditorStateFromIniString(ImNodesEditorContext* editor, const char* data, size_t data_size);
|
||||
|
||||
void SaveCurrentEditorStateToIniFile(const char* file_name);
|
||||
void SaveEditorStateToIniFile(const ImNodesEditorContext* editor, const char* file_name);
|
||||
|
||||
void LoadCurrentEditorStateFromIniFile(const char* file_name);
|
||||
void LoadEditorStateFromIniFile(ImNodesEditorContext* editor, const char* file_name);
|
||||
} // namespace IMNODES_NAMESPACE
|
||||
500
Lib/imnodes-master-b2ec254/imnodes_internal.h
Normal file
500
Lib/imnodes-master-b2ec254/imnodes_internal.h
Normal file
@ -0,0 +1,500 @@
|
||||
#pragma once
|
||||
|
||||
#define IMGUI_DEFINE_MATH_OPERATORS
|
||||
#include <imgui.h>
|
||||
#include <imgui_internal.h>
|
||||
|
||||
#include "imnodes.h"
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
// the structure of this file:
|
||||
//
|
||||
// [SECTION] internal enums
|
||||
// [SECTION] internal data structures
|
||||
// [SECTION] global and editor context structs
|
||||
// [SECTION] object pool implementation
|
||||
|
||||
struct ImNodesContext;
|
||||
|
||||
extern ImNodesContext* GImNodes;
|
||||
|
||||
// [SECTION] internal enums
|
||||
|
||||
typedef int ImNodesScope;
|
||||
typedef int ImNodesAttributeType;
|
||||
typedef int ImNodesUIState;
|
||||
typedef int ImNodesClickInteractionType;
|
||||
typedef int ImNodesLinkCreationType;
|
||||
|
||||
enum ImNodesScope_
|
||||
{
|
||||
ImNodesScope_None = 1,
|
||||
ImNodesScope_Editor = 1 << 1,
|
||||
ImNodesScope_Node = 1 << 2,
|
||||
ImNodesScope_Attribute = 1 << 3
|
||||
};
|
||||
|
||||
enum ImNodesAttributeType_
|
||||
{
|
||||
ImNodesAttributeType_None,
|
||||
ImNodesAttributeType_Input,
|
||||
ImNodesAttributeType_Output
|
||||
};
|
||||
|
||||
enum ImNodesUIState_
|
||||
{
|
||||
ImNodesUIState_None = 0,
|
||||
ImNodesUIState_LinkStarted = 1 << 0,
|
||||
ImNodesUIState_LinkDropped = 1 << 1,
|
||||
ImNodesUIState_LinkCreated = 1 << 2
|
||||
};
|
||||
|
||||
enum ImNodesClickInteractionType_
|
||||
{
|
||||
ImNodesClickInteractionType_Node,
|
||||
ImNodesClickInteractionType_Link,
|
||||
ImNodesClickInteractionType_LinkCreation,
|
||||
ImNodesClickInteractionType_Panning,
|
||||
ImNodesClickInteractionType_BoxSelection,
|
||||
ImNodesClickInteractionType_ImGuiItem,
|
||||
ImNodesClickInteractionType_None
|
||||
};
|
||||
|
||||
enum ImNodesLinkCreationType_
|
||||
{
|
||||
ImNodesLinkCreationType_Standard,
|
||||
ImNodesLinkCreationType_FromDetach
|
||||
};
|
||||
|
||||
// [SECTION] internal data structures
|
||||
|
||||
// The object T must have the following interface:
|
||||
//
|
||||
// struct T
|
||||
// {
|
||||
// T();
|
||||
//
|
||||
// int id;
|
||||
// };
|
||||
template<typename T>
|
||||
struct ImObjectPool
|
||||
{
|
||||
ImVector<T> Pool;
|
||||
ImVector<bool> InUse;
|
||||
ImVector<int> FreeList;
|
||||
ImGuiStorage IdMap;
|
||||
|
||||
ImObjectPool() : Pool(), InUse(), FreeList(), IdMap() {}
|
||||
};
|
||||
|
||||
// Emulates std::optional<int> using the sentinel value `INVALID_INDEX`.
|
||||
struct ImOptionalIndex
|
||||
{
|
||||
ImOptionalIndex() : _Index(INVALID_INDEX) {}
|
||||
ImOptionalIndex(const int value) : _Index(value) {}
|
||||
|
||||
// Observers
|
||||
|
||||
inline bool HasValue() const { return _Index != INVALID_INDEX; }
|
||||
|
||||
inline int Value() const
|
||||
{
|
||||
IM_ASSERT(HasValue());
|
||||
return _Index;
|
||||
}
|
||||
|
||||
// Modifiers
|
||||
|
||||
inline ImOptionalIndex& operator=(const int value)
|
||||
{
|
||||
_Index = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline void Reset() { _Index = INVALID_INDEX; }
|
||||
|
||||
inline bool operator==(const ImOptionalIndex& rhs) const { return _Index == rhs._Index; }
|
||||
|
||||
inline bool operator==(const int rhs) const { return _Index == rhs; }
|
||||
|
||||
inline bool operator!=(const ImOptionalIndex& rhs) const { return _Index != rhs._Index; }
|
||||
|
||||
inline bool operator!=(const int rhs) const { return _Index != rhs; }
|
||||
|
||||
static const int INVALID_INDEX = -1;
|
||||
|
||||
private:
|
||||
int _Index;
|
||||
};
|
||||
|
||||
struct ImNodeData
|
||||
{
|
||||
int Id;
|
||||
ImVec2 Origin; // The node origin is in editor space
|
||||
ImRect TitleBarContentRect;
|
||||
ImRect Rect;
|
||||
|
||||
struct
|
||||
{
|
||||
ImU32 Background, BackgroundHovered, BackgroundSelected, Outline, Titlebar, TitlebarHovered,
|
||||
TitlebarSelected;
|
||||
} ColorStyle;
|
||||
|
||||
struct
|
||||
{
|
||||
float CornerRounding;
|
||||
ImVec2 Padding;
|
||||
float BorderThickness;
|
||||
} LayoutStyle;
|
||||
|
||||
ImVector<int> PinIndices;
|
||||
bool Draggable;
|
||||
|
||||
ImNodeData(const int node_id)
|
||||
: Id(node_id), Origin(0.0f, 0.0f), TitleBarContentRect(),
|
||||
Rect(ImVec2(0.0f, 0.0f), ImVec2(0.0f, 0.0f)), ColorStyle(), LayoutStyle(), PinIndices(),
|
||||
Draggable(true)
|
||||
{
|
||||
}
|
||||
|
||||
~ImNodeData() { Id = INT_MIN; }
|
||||
};
|
||||
|
||||
struct ImPinData
|
||||
{
|
||||
int Id;
|
||||
int ParentNodeIdx;
|
||||
ImRect AttributeRect;
|
||||
ImNodesAttributeType Type;
|
||||
ImNodesPinShape Shape;
|
||||
ImVec2 Pos; // screen-space coordinates
|
||||
int Flags;
|
||||
|
||||
struct
|
||||
{
|
||||
ImU32 Background, Hovered;
|
||||
} ColorStyle;
|
||||
|
||||
ImPinData(const int pin_id)
|
||||
: Id(pin_id), ParentNodeIdx(), AttributeRect(), Type(ImNodesAttributeType_None),
|
||||
Shape(ImNodesPinShape_CircleFilled), Pos(), Flags(ImNodesAttributeFlags_None),
|
||||
ColorStyle()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct ImLinkData
|
||||
{
|
||||
int Id;
|
||||
int StartPinIdx, EndPinIdx;
|
||||
|
||||
struct
|
||||
{
|
||||
ImU32 Base, Hovered, Selected;
|
||||
} ColorStyle;
|
||||
|
||||
ImLinkData(const int link_id) : Id(link_id), StartPinIdx(), EndPinIdx(), ColorStyle() {}
|
||||
};
|
||||
|
||||
struct ImClickInteractionState
|
||||
{
|
||||
ImNodesClickInteractionType Type;
|
||||
|
||||
struct
|
||||
{
|
||||
int StartPinIdx;
|
||||
ImOptionalIndex EndPinIdx;
|
||||
ImNodesLinkCreationType Type;
|
||||
} LinkCreation;
|
||||
|
||||
struct
|
||||
{
|
||||
ImRect Rect; // Coordinates in grid space
|
||||
} BoxSelector;
|
||||
|
||||
ImClickInteractionState() : Type(ImNodesClickInteractionType_None) {}
|
||||
};
|
||||
|
||||
struct ImNodesColElement
|
||||
{
|
||||
ImU32 Color;
|
||||
ImNodesCol Item;
|
||||
|
||||
ImNodesColElement(const ImU32 c, const ImNodesCol s) : Color(c), Item(s) {}
|
||||
};
|
||||
|
||||
struct ImNodesStyleVarElement
|
||||
{
|
||||
ImNodesStyleVar Item;
|
||||
float FloatValue[2];
|
||||
|
||||
ImNodesStyleVarElement(const ImNodesStyleVar variable, const float value) : Item(variable)
|
||||
{
|
||||
FloatValue[0] = value;
|
||||
}
|
||||
|
||||
ImNodesStyleVarElement(const ImNodesStyleVar variable, const ImVec2 value) : Item(variable)
|
||||
{
|
||||
FloatValue[0] = value.x;
|
||||
FloatValue[1] = value.y;
|
||||
}
|
||||
};
|
||||
|
||||
// [SECTION] global and editor context structs
|
||||
|
||||
struct ImNodesEditorContext
|
||||
{
|
||||
ImObjectPool<ImNodeData> Nodes;
|
||||
ImObjectPool<ImPinData> Pins;
|
||||
ImObjectPool<ImLinkData> Links;
|
||||
|
||||
ImVector<int> NodeDepthOrder;
|
||||
|
||||
// ui related fields
|
||||
ImVec2 Panning;
|
||||
ImVec2 AutoPanningDelta;
|
||||
// Minimum and maximum extents of all content in grid space. Valid after final
|
||||
// ImNodes::EndNode() call.
|
||||
ImRect GridContentBounds;
|
||||
|
||||
ImVector<int> SelectedNodeIndices;
|
||||
ImVector<int> SelectedLinkIndices;
|
||||
|
||||
// Relative origins of selected nodes for snapping of dragged nodes
|
||||
ImVector<ImVec2> SelectedNodeOffsets;
|
||||
// Offset of the primary node origin relative to the mouse cursor.
|
||||
ImVec2 PrimaryNodeOffset;
|
||||
|
||||
ImClickInteractionState ClickInteraction;
|
||||
|
||||
// Mini-map state set by MiniMap()
|
||||
|
||||
bool MiniMapEnabled;
|
||||
ImNodesMiniMapLocation MiniMapLocation;
|
||||
float MiniMapSizeFraction;
|
||||
ImNodesMiniMapNodeHoveringCallback MiniMapNodeHoveringCallback;
|
||||
ImNodesMiniMapNodeHoveringCallbackUserData MiniMapNodeHoveringCallbackUserData;
|
||||
|
||||
// Mini-map state set during EndNodeEditor() call
|
||||
|
||||
ImRect MiniMapRectScreenSpace;
|
||||
ImRect MiniMapContentScreenSpace;
|
||||
float MiniMapScaling;
|
||||
|
||||
ImNodesEditorContext()
|
||||
: Nodes(), Pins(), Links(), Panning(0.f, 0.f), SelectedNodeIndices(), SelectedLinkIndices(),
|
||||
SelectedNodeOffsets(), PrimaryNodeOffset(0.f, 0.f), ClickInteraction(),
|
||||
MiniMapEnabled(false), MiniMapSizeFraction(0.0f), MiniMapNodeHoveringCallback(NULL),
|
||||
MiniMapNodeHoveringCallbackUserData(NULL), MiniMapScaling(0.0f)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct ImNodesContext
|
||||
{
|
||||
ImNodesEditorContext* DefaultEditorCtx;
|
||||
ImNodesEditorContext* EditorCtx;
|
||||
|
||||
// Canvas draw list and helper state
|
||||
ImDrawList* CanvasDrawList;
|
||||
ImGuiStorage NodeIdxToSubmissionIdx;
|
||||
ImVector<int> NodeIdxSubmissionOrder;
|
||||
ImVector<int> NodeIndicesOverlappingWithMouse;
|
||||
ImVector<int> OccludedPinIndices;
|
||||
|
||||
// Canvas extents
|
||||
ImVec2 CanvasOriginScreenSpace;
|
||||
ImRect CanvasRectScreenSpace;
|
||||
|
||||
// Debug helpers
|
||||
ImNodesScope CurrentScope;
|
||||
|
||||
// Configuration state
|
||||
ImNodesIO Io;
|
||||
ImNodesStyle Style;
|
||||
ImVector<ImNodesColElement> ColorModifierStack;
|
||||
ImVector<ImNodesStyleVarElement> StyleModifierStack;
|
||||
ImGuiTextBuffer TextBuffer;
|
||||
|
||||
int CurrentAttributeFlags;
|
||||
ImVector<int> AttributeFlagStack;
|
||||
|
||||
// UI element state
|
||||
int CurrentNodeIdx;
|
||||
int CurrentPinIdx;
|
||||
int CurrentAttributeId;
|
||||
|
||||
ImOptionalIndex HoveredNodeIdx;
|
||||
ImOptionalIndex HoveredLinkIdx;
|
||||
ImOptionalIndex HoveredPinIdx;
|
||||
|
||||
ImOptionalIndex DeletedLinkIdx;
|
||||
ImOptionalIndex SnapLinkIdx;
|
||||
|
||||
// Event helper state
|
||||
// TODO: this should be a part of a state machine, and not a member of the global struct.
|
||||
// Unclear what parts of the code this relates to.
|
||||
int ImNodesUIState;
|
||||
|
||||
int ActiveAttributeId;
|
||||
bool ActiveAttribute;
|
||||
|
||||
// ImGui::IO cache
|
||||
|
||||
ImVec2 MousePos;
|
||||
|
||||
bool LeftMouseClicked;
|
||||
bool LeftMouseReleased;
|
||||
bool AltMouseClicked;
|
||||
bool LeftMouseDragging;
|
||||
bool AltMouseDragging;
|
||||
float AltMouseScrollDelta;
|
||||
bool MultipleSelectModifier;
|
||||
};
|
||||
|
||||
namespace IMNODES_NAMESPACE
|
||||
{
|
||||
static inline ImNodesEditorContext& EditorContextGet()
|
||||
{
|
||||
// No editor context was set! Did you forget to call ImNodes::CreateContext()?
|
||||
IM_ASSERT(GImNodes->EditorCtx != NULL);
|
||||
return *GImNodes->EditorCtx;
|
||||
}
|
||||
|
||||
// [SECTION] ObjectPool implementation
|
||||
|
||||
template<typename T>
|
||||
static inline int ObjectPoolFind(const ImObjectPool<T>& objects, const int id)
|
||||
{
|
||||
const int index = objects.IdMap.GetInt(static_cast<ImGuiID>(id), -1);
|
||||
return index;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline void ObjectPoolUpdate(ImObjectPool<T>& objects)
|
||||
{
|
||||
for (int i = 0; i < objects.InUse.size(); ++i)
|
||||
{
|
||||
const int id = objects.Pool[i].Id;
|
||||
|
||||
if (!objects.InUse[i] && objects.IdMap.GetInt(id, -1) == i)
|
||||
{
|
||||
objects.IdMap.SetInt(id, -1);
|
||||
objects.FreeList.push_back(i);
|
||||
(objects.Pool.Data + i)->~T();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<>
|
||||
inline void ObjectPoolUpdate(ImObjectPool<ImNodeData>& nodes)
|
||||
{
|
||||
for (int i = 0; i < nodes.InUse.size(); ++i)
|
||||
{
|
||||
if (nodes.InUse[i])
|
||||
{
|
||||
nodes.Pool[i].PinIndices.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
const int id = nodes.Pool[i].Id;
|
||||
|
||||
if (nodes.IdMap.GetInt(id, -1) == i)
|
||||
{
|
||||
// Remove node idx form depth stack the first time we detect that this idx slot is
|
||||
// unused
|
||||
ImVector<int>& depth_stack = EditorContextGet().NodeDepthOrder;
|
||||
const int* const elem = depth_stack.find(i);
|
||||
IM_ASSERT(elem != depth_stack.end());
|
||||
depth_stack.erase(elem);
|
||||
|
||||
nodes.IdMap.SetInt(id, -1);
|
||||
nodes.FreeList.push_back(i);
|
||||
(nodes.Pool.Data + i)->~ImNodeData();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline void ObjectPoolReset(ImObjectPool<T>& objects)
|
||||
{
|
||||
if (!objects.InUse.empty())
|
||||
{
|
||||
memset(objects.InUse.Data, 0, objects.InUse.size_in_bytes());
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline int ObjectPoolFindOrCreateIndex(ImObjectPool<T>& objects, const int id)
|
||||
{
|
||||
int index = objects.IdMap.GetInt(static_cast<ImGuiID>(id), -1);
|
||||
|
||||
// Construct new object
|
||||
if (index == -1)
|
||||
{
|
||||
if (objects.FreeList.empty())
|
||||
{
|
||||
index = objects.Pool.size();
|
||||
IM_ASSERT(objects.Pool.size() == objects.InUse.size());
|
||||
const int new_size = objects.Pool.size() + 1;
|
||||
objects.Pool.resize(new_size);
|
||||
objects.InUse.resize(new_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
index = objects.FreeList.back();
|
||||
objects.FreeList.pop_back();
|
||||
}
|
||||
IM_PLACEMENT_NEW(objects.Pool.Data + index) T(id);
|
||||
objects.IdMap.SetInt(static_cast<ImGuiID>(id), index);
|
||||
}
|
||||
|
||||
// Flag it as used
|
||||
objects.InUse[index] = true;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline int ObjectPoolFindOrCreateIndex(ImObjectPool<ImNodeData>& nodes, const int node_id)
|
||||
{
|
||||
int node_idx = nodes.IdMap.GetInt(static_cast<ImGuiID>(node_id), -1);
|
||||
|
||||
// Construct new node
|
||||
if (node_idx == -1)
|
||||
{
|
||||
if (nodes.FreeList.empty())
|
||||
{
|
||||
node_idx = nodes.Pool.size();
|
||||
IM_ASSERT(nodes.Pool.size() == nodes.InUse.size());
|
||||
const int new_size = nodes.Pool.size() + 1;
|
||||
nodes.Pool.resize(new_size);
|
||||
nodes.InUse.resize(new_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
node_idx = nodes.FreeList.back();
|
||||
nodes.FreeList.pop_back();
|
||||
}
|
||||
IM_PLACEMENT_NEW(nodes.Pool.Data + node_idx) ImNodeData(node_id);
|
||||
nodes.IdMap.SetInt(static_cast<ImGuiID>(node_id), node_idx);
|
||||
|
||||
ImNodesEditorContext& editor = EditorContextGet();
|
||||
editor.NodeDepthOrder.push_back(node_idx);
|
||||
}
|
||||
|
||||
// Flag node as used
|
||||
nodes.InUse[node_idx] = true;
|
||||
|
||||
return node_idx;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline T& ObjectPoolFindOrCreateObject(ImObjectPool<T>& objects, const int id)
|
||||
{
|
||||
const int index = ObjectPoolFindOrCreateIndex(objects, id);
|
||||
return objects.Pool[index];
|
||||
}
|
||||
} // namespace IMNODES_NAMESPACE
|
||||
11
Lib/imnodes-master-b2ec254/vcpkg.json
Normal file
11
Lib/imnodes-master-b2ec254/vcpkg.json
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "imnodes",
|
||||
"version-string": "0.1.0-dev",
|
||||
"dependencies": [
|
||||
"sdl2",
|
||||
{
|
||||
"name": "imgui",
|
||||
"features": [ "sdl2-binding", "opengl3-binding" ]
|
||||
}
|
||||
]
|
||||
}
|
||||
4
Makefile
4
Makefile
@ -79,6 +79,7 @@ CXX_INCLUDES_PATHS = \
|
||||
Inc \
|
||||
Lib/imgui-1.92.4-docking \
|
||||
Lib/imgui-1.92.4-docking/backends \
|
||||
Lib/imnodes-master-b2ec254 \
|
||||
|
||||
# C++源文件目录
|
||||
CXX_SOURCES_PATHS = \
|
||||
@ -93,7 +94,8 @@ Lib/imgui-1.92.4-docking/imgui_tables.cpp \
|
||||
Lib/imgui-1.92.4-docking/imgui_widgets.cpp \
|
||||
Lib/imgui-1.92.4-docking/backends/imgui_impl_dx11.cpp \
|
||||
Lib/imgui-1.92.4-docking/backends/imgui_impl_win32.cpp \
|
||||
# Lib/imgui-1.92.4-docking/examples/example_win32_directx11/main.cpp \
|
||||
\
|
||||
Lib/imnodes-master-b2ec254/imnodes.cpp \
|
||||
|
||||
# Windows 资源文件脚本头文件路径
|
||||
WIN_RESOURCE_INCLUDES_PATHS = \
|
||||
|
||||
@ -3,6 +3,9 @@
|
||||
#include "imgui_impl_win32.h"
|
||||
#include "imgui_impl_dx11.h"
|
||||
|
||||
// ImNodes相关
|
||||
#include "imnodes.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
// Mingw 相关库
|
||||
@ -87,6 +90,9 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
|
||||
// 建立 Dear ImGui 上下文
|
||||
ImGui::CreateContext();
|
||||
|
||||
// 建立ImNodes 上下文
|
||||
ImNodes::CreateContext();
|
||||
|
||||
// 获取ImGui IO 设备配置结构体
|
||||
ImGuiIO &io = ImGui::GetIO();
|
||||
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
|
||||
@ -220,6 +226,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
|
||||
ImGui_ImplDX11_Shutdown(); // 关闭 ImGui DX11 组件
|
||||
ImGui_ImplWin32_Shutdown(); // 关闭 ImGui Win32 组件
|
||||
ImGui::DestroyContext(); // 销毁 ImGui 上下文
|
||||
ImNodes::DestroyContext(); // 销毁 ImNodes 上下文
|
||||
|
||||
CleanupDeviceD3D(); // 清理 Direct 3D 设备
|
||||
DestroyWindow(hwnd); // 销毁窗体
|
||||
|
||||
@ -24,10 +24,30 @@ void UI_Layout()
|
||||
// 设置窗体相关属性,不允许停靠
|
||||
window_flags |= ImGuiWindowFlags_NoDocking;
|
||||
|
||||
ImGui::Begin("Main Panel", NULL, window_flags);
|
||||
ImGui::Begin("Main Panel", NULL, window_flags); // 创建Label
|
||||
ImGui::PopStyleVar(2); // 退出绘制风格栈中的设置项
|
||||
{
|
||||
// 退出绘制风格栈中的设置项
|
||||
ImGui::PopStyleVar(2);
|
||||
|
||||
ImNodes::BeginNodeEditor();
|
||||
{
|
||||
|
||||
ImNodes::BeginNode(1);
|
||||
|
||||
ImNodes::BeginNodeTitleBar();
|
||||
ImGui::TextUnformatted("output node");
|
||||
ImNodes::EndNodeTitleBar();
|
||||
|
||||
ImGui::Text("Test Format %%d :%d", 123);
|
||||
|
||||
ImGui::Button("Click");
|
||||
|
||||
ImGui::SameLine();
|
||||
static bool check = false;
|
||||
ImGui::Checkbox("", &check);
|
||||
|
||||
ImNodes::EndNode();
|
||||
}
|
||||
ImNodes::EndNodeEditor();
|
||||
}
|
||||
ImGui::End();
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user