├── README.md └── workingMenu16.4 ├── Fonts.hpp ├── KittyMemory ├── KittyMemory.cpp ├── KittyMemory.hpp ├── KittyUtils.cpp ├── KittyUtils.hpp ├── MemoryBackup.cpp ├── MemoryBackup.hpp ├── MemoryPatch.cpp ├── MemoryPatch.hpp ├── Read Me.txt ├── defs.h ├── imconfig.h ├── imgui.cpp ├── imgui.h ├── imgui_demo.cpp ├── imgui_draw.cpp ├── imgui_impl_metal.h ├── imgui_impl_metal.mm ├── imgui_internal.h ├── imgui_memory_editor.h ├── imgui_tables.cpp ├── imgui_widgets.cpp ├── imstb_rectpack.h ├── imstb_textedit.h ├── imstb_truetype.h ├── initializer_list ├── writeData.cpp └── writeData.hpp ├── Makefile ├── Menu.h ├── Menu.mm ├── MenuLoad ├── ImGuiDrawView.h ├── ImGuiDrawView.xm ├── Includes.h ├── MenuLoad.h └── MenuLoad.mm ├── ModMenu.plist ├── UserMenu.h ├── UserMenu.mm ├── control └── packages └── com.newimgui.ark_1_iphoneos-arm.deb /README.md: -------------------------------------------------------------------------------- 1 | # AdvancedModMenuTemplate 2 | Clean & Easy to setup mod menu. Uses ImGui. Has built in streamer mode (hide the menu while recording). 3 | 4 | https://ibb.co/SQ2rXNj 5 | -------------------------------------------------------------------------------- /workingMenu16.4/KittyMemory/KittyMemory.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // KittyMemory.cpp 3 | // 4 | // 5 | // Created by MJ (Ruit) on 1/1/19. 6 | // 7 | // 8 | 9 | #include "KittyMemory.hpp" 10 | #include 11 | 12 | 13 | using KittyMemory::Memory_Status; 14 | 15 | 16 | // may not be accurate 17 | static bool cydiaExist(){ 18 | bool ret = false; 19 | FILE *f = NULL; 20 | if(( f = fopen( "/Applications/Cydia.app" , "r" ) ) 21 | || ( f = fopen( "/Library/MobileSubstrate/MobileSubstrate.dylib" , "r" ) )){ 22 | ret = true; 23 | } 24 | if(f != NULL){ 25 | fclose(f); 26 | } 27 | return ret; 28 | } 29 | 30 | typedef void (*MSHookMemory_t)(void *, const void *, size_t); 31 | inline bool findMSHookMemory(void *dst, const void *src, size_t len){ 32 | static void *ret = MSFindSymbol(NULL, "_MSHookMemory"); 33 | if(ret != NULL){ 34 | reinterpret_cast(ret)(dst, src, len); 35 | return true; 36 | } 37 | return false; 38 | } 39 | 40 | 41 | extern "C" kern_return_t mach_vm_remap(vm_map_t, mach_vm_address_t *, mach_vm_size_t, 42 | mach_vm_offset_t, int, vm_map_t, mach_vm_address_t, 43 | boolean_t, vm_prot_t *, vm_prot_t *, vm_inherit_t); 44 | 45 | 46 | bool KittyMemory::ProtectAddr(void *address, size_t length, int protection, bool aligned) { 47 | if(aligned) 48 | return mprotect(address, length, protection) != -1; 49 | 50 | uintptr_t pageStart = _PAGE_START_OF_(address); 51 | uintptr_t pageLen = _PAGE_LEN_OF_(address, length); 52 | return mprotect(reinterpret_cast(pageStart), pageLen, protection) != -1; 53 | } 54 | 55 | 56 | kern_return_t KittyMemory::getPageInfo(void *page_start, vm_region_submap_short_info_64 *outInfo) { 57 | vm_address_t region = reinterpret_cast(page_start); 58 | vm_size_t region_len = 0; 59 | mach_msg_type_number_t info_count = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64; 60 | unsigned int depth = 0; 61 | return vm_region_recurse_64(mach_task_self(), ®ion, ®ion_len, 62 | &depth, 63 | (vm_region_recurse_info_t) outInfo, 64 | &info_count); 65 | } 66 | 67 | 68 | /* 69 | refs to 70 | - https://github.com/asLody/whale/blob/master/whale/src/platform/memory.cc 71 | - CydiaSubstrate 72 | */ 73 | Memory_Status KittyMemory::memWrite(void *address, const void *buffer, size_t len) { 74 | if (address == NULL) 75 | return INV_ADDR; 76 | 77 | if (buffer == NULL) 78 | return INV_BUF; 79 | 80 | if (len < 1 || len > INT_MAX) 81 | return INV_LEN; 82 | 83 | // check for MSHookMemory that was added recently, but check for cydia existance first. 84 | if(cydiaExist() && findMSHookMemory(address, buffer, len)){ 85 | return SUCCESS; 86 | } 87 | 88 | void * page_start = reinterpret_cast(_PAGE_START_OF_(address)); 89 | void * page_offset = reinterpret_cast(_PAGE_OFFSET_OF_(address)); 90 | size_t page_len = _PAGE_LEN_OF_(address, len); 91 | 92 | vm_region_submap_short_info_64 page_info; 93 | if(BAD_KERN_CALL(getPageInfo(page_start, &page_info))) 94 | return INV_KERN_CALL; 95 | 96 | if(page_info.protection & VM_PROT_WRITE){ 97 | if(memcpy(address, buffer, len) != NULL){ 98 | return SUCCESS; 99 | } else { 100 | return FAILED; 101 | } 102 | } 103 | 104 | void *new_map = mmap(NULL, page_len, _PROT_RW_, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); 105 | if(new_map == NULL) 106 | return INV_MAP; 107 | 108 | task_t self_task = mach_task_self(); 109 | 110 | 111 | if(BAD_KERN_CALL(vm_copy(self_task, 112 | reinterpret_cast(page_start), page_len, reinterpret_cast(new_map)))) 113 | return INV_KERN_CALL; 114 | 115 | 116 | void *dst = reinterpret_cast(reinterpret_cast(new_map) + reinterpret_cast(page_offset)); 117 | if(memcpy(dst, buffer, len) == NULL || !ProtectAddr(new_map, page_len, _PROT_RX_, true)) 118 | return FAILED; 119 | 120 | vm_prot_t cur_protection, max_protection; 121 | mach_vm_address_t mach_vm_page_start = reinterpret_cast(page_start); 122 | if(BAD_KERN_CALL(mach_vm_remap(self_task, &mach_vm_page_start, page_len, 0, VM_FLAGS_OVERWRITE, 123 | self_task, reinterpret_cast(new_map), TRUE, &cur_protection, &max_protection, 124 | page_info.inheritance))) 125 | return INV_KERN_CALL; 126 | 127 | return SUCCESS; 128 | } 129 | 130 | 131 | Memory_Status KittyMemory::memRead(void *buffer, const void *addr, size_t len) { 132 | if (addr == NULL) 133 | return INV_ADDR; 134 | 135 | if (buffer == NULL) 136 | return INV_BUF; 137 | 138 | if (len < 1 || len > INT_MAX) 139 | return INV_LEN; 140 | 141 | if (memcpy(buffer, addr, len) != NULL) 142 | return SUCCESS; 143 | 144 | return FAILED; 145 | } 146 | 147 | 148 | std::string KittyMemory::read2HexStr(const void *addr, size_t len) { 149 | char temp[len]; 150 | memset(temp, 0, len); 151 | 152 | const size_t bufferLen = len * 2 + 1; 153 | char buffer[bufferLen]; 154 | memset(buffer, 0, bufferLen); 155 | 156 | std::string ret; 157 | 158 | if (memRead(temp, addr, len) != SUCCESS) 159 | return ret; 160 | 161 | for (int i = 0; i < len; i++) { 162 | sprintf(&buffer[i * 2], "%02X", (unsigned char) temp[i]); 163 | } 164 | 165 | ret += buffer; 166 | return ret; 167 | } 168 | 169 | 170 | KittyMemory::memory_file_info KittyMemory::getBaseInfo(){ 171 | memory_file_info _info = { 172 | 0, 173 | _dyld_get_image_header(0), 174 | _dyld_get_image_name(0), 175 | _dyld_get_image_vmaddr_slide(0) 176 | }; 177 | return _info; 178 | } 179 | 180 | 181 | 182 | KittyMemory::memory_file_info KittyMemory::getMemoryFileInfo(const char *fileName){ 183 | memory_file_info _info; 184 | 185 | int imageCount = _dyld_image_count(); 186 | 187 | for(int i = 0; i < imageCount; i++) { 188 | const char *name = _dyld_get_image_name(i); 189 | const mach_header *header = _dyld_get_image_header(i); 190 | if(!strstr(name, fileName)) continue; 191 | 192 | memory_file_info new_info = { 193 | i, header, name, _dyld_get_image_vmaddr_slide(i) 194 | }; 195 | 196 | _info = new_info; 197 | } 198 | return _info; 199 | } 200 | 201 | 202 | uint64_t KittyMemory::getAbsoluteAddress(const char *fileName, uint64_t address){ 203 | memory_file_info info; 204 | if(fileName != NULL){ 205 | info = getMemoryFileInfo(fileName); 206 | } else { 207 | info = getBaseInfo(); 208 | } 209 | if(info.address == 0) 210 | return 0; 211 | return info.address + address; 212 | } 213 | -------------------------------------------------------------------------------- /workingMenu16.4/KittyMemory/KittyMemory.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // KittyMemory.hpp 3 | // 4 | // 5 | // Created by MJ (Ruit) on 1/1/19. 6 | // 7 | // 8 | 9 | #pragma once 10 | 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #define BAD_KERN_CALL(call) call != KERN_SUCCESS 22 | 23 | #define _SYS_PAGE_SIZE_ (sysconf(_SC_PAGE_SIZE)) 24 | 25 | #define _PAGE_START_OF_(x) ((uintptr_t)x & ~(uintptr_t)(_SYS_PAGE_SIZE_ - 1)) 26 | #define _PAGE_END_OF_(x, len) (_PAGE_START_OF_((uintptr_t)x + len - 1)) 27 | #define _PAGE_LEN_OF_(x, len) (_PAGE_END_OF_(x, len) - _PAGE_START_OF_(x) + _SYS_PAGE_SIZE_) 28 | #define _PAGE_OFFSET_OF_(x) ((uintptr_t)x - _PAGE_START_OF_(x)) 29 | 30 | #define _PROT_RWX_ (PROT_READ | PROT_WRITE | PROT_EXEC) 31 | #define _PROT_RX_ (PROT_READ | PROT_EXEC) 32 | #define _PROT_RW_ (PROT_READ | PROT_WRITE) 33 | 34 | 35 | #define EMPTY_VEC_OFFSET std::vector() 36 | 37 | 38 | namespace KittyMemory { 39 | 40 | typedef enum { 41 | FAILED = 0, 42 | SUCCESS = 1, 43 | INV_ADDR = 2, 44 | INV_LEN = 3, 45 | INV_BUF = 4, 46 | INV_PROT = 5, 47 | INV_KERN_CALL = 6, 48 | INV_MAP = 7 49 | } Memory_Status; 50 | 51 | 52 | typedef struct { 53 | int index; 54 | const mach_header *header; 55 | const char *name; 56 | intptr_t address; 57 | } memory_file_info; 58 | 59 | 60 | /* 61 | * Changes protection of an address with given length 62 | */ 63 | bool ProtectAddr(void *address, size_t length, int protection, bool aligned); 64 | 65 | /* 66 | * Writes buffer content to an address 67 | */ 68 | Memory_Status memWrite(void *address, const void *buffer, size_t len); 69 | 70 | /* 71 | * Reads an address content into a buffer 72 | */ 73 | Memory_Status memRead(void *buffer, const void *addr, size_t len); 74 | 75 | /* 76 | * Wrapper to dereference & get value of a multi level pointer 77 | * Make sure to use the correct data type! 78 | */ 79 | template 80 | Type readMultiPtr(void *ptr, std::vector offsets) { 81 | Type defaultVal = {}; 82 | if (ptr == NULL) 83 | return defaultVal; 84 | 85 | uintptr_t finalPtr = reinterpret_cast(ptr); 86 | int offsetsSize = offsets.size(); 87 | if (offsetsSize > 0) { 88 | for (int i = 0; finalPtr != 0 && i < offsetsSize; i++) { 89 | if (i == (offsetsSize - 1)) 90 | return *reinterpret_cast(finalPtr + offsets[i]); 91 | 92 | finalPtr = *reinterpret_cast(finalPtr + offsets[i]); 93 | } 94 | } 95 | 96 | if (finalPtr == 0) 97 | return defaultVal; 98 | 99 | return *reinterpret_cast(finalPtr); 100 | } 101 | 102 | 103 | /* 104 | * Wrapper to dereference & set value of a multi level pointer 105 | * Make sure to use the correct data type!, const objects won't work 106 | */ 107 | template 108 | bool writeMultiPtr(void *ptr, std::vector offsets, Type val) { 109 | if (ptr == NULL) 110 | return false; 111 | 112 | uintptr_t finalPtr = reinterpret_cast(ptr); 113 | int offsetsSize = offsets.size(); 114 | if (offsetsSize > 0) { 115 | for (int i = 0; finalPtr != 0 && i < offsetsSize; i++) { 116 | if (i == (offsetsSize - 1)) { 117 | *reinterpret_cast(finalPtr + offsets[i]) = val; 118 | return true; 119 | } 120 | 121 | finalPtr = *reinterpret_cast(finalPtr + offsets[i]); 122 | } 123 | } 124 | 125 | if (finalPtr == 0) 126 | return false; 127 | 128 | *reinterpret_cast(finalPtr) = val; 129 | return true; 130 | } 131 | 132 | 133 | /* 134 | * Wrapper to dereference & get value of a pointer 135 | * Make sure to use the correct data type! 136 | */ 137 | template 138 | Type readPtr(void *ptr) { 139 | Type defaultVal = {}; 140 | if (ptr == NULL) 141 | return defaultVal; 142 | 143 | return *reinterpret_cast(ptr); 144 | } 145 | 146 | 147 | /* 148 | * Wrapper to dereference & set value of a pointer 149 | * Make sure to use the correct data type!, const objects won't work 150 | */ 151 | template 152 | bool writePtr(void *ptr, Type val) { 153 | if (ptr == NULL) 154 | return false; 155 | 156 | *reinterpret_cast(ptr) = val; 157 | return true; 158 | } 159 | 160 | 161 | /* 162 | * Reads an address content and returns hex string 163 | */ 164 | std::string read2HexStr(const void *address, size_t len); 165 | 166 | 167 | kern_return_t getPageInfo(void *page_start, vm_region_submap_short_info_64 *outInfo); 168 | 169 | /* 170 | * returns base executable info 171 | */ 172 | memory_file_info getBaseInfo(); 173 | 174 | /* 175 | * find in memory file info 176 | */ 177 | memory_file_info getMemoryFileInfo(const char *fileName); 178 | 179 | /* 180 | * returns relative address of file in memory, NULL as fileName will return base executable 181 | */ 182 | uint64_t getAbsoluteAddress(const char *fileName, uint64_t address); 183 | 184 | }; -------------------------------------------------------------------------------- /workingMenu16.4/KittyMemory/KittyUtils.cpp: -------------------------------------------------------------------------------- 1 | #include "KittyUtils.hpp" 2 | 3 | static void xtrim(std::string &hex){ 4 | if(hex.compare(0, 2, "0x") == 0){ 5 | hex.erase(0, 2); 6 | } 7 | 8 | // https://www.techiedelight.com/remove-whitespaces-string-cpp/ 9 | hex.erase(std::remove_if(hex.begin(), hex.end(), [](char c){ 10 | return (c == ' ' || c == '\n' || c == '\r' || 11 | c == '\t' || c == '\v' || c == '\f'); 12 | }), 13 | hex.end()); 14 | } 15 | 16 | 17 | bool KittyUtils::validateHexString(std::string &xstr){ 18 | if(xstr.length() < 2) return false; 19 | xtrim(xstr); // first remove spaces 20 | if(xstr.length() % 2 != 0) return false; 21 | for(size_t i = 0; i < xstr.length(); i++){ 22 | if(!std::isxdigit((unsigned char)xstr[i])){ 23 | return false; 24 | } 25 | } 26 | return true; 27 | } 28 | 29 | 30 | // https://tweex.net/post/c-anything-tofrom-a-hex-string/ 31 | #include 32 | #include 33 | 34 | 35 | // ------------------------------------------------------------------ 36 | /*! 37 | Convert a block of data to a hex string 38 | */ 39 | void KittyUtils::toHex( 40 | void *const data, //!< Data to convert 41 | const size_t dataLength, //!< Length of the data to convert 42 | std::string &dest //!< Destination string 43 | ) 44 | { 45 | unsigned char *byteData = reinterpret_cast(data); 46 | std::stringstream hexStringStream; 47 | 48 | hexStringStream << std::hex << std::setfill('0'); 49 | for(size_t index = 0; index < dataLength; ++index) 50 | hexStringStream << std::setw(2) << static_cast(byteData[index]); 51 | dest = hexStringStream.str(); 52 | } 53 | 54 | 55 | // ------------------------------------------------------------------ 56 | /*! 57 | Convert a hex string to a block of data 58 | */ 59 | void KittyUtils::fromHex( 60 | const std::string &in, //!< Input hex string 61 | void *const data //!< Data store 62 | ) 63 | { 64 | size_t length = in.length(); 65 | unsigned char *byteData = reinterpret_cast(data); 66 | 67 | std::stringstream hexStringStream; hexStringStream >> std::hex; 68 | for(size_t strIndex = 0, dataIndex = 0; strIndex < length; ++dataIndex) 69 | { 70 | // Read out and convert the string two characters at a time 71 | const char tmpStr[3] = { in[strIndex++], in[strIndex++], 0 }; 72 | 73 | // Reset and fill the string stream 74 | hexStringStream.clear(); 75 | hexStringStream.str(tmpStr); 76 | 77 | // Do the conversion 78 | int tmpValue = 0; 79 | hexStringStream >> tmpValue; 80 | byteData[dataIndex] = static_cast(tmpValue); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /workingMenu16.4/KittyMemory/KittyUtils.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace KittyUtils { 7 | 8 | bool validateHexString(std::string &xstr); 9 | void toHex(void *const data, const size_t dataLength, std::string &dest); 10 | void fromHex(const std::string &in, void *const data); 11 | 12 | } -------------------------------------------------------------------------------- /workingMenu16.4/KittyMemory/MemoryBackup.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // MemoryBackup.cpp 3 | // 4 | // Created by MJ (Ruit) on 4/19/20. 5 | // 6 | 7 | #include "MemoryBackup.hpp" 8 | 9 | 10 | MemoryBackup::MemoryBackup() { 11 | _address = 0; 12 | _size = 0; 13 | _orig_code.clear(); 14 | } 15 | 16 | MemoryBackup::MemoryBackup(const char *fileName, uint64_t address, size_t backup_size) { 17 | MemoryBackup(); 18 | 19 | if (address == 0 || backup_size < 1) 20 | return; 21 | 22 | _address = reinterpret_cast(KittyMemory::getAbsoluteAddress(fileName, address)); 23 | if(_address == NULL) return; 24 | 25 | _size = backup_size; 26 | 27 | _orig_code.resize(backup_size); 28 | 29 | // backup current content 30 | KittyMemory::memRead(&_orig_code[0], reinterpret_cast(_address), backup_size); 31 | } 32 | 33 | 34 | MemoryBackup::MemoryBackup(uint64_t absolute_address, size_t backup_size) { 35 | MemoryBackup(); 36 | 37 | if (absolute_address == 0 || backup_size < 1) 38 | return; 39 | 40 | _address = reinterpret_cast(absolute_address); 41 | 42 | _size = backup_size; 43 | 44 | _orig_code.resize(backup_size); 45 | 46 | // backup current content 47 | KittyMemory::memRead(&_orig_code[0], reinterpret_cast(_address), backup_size); 48 | } 49 | 50 | MemoryBackup::~MemoryBackup() { 51 | // clean up 52 | _orig_code.clear(); 53 | } 54 | 55 | 56 | bool MemoryBackup::isValid() const { 57 | return (_address != 0 && _size > 0 58 | && _orig_code.size() == _size); 59 | } 60 | 61 | size_t MemoryBackup::get_BackupSize() const{ 62 | return _size; 63 | } 64 | 65 | void *MemoryBackup::get_TargetAddress() const{ 66 | return _address; 67 | } 68 | 69 | bool MemoryBackup::Restore() { 70 | if (!isValid()) return false; 71 | return KittyMemory::memWrite(reinterpret_cast(_address), &_orig_code[0], _size) == KittyMemory::SUCCESS; 72 | } 73 | 74 | std::string MemoryBackup::get_CurrBytes() { 75 | if (!isValid()) 76 | _hexString = std::string("0xInvalid"); 77 | else 78 | _hexString = KittyMemory::read2HexStr(reinterpret_cast(_address), _size); 79 | 80 | return _hexString; 81 | } 82 | -------------------------------------------------------------------------------- /workingMenu16.4/KittyMemory/MemoryBackup.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // MemoryBackup.hpp 3 | // 4 | // Created by MJ (Ruit) on 4/19/20. 5 | // 6 | 7 | #pragma once 8 | 9 | #include 10 | 11 | #include "KittyMemory.hpp" 12 | 13 | class MemoryBackup { 14 | private: 15 | void *_address; 16 | size_t _size; 17 | 18 | std::vector _orig_code; 19 | 20 | std::string _hexString; 21 | 22 | public: 23 | MemoryBackup(); 24 | 25 | /* 26 | * expects library name and relative address 27 | */ 28 | MemoryBackup(const char *fileName, uint64_t address, size_t backup_size); 29 | 30 | /* 31 | * expects absolute address 32 | */ 33 | MemoryBackup(uint64_t absolute_address, size_t backup_size); 34 | 35 | 36 | ~MemoryBackup(); 37 | 38 | 39 | /* 40 | * Validate patch 41 | */ 42 | bool isValid() const; 43 | 44 | 45 | size_t get_BackupSize() const; 46 | 47 | /* 48 | * Returns pointer to the target address 49 | */ 50 | void *get_TargetAddress() const; 51 | 52 | 53 | /* 54 | * Restores backup code 55 | */ 56 | bool Restore(); 57 | 58 | 59 | /* 60 | * Returns current target address bytes as hex string 61 | */ 62 | std::string get_CurrBytes(); 63 | }; 64 | -------------------------------------------------------------------------------- /workingMenu16.4/KittyMemory/MemoryPatch.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // MemoryPatch.cpp 3 | // 4 | // Created by MJ (Ruit) on 1/1/19. 5 | // 6 | 7 | #include "MemoryPatch.hpp" 8 | 9 | 10 | MemoryPatch::MemoryPatch() { 11 | _address = 0; 12 | _size = 0; 13 | _orig_code.clear(); 14 | _patch_code.clear(); 15 | } 16 | 17 | MemoryPatch::MemoryPatch(uint64_t absolute_address, 18 | const void *patch_code, size_t patch_size) { 19 | MemoryPatch(); 20 | 21 | if (absolute_address == 0 || patch_code == NULL || patch_size < 1) 22 | return; 23 | 24 | _address = reinterpret_cast(absolute_address); 25 | _size = patch_size; 26 | 27 | _orig_code.resize(patch_size); 28 | _patch_code.resize(patch_size); 29 | 30 | // initialize patch & backup current content 31 | KittyMemory::memRead(&_patch_code[0], patch_code, patch_size); 32 | KittyMemory::memRead(&_orig_code[0], static_cast(_address), patch_size); 33 | } 34 | 35 | MemoryPatch::MemoryPatch(const char *fileName, uint64_t address, 36 | const void *patch_code, size_t patch_size) { 37 | MemoryPatch(); 38 | 39 | if (address == 0 || patch_code == NULL || patch_size < 1) 40 | return; 41 | 42 | _address = reinterpret_cast(KittyMemory::getAbsoluteAddress(fileName, address)); 43 | if(_address == NULL) return; 44 | 45 | _size = patch_size; 46 | 47 | _orig_code.resize(patch_size); 48 | _patch_code.resize(patch_size); 49 | 50 | // initialize patch & backup current content 51 | KittyMemory::memRead(&_patch_code[0], patch_code, patch_size); 52 | KittyMemory::memRead(&_orig_code[0], reinterpret_cast(_address), patch_size); 53 | } 54 | 55 | MemoryPatch::~MemoryPatch() { 56 | // clean up 57 | _orig_code.clear(); 58 | _patch_code.clear(); 59 | } 60 | 61 | 62 | MemoryPatch MemoryPatch::createWithHex(const char *fileName, uint64_t address, std::string hex) { 63 | MemoryPatch patch; 64 | 65 | if (address == 0 || !KittyUtils::validateHexString(hex)) 66 | return patch; 67 | 68 | patch._address = reinterpret_cast(KittyMemory::getAbsoluteAddress(fileName, address)); 69 | if(patch._address == NULL) return patch; 70 | 71 | patch._size = hex.length() / 2; 72 | 73 | patch._orig_code.resize(patch._size); 74 | patch._patch_code.resize(patch._size); 75 | 76 | // initialize patch 77 | KittyUtils::fromHex(hex, &patch._patch_code[0]); 78 | 79 | // backup current content 80 | KittyMemory::memRead(&patch._orig_code[0], reinterpret_cast(patch._address), patch._size); 81 | return patch; 82 | } 83 | 84 | MemoryPatch MemoryPatch::createWithHex(uint64_t absolute_address, std::string hex) { 85 | MemoryPatch patch; 86 | 87 | if (absolute_address == 0 || !KittyUtils::validateHexString(hex)) 88 | return patch; 89 | 90 | patch._address = reinterpret_cast(absolute_address); 91 | patch._size = hex.length() / 2; 92 | 93 | patch._orig_code.resize(patch._size); 94 | patch._patch_code.resize(patch._size); 95 | 96 | // initialize patch 97 | KittyUtils::fromHex(hex, &patch._patch_code[0]); 98 | 99 | // backup current content 100 | KittyMemory::memRead(&patch._orig_code[0], reinterpret_cast(patch._address), patch._size); 101 | return patch; 102 | } 103 | 104 | bool MemoryPatch::isValid() const { 105 | return (_address != NULL && _size > 0 106 | && _orig_code.size() == _size && _patch_code.size() == _size); 107 | } 108 | 109 | size_t MemoryPatch::get_PatchSize() const{ 110 | return _size; 111 | } 112 | 113 | void *MemoryPatch::get_TargetAddress() const{ 114 | return _address; 115 | } 116 | 117 | bool MemoryPatch::Restore() { 118 | if (!isValid()) return false; 119 | return KittyMemory::memWrite(_address, &_orig_code[0], _size) == KittyMemory::SUCCESS; 120 | } 121 | 122 | bool MemoryPatch::Modify() { 123 | if (!isValid()) return false; 124 | return (KittyMemory::memWrite(_address, &_patch_code[0], _size) == KittyMemory::SUCCESS); 125 | } 126 | 127 | std::string MemoryPatch::get_CurrBytes() { 128 | if (!isValid()) 129 | _hexString = std::string("0xInvalid"); 130 | else 131 | _hexString = KittyMemory::read2HexStr(reinterpret_cast(_address), _size); 132 | 133 | return _hexString; 134 | } 135 | -------------------------------------------------------------------------------- /workingMenu16.4/KittyMemory/MemoryPatch.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // MemoryPatch.h 3 | // 4 | // Created by MJ (Ruit) on 1/1/19. 5 | // 6 | 7 | #pragma once 8 | 9 | #include 10 | 11 | #include "KittyMemory.hpp" 12 | #include "KittyUtils.hpp" 13 | 14 | 15 | class MemoryPatch { 16 | private: 17 | void *_address; 18 | size_t _size; 19 | 20 | std::vector _orig_code; 21 | std::vector _patch_code; 22 | 23 | std::string _hexString; 24 | 25 | public: 26 | MemoryPatch(); 27 | 28 | /* 29 | * expects an already calculated address 30 | */ 31 | MemoryPatch(uint64_t absolute_address, 32 | const void *patch_code, size_t patch_size); 33 | 34 | /* 35 | * expects file name and relative address, you can pass NULL as filename for base executable 36 | */ 37 | MemoryPatch(const char *fileName, uint64_t address, 38 | const void *patch_code, size_t patch_size); 39 | 40 | 41 | ~MemoryPatch(); 42 | 43 | /* 44 | * compatible hex format (0xffff & ffff & ff ff) 45 | */ 46 | static MemoryPatch createWithHex(const char *fileName, uint64_t address, std::string hex); 47 | static MemoryPatch createWithHex(uint64_t absolute_address, std::string hex); 48 | 49 | /* 50 | * Validate patch 51 | */ 52 | bool isValid() const; 53 | 54 | 55 | size_t get_PatchSize() const; 56 | 57 | /* 58 | * Returns pointer to the target address 59 | */ 60 | void *get_TargetAddress() const; 61 | 62 | 63 | /* 64 | * Restores patch to original value 65 | */ 66 | bool Restore(); 67 | 68 | 69 | /* 70 | * Applies patch modifications to target address 71 | */ 72 | bool Modify(); 73 | 74 | 75 | /* 76 | * Returns current patch target address bytes as hex string 77 | */ 78 | std::string get_CurrBytes(); 79 | }; -------------------------------------------------------------------------------- /workingMenu16.4/KittyMemory/Read Me.txt: -------------------------------------------------------------------------------- 1 | KittyMemory is NOT made by me, it's made by Ruit. 2 | 3 | I just implemented it in my menu. 4 | 5 | KittyMemory is open source & can be found on github: 6 | - https://github.com/MJx0/KittyMemory -------------------------------------------------------------------------------- /workingMenu16.4/KittyMemory/defs.h: -------------------------------------------------------------------------------- 1 | 2 | #if defined(__GNUC__) 3 | typedef long long ll; 4 | typedef unsigned long long ull; 5 | #define __int64 long long 6 | #define __int32 int 7 | #define __int16 short 8 | #define __int8 char 9 | #define MAKELL(num) num ## LL 10 | #define FMT_64 "ll" 11 | #elif defined(_MSC_VER) 12 | typedef __int64 ll; 13 | typedef unsigned __int64 ull; 14 | #define MAKELL(num) num ## i64 15 | #define FMT_64 "I64" 16 | #elif defined (__BORLANDC__) 17 | typedef __int64 ll; 18 | typedef unsigned __int64 ull; 19 | #define MAKELL(num) num ## i64 20 | #define FMT_64 "L" 21 | #else 22 | #error "unknown compiler" 23 | #endif 24 | typedef unsigned int uint; 25 | typedef unsigned char uchar; 26 | typedef unsigned short ushort; 27 | typedef unsigned long ulong; 28 | 29 | typedef char int8; 30 | typedef signed char sint8; 31 | typedef unsigned char uint8; 32 | typedef short int16; 33 | typedef signed short sint16; 34 | typedef unsigned short uint16; 35 | typedef int int32; 36 | typedef signed int sint32; 37 | typedef unsigned int uint32; 38 | typedef ll int64; 39 | typedef ll sint64; 40 | typedef ull uint64; 41 | 42 | // Partially defined types: 43 | #define _BYTE uint8 44 | #define _WORD uint16 45 | #define _DWORD uint32 46 | #define _QWORD uint64 47 | #if !defined(_MSC_VER) 48 | #define _LONGLONG __int128 49 | #endif 50 | 51 | #ifndef _WINDOWS_ 52 | typedef int8 BYTE; 53 | typedef int16 WORD; 54 | typedef int32 DWORD; 55 | typedef int32 LONG; 56 | #endif 57 | typedef int64 QWORD; 58 | #ifndef __cplusplus 59 | typedef int bool; // we want to use bool in our C programs 60 | #endif 61 | 62 | // Some convenience macros to make partial accesses nicer 63 | // first unsigned macros: 64 | #define LOBYTE(x) (*((_BYTE*)&(x))) // low byte 65 | #define LOWORD(x) (*((_WORD*)&(x))) // low word 66 | #define LODWORD(x) (*((_DWORD*)&(x))) // low dword 67 | #define HIBYTE(x) (*((_BYTE*)&(x)+1)) 68 | #define HIWORD(x) (*((_WORD*)&(x)+1)) 69 | #define HIDWORD(x) (*((_DWORD*)&(x)+1)) 70 | #define BYTEn(x, n) (*((_BYTE*)&(x)+n)) 71 | #define WORDn(x, n) (*((_WORD*)&(x)+n)) 72 | #define BYTE1(x) BYTEn(x, 1) // byte 1 (counting from 0) 73 | #define BYTE2(x) BYTEn(x, 2) 74 | #define BYTE3(x) BYTEn(x, 3) 75 | #define BYTE4(x) BYTEn(x, 4) 76 | #define BYTE5(x) BYTEn(x, 5) 77 | #define BYTE6(x) BYTEn(x, 6) 78 | #define BYTE7(x) BYTEn(x, 7) 79 | #define BYTE8(x) BYTEn(x, 8) 80 | #define BYTE9(x) BYTEn(x, 9) 81 | #define BYTE10(x) BYTEn(x, 10) 82 | #define BYTE11(x) BYTEn(x, 11) 83 | #define BYTE12(x) BYTEn(x, 12) 84 | #define BYTE13(x) BYTEn(x, 13) 85 | #define BYTE14(x) BYTEn(x, 14) 86 | #define BYTE15(x) BYTEn(x, 15) 87 | #define WORD1(x) WORDn(x, 1) 88 | #define WORD2(x) WORDn(x, 2) // third word of the object, unsigned 89 | #define WORD3(x) WORDn(x, 3) 90 | #define WORD4(x) WORDn(x, 4) 91 | #define WORD5(x) WORDn(x, 5) 92 | #define WORD6(x) WORDn(x, 6) 93 | #define WORD7(x) WORDn(x, 7) 94 | 95 | // now signed macros (the same but with sign extension) 96 | #define SLOBYTE(x) (*((int8*)&(x))) 97 | #define SLOWORD(x) (*((int16*)&(x))) 98 | #define SLODWORD(x) (*((int32*)&(x))) 99 | #define SHIBYTE(x) (*((int8*)&(x)+1)) 100 | #define SHIWORD(x) (*((int16*)&(x)+1)) 101 | #define SHIDWORD(x) (*((int32*)&(x)+1)) 102 | #define SBYTEn(x, n) (*((int8*)&(x)+n)) 103 | #define SWORDn(x, n) (*((int16*)&(x)+n)) 104 | #define SBYTE1(x) SBYTEn(x, 1) 105 | #define SBYTE2(x) SBYTEn(x, 2) 106 | #define SBYTE3(x) SBYTEn(x, 3) 107 | #define SBYTE4(x) SBYTEn(x, 4) 108 | #define SBYTE5(x) SBYTEn(x, 5) 109 | #define SBYTE6(x) SBYTEn(x, 6) 110 | #define SBYTE7(x) SBYTEn(x, 7) 111 | #define SBYTE8(x) SBYTEn(x, 8) 112 | #define SBYTE9(x) SBYTEn(x, 9) 113 | #define SBYTE10(x) SBYTEn(x, 10) 114 | #define SBYTE11(x) SBYTEn(x, 11) 115 | #define SBYTE12(x) SBYTEn(x, 12) 116 | #define SBYTE13(x) SBYTEn(x, 13) 117 | #define SBYTE14(x) SBYTEn(x, 14) 118 | #define SBYTE15(x) SBYTEn(x, 15) 119 | #define SWORD1(x) SWORDn(x, 1) 120 | #define SWORD2(x) SWORDn(x, 2) 121 | #define SWORD3(x) SWORDn(x, 3) 122 | #define SWORD4(x) SWORDn(x, 4) 123 | #define SWORD5(x) SWORDn(x, 5) 124 | #define SWORD6(x) SWORDn(x, 6) 125 | #define SWORD7(x) SWORDn(x, 7) 126 | 127 | 128 | // Helper functions to represent some assembly instructions. 129 | 130 | #ifdef __cplusplus 131 | 132 | // Fill memory block with an integer value 133 | inline void memset32(void *ptr, uint32 value, int count) 134 | { 135 | uint32 *p = (uint32 *)ptr; 136 | for ( int i=0; i < count; i++ ) 137 | *p++ = value; 138 | } 139 | 140 | // Generate a reference to pair of operands 141 | template int16 __PAIR__( int8 high, T low) { return ((( int16)high) << sizeof(high)*8) | uint8(low); } 142 | template int32 __PAIR__( int16 high, T low) { return ((( int32)high) << sizeof(high)*8) | uint16(low); } 143 | template int64 __PAIR__( int32 high, T low) { return ((( int64)high) << sizeof(high)*8) | uint32(low); } 144 | template uint16 __PAIR__(uint8 high, T low) { return (((uint16)high) << sizeof(high)*8) | uint8(low); } 145 | template uint32 __PAIR__(uint16 high, T low) { return (((uint32)high) << sizeof(high)*8) | uint16(low); } 146 | template uint64 __PAIR__(uint32 high, T low) { return (((uint64)high) << sizeof(high)*8) | uint32(low); } 147 | 148 | // rotate left 149 | template T __ROL__(T value, uint count) 150 | { 151 | const uint nbits = sizeof(T) * 8; 152 | count %= nbits; 153 | 154 | T high = value >> (nbits - count); 155 | value <<= count; 156 | value |= high; 157 | return value; 158 | } 159 | 160 | // rotate right 161 | template T __ROR__(T value, uint count) 162 | { 163 | const uint nbits = sizeof(T) * 8; 164 | count %= nbits; 165 | 166 | T low = value << (nbits - count); 167 | value >>= count; 168 | value |= low; 169 | return value; 170 | } 171 | 172 | // carry flag of left shift 173 | template int8 __MKCSHL__(T value, uint count) 174 | { 175 | const uint nbits = sizeof(T) * 8; 176 | count %= nbits; 177 | 178 | return (value >> (nbits-count)) & 1; 179 | } 180 | 181 | // carry flag of right shift 182 | template int8 __MKCSHR__(T value, uint count) 183 | { 184 | return (value >> (count-1)) & 1; 185 | } 186 | 187 | // sign flag 188 | template int8 __SETS__(T x) 189 | { 190 | if ( sizeof(T) == 1 ) 191 | return int8(x) < 0; 192 | if ( sizeof(T) == 2 ) 193 | return int16(x) < 0; 194 | if ( sizeof(T) == 4 ) 195 | return int32(x) < 0; 196 | return int64(x) < 0; 197 | } 198 | 199 | // overflow flag of subtraction (x-y) 200 | template int8 __OFSUB__(T x, U y) 201 | { 202 | if ( sizeof(T) < sizeof(U) ) 203 | { 204 | U x2 = x; 205 | int8 sx = __SETS__(x2); 206 | return (sx ^ __SETS__(y)) & (sx ^ __SETS__(x2-y)); 207 | } 208 | else 209 | { 210 | T y2 = y; 211 | int8 sx = __SETS__(x); 212 | return (sx ^ __SETS__(y2)) & (sx ^ __SETS__(x-y2)); 213 | } 214 | } 215 | 216 | // overflow flag of addition (x+y) 217 | template int8 __OFADD__(T x, U y) 218 | { 219 | if ( sizeof(T) < sizeof(U) ) 220 | { 221 | U x2 = x; 222 | int8 sx = __SETS__(x2); 223 | return ((1 ^ sx) ^ __SETS__(y)) & (sx ^ __SETS__(x2+y)); 224 | } 225 | else 226 | { 227 | T y2 = y; 228 | int8 sx = __SETS__(x); 229 | return ((1 ^ sx) ^ __SETS__(y2)) & (sx ^ __SETS__(x+y2)); 230 | } 231 | } 232 | 233 | // carry flag of subtraction (x-y) 234 | template int8 __CFSUB__(T x, U y) 235 | { 236 | int size = sizeof(T) > sizeof(U) ? sizeof(T) : sizeof(U); 237 | if ( size == 1 ) 238 | return uint8(x) < uint8(y); 239 | if ( size == 2 ) 240 | return uint16(x) < uint16(y); 241 | if ( size == 4 ) 242 | return uint32(x) < uint32(y); 243 | return uint64(x) < uint64(y); 244 | } 245 | 246 | // carry flag of addition (x+y) 247 | template int8 __CFADD__(T x, U y) 248 | { 249 | int size = sizeof(T) > sizeof(U) ? sizeof(T) : sizeof(U); 250 | if ( size == 1 ) 251 | return uint8(x) > uint8(x+y); 252 | if ( size == 2 ) 253 | return uint16(x) > uint16(x+y); 254 | if ( size == 4 ) 255 | return uint32(x) > uint32(x+y); 256 | return uint64(x) > uint64(x+y); 257 | } 258 | 259 | #else 260 | // The following definition is not quite correct because it always returns 261 | // uint64. The above C++ functions are good, though. 262 | #define __PAIR__(high, low) (((uint64)(high)<>y) 268 | #define __CFADD__(x, y) invalid_operation // Generate carry flag for (x+y) 269 | #define __CFSUB__(x, y) invalid_operation // Generate carry flag for (x-y) 270 | #define __OFADD__(x, y) invalid_operation // Generate overflow flag for (x+y) 271 | #define __OFSUB__(x, y) invalid_operation // Generate overflow flag for (x-y) 272 | #endif 273 | 274 | // No definition for rcl/rcr because the carry flag is unknown 275 | #define __RCL__(x, y) invalid_operation // Rotate left thru carry 276 | #define __RCR__(x, y) invalid_operation // Rotate right thru carry 277 | #define __MKCRCL__(x, y) invalid_operation // Generate carry flag for a RCL 278 | #define __MKCRCR__(x, y) invalid_operation // Generate carry flag for a RCR 279 | #define __SETP__(x, y) invalid_operation // Generate parity flag for (x-y) 280 | 281 | // In the decompilation listing there are some objects declarared as _UNKNOWN 282 | // because we could not determine their types. Since the C compiler does not 283 | // accept void item declarations, we replace them by anything of our choice, 284 | // for example a char: 285 | 286 | #define _UNKNOWN char 287 | 288 | #ifdef _MSC_VER 289 | #define snprintf _snprintf 290 | #define vsnprintf _vsnprintf 291 | #endif 292 | 293 | -------------------------------------------------------------------------------- /workingMenu16.4/KittyMemory/imconfig.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // COMPILE-TIME OPTIONS FOR DEAR IMGUI 3 | // Runtime options (clipboard callbacks, enabling various features, etc.) can generally be set via the ImGuiIO structure. 4 | // You can use ImGui::SetAllocatorFunctions() before calling ImGui::CreateContext() to rewire memory allocation functions. 5 | //----------------------------------------------------------------------------- 6 | // A) You may edit imconfig.h (and not overwrite it when updating Dear ImGui, or maintain a patch/rebased branch with your modifications to it) 7 | // B) or '#define IMGUI_USER_CONFIG "my_imgui_config.h"' in your project and then add directives in your own file without touching this template. 8 | //----------------------------------------------------------------------------- 9 | // You need to make sure that configuration settings are defined consistently _everywhere_ Dear ImGui is used, which include the imgui*.cpp 10 | // files but also _any_ of your code that uses Dear ImGui. This is because some compile-time options have an affect on data structures. 11 | // Defining those options in imconfig.h will ensure every compilation unit gets to see the same data structure layouts. 12 | // Call IMGUI_CHECKVERSION() from your .cpp files to verify that the data structures your files are using are matching the ones imgui.cpp is using. 13 | //----------------------------------------------------------------------------- 14 | 15 | #pragma once 16 | 17 | //---- Define assertion handler. Defaults to calling assert(). 18 | // If your macro uses multiple statements, make sure is enclosed in a 'do { .. } while (0)' block so it can be used as a single statement. 19 | //#define IM_ASSERT(_EXPR) MyAssert(_EXPR) 20 | //#define IM_ASSERT(_EXPR) ((void)(_EXPR)) // Disable asserts 21 | 22 | //---- Define attributes of all API symbols declarations, e.g. for DLL under Windows 23 | // Using Dear ImGui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility. 24 | // DLL users: heaps and globals are not shared across DLL boundaries! You will need to call SetCurrentContext() + SetAllocatorFunctions() 25 | // for each static/DLL boundary you are calling from. Read "Context and Memory Allocators" section of imgui.cpp for more details. 26 | //#define IMGUI_API __declspec( dllexport ) 27 | //#define IMGUI_API __declspec( dllimport ) 28 | 29 | //---- Don't define obsolete functions/enums/behaviors. Consider enabling from time to time after updating to avoid using soon-to-be obsolete function/names. 30 | //#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS 31 | 32 | //---- Disable all of Dear ImGui or don't implement standard windows. 33 | // It is very strongly recommended to NOT disable the demo windows during development. Please read comments in imgui_demo.cpp. 34 | //#define IMGUI_DISABLE // Disable everything: all headers and source files will be empty. 35 | //#define IMGUI_DISABLE_DEMO_WINDOWS // Disable demo windows: ShowDemoWindow()/ShowStyleEditor() will be empty. Not recommended. 36 | //#define IMGUI_DISABLE_METRICS_WINDOW // Disable metrics/debugger window: ShowMetricsWindow() will be empty. 37 | 38 | //---- Don't implement some functions to reduce linkage requirements. 39 | //#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc. (user32.lib/.a, kernel32.lib/.a) 40 | //#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] Don't implement default IME handler. Won't use and link with ImmGetContext/ImmSetCompositionWindow. (imm32.lib/.a) 41 | //#define IMGUI_DISABLE_WIN32_FUNCTIONS // [Win32] Won't use and link with any Win32 function (clipboard, ime). 42 | //#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS // [OSX] Implement default OSX clipboard handler (need to link with '-framework ApplicationServices', this is why this is not the default). 43 | //#define IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself (e.g. if you don't want to link with vsnprintf) 44 | //#define IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS // Don't implement ImFabs/ImSqrt/ImPow/ImFmod/ImCos/ImSin/ImAcos/ImAtan2 so you can implement them yourself. 45 | //#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite so you can implement them yourself if you don't want to link with fopen/fclose/fread/fwrite. This will also disable the LogToTTY() function. 46 | //#define IMGUI_DISABLE_DEFAULT_ALLOCATORS // Don't implement default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions(). 47 | 48 | //---- Include imgui_user.h at the end of imgui.h as a convenience 49 | //#define IMGUI_INCLUDE_IMGUI_USER_H 50 | 51 | //---- Pack colors to BGRA8 instead of RGBA8 (to avoid converting from one to another) 52 | //#define IMGUI_USE_BGRA_PACKED_COLOR 53 | 54 | //---- Use 32-bit for ImWchar (default is 16-bit) to support unicode planes 1-16. (e.g. point beyond 0xFFFF like emoticons, dingbats, symbols, shapes, ancient languages, etc...) 55 | //#define IMGUI_USE_WCHAR32 56 | 57 | //---- Avoid multiple STB libraries implementations, or redefine path/filenames to prioritize another version 58 | // By default the embedded implementations are declared static and not available outside of Dear ImGui sources files. 59 | //#define IMGUI_STB_TRUETYPE_FILENAME "my_folder/stb_truetype.h" 60 | //#define IMGUI_STB_RECT_PACK_FILENAME "my_folder/stb_rect_pack.h" 61 | //#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION 62 | //#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION 63 | 64 | //---- Use stb_printf's faster implementation of vsnprintf instead of the one from libc (unless IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS is defined) 65 | // Requires 'stb_sprintf.h' to be available in the include path. Compatibility checks of arguments and formats done by clang and GCC will be disabled in order to support the extra formats provided by STB sprintf. 66 | // #define IMGUI_USE_STB_SPRINTF 67 | 68 | //---- Use FreeType to build and rasterize the font atlas (instead of stb_truetype which is embedded by default in Dear ImGui) 69 | // Requires FreeType headers to be available in the include path. Requires program to be compiled with 'misc/freetype/imgui_freetype.cpp' (in this repository) + the FreeType library (not provided). 70 | // On Windows you may use vcpkg with 'vcpkg install freetype' + 'vcpkg integrate install'. 71 | //#define IMGUI_ENABLE_FREETYPE 72 | 73 | //---- Use stb_truetype to build and rasterize the font atlas (default) 74 | // The only purpose of this define is if you want force compilation of the stb_truetype backend ALONG with the FreeType backend. 75 | //#define IMGUI_ENABLE_STB_TRUETYPE 76 | 77 | //---- Define constructor and implicit cast operators to convert back<>forth between your math types and ImVec2/ImVec4. 78 | // This will be inlined as part of ImVec2 and ImVec4 class declarations. 79 | /* 80 | #define IM_VEC2_CLASS_EXTRA \ 81 | ImVec2(const MyVec2& f) { x = f.x; y = f.y; } \ 82 | operator MyVec2() const { return MyVec2(x,y); } 83 | 84 | #define IM_VEC4_CLASS_EXTRA \ 85 | ImVec4(const MyVec4& f) { x = f.x; y = f.y; z = f.z; w = f.w; } \ 86 | operator MyVec4() const { return MyVec4(x,y,z,w); } 87 | */ 88 | 89 | //---- Use 32-bit vertex indices (default is 16-bit) is one way to allow large meshes with more than 64K vertices. 90 | // Your renderer backend will need to support it (most example renderer backends support both 16/32-bit indices). 91 | // Another way to allow large meshes while keeping 16-bit indices is to handle ImDrawCmd::VtxOffset in your renderer. 92 | // Read about ImGuiBackendFlags_RendererHasVtxOffset for details. 93 | //#define ImDrawIdx unsigned int 94 | 95 | //---- Override ImDrawCallback signature (will need to modify renderer backends accordingly) 96 | //struct ImDrawList; 97 | //struct ImDrawCmd; 98 | //typedef void (*MyImDrawCallback)(const ImDrawList* draw_list, const ImDrawCmd* cmd, void* my_renderer_user_data); 99 | //#define ImDrawCallback MyImDrawCallback 100 | 101 | //---- Debug Tools: Macro to break in Debugger 102 | // (use 'Metrics->Tools->Item Picker' to pick widgets with the mouse and break into them for easy debugging.) 103 | //#define IM_DEBUG_BREAK IM_ASSERT(0) 104 | //#define IM_DEBUG_BREAK __debugbreak() 105 | 106 | //---- Debug Tools: Have the Item Picker break in the ItemAdd() function instead of ItemHoverable(), 107 | // (which comes earlier in the code, will catch a few extra items, allow picking items other than Hovered one.) 108 | // This adds a small runtime cost which is why it is not enabled by default. 109 | //#define IMGUI_DEBUG_TOOL_ITEM_PICKER_EX 110 | 111 | //---- Debug Tools: Enable slower asserts 112 | //#define IMGUI_DEBUG_PARANOID 113 | 114 | //---- Tip: You can add extra functions within the ImGui:: namespace, here or in your own headers files. 115 | /* 116 | namespace ImGui 117 | { 118 | void MyFunction(const char* name, const MyMatrix44& v); 119 | } 120 | */ 121 | -------------------------------------------------------------------------------- /workingMenu16.4/KittyMemory/imgui_impl_metal.h: -------------------------------------------------------------------------------- 1 | // dear imgui: Renderer Backend for Metal 2 | // This needs to be used along with a Platform Backend (e.g. OSX) 3 | 4 | // Implemented features: 5 | // [X] Renderer: User texture binding. Use 'MTLTexture' as ImTextureID. Read the FAQ about ImTextureID! 6 | // [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices. 7 | 8 | // You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. 9 | // If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp. 10 | // Read online: https://github.com/ocornut/imgui/tree/master/docs 11 | 12 | #include "imgui.h" // IMGUI_IMPL_API 13 | 14 | @class MTLRenderPassDescriptor; 15 | @protocol MTLDevice, MTLCommandBuffer, MTLRenderCommandEncoder; 16 | 17 | IMGUI_IMPL_API bool ImGui_ImplMetal_Init(id device); 18 | IMGUI_IMPL_API void ImGui_ImplMetal_Shutdown(); 19 | IMGUI_IMPL_API void ImGui_ImplMetal_NewFrame(MTLRenderPassDescriptor* renderPassDescriptor); 20 | IMGUI_IMPL_API void ImGui_ImplMetal_RenderDrawData(ImDrawData* draw_data, 21 | id commandBuffer, 22 | id commandEncoder); 23 | 24 | // Called by Init/NewFrame/Shutdown 25 | IMGUI_IMPL_API bool ImGui_ImplMetal_CreateFontsTexture(id device); 26 | IMGUI_IMPL_API void ImGui_ImplMetal_DestroyFontsTexture(); 27 | IMGUI_IMPL_API bool ImGui_ImplMetal_CreateDeviceObjects(id device); 28 | IMGUI_IMPL_API void ImGui_ImplMetal_DestroyDeviceObjects(); 29 | -------------------------------------------------------------------------------- /workingMenu16.4/KittyMemory/imgui_impl_metal.mm: -------------------------------------------------------------------------------- 1 | // dear imgui: Renderer Backend for Metal 2 | // This needs to be used along with a Platform Backend (e.g. OSX) 3 | 4 | // Implemented features: 5 | // [X] Renderer: User texture binding. Use 'MTLTexture' as ImTextureID. Read the FAQ about ImTextureID! 6 | // [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices. 7 | 8 | // You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. 9 | // If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp. 10 | // Read online: https://github.com/ocornut/imgui/tree/master/docs 11 | 12 | // CHANGELOG 13 | // (minor and older changes stripped away, please see git history for details) 14 | // 2021-02-18: Metal: Change blending equation to preserve alpha in output buffer. 15 | // 2021-01-25: Metal: Fixed texture storage mode when building on Mac Catalyst. 16 | // 2019-05-29: Metal: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag. 17 | // 2019-04-30: Metal: Added support for special ImDrawCallback_ResetRenderState callback to reset render state. 18 | // 2019-02-11: Metal: Projecting clipping rectangles correctly using draw_data->FramebufferScale to allow multi-viewports for retina display. 19 | // 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window. 20 | // 2018-07-05: Metal: Added new Metal backend implementation. 21 | 22 | #include "imgui.h" 23 | #include "imgui_impl_metal.h" 24 | 25 | #import 26 | // #import // Not supported in XCode 9.2. Maybe a macro to detect the SDK version can be used (something like #if MACOS_SDK >= 10.13 ...) 27 | #import 28 | 29 | #pragma mark - Support classes 30 | 31 | // A wrapper around a MTLBuffer object that knows the last time it was reused 32 | @interface MetalBuffer : NSObject 33 | @property (nonatomic, strong) id buffer; 34 | @property (nonatomic, assign) NSTimeInterval lastReuseTime; 35 | - (instancetype)initWithBuffer:(id)buffer; 36 | @end 37 | 38 | // An object that encapsulates the data necessary to uniquely identify a 39 | // render pipeline state. These are used as cache keys. 40 | @interface FramebufferDescriptor : NSObject 41 | @property (nonatomic, assign) unsigned long sampleCount; 42 | @property (nonatomic, assign) MTLPixelFormat colorPixelFormat; 43 | @property (nonatomic, assign) MTLPixelFormat depthPixelFormat; 44 | @property (nonatomic, assign) MTLPixelFormat stencilPixelFormat; 45 | - (instancetype)initWithRenderPassDescriptor:(MTLRenderPassDescriptor *)renderPassDescriptor; 46 | @end 47 | 48 | // A singleton that stores long-lived objects that are needed by the Metal 49 | // renderer backend. Stores the render pipeline state cache and the default 50 | // font texture, and manages the reusable buffer cache. 51 | @interface MetalContext : NSObject 52 | @property (nonatomic, strong) id depthStencilState; 53 | @property (nonatomic, strong) FramebufferDescriptor *framebufferDescriptor; // framebuffer descriptor for current frame; transient 54 | @property (nonatomic, strong) NSMutableDictionary *renderPipelineStateCache; // pipeline cache; keyed on framebuffer descriptors 55 | @property (nonatomic, strong, nullable) id fontTexture; 56 | @property (nonatomic, strong) NSMutableArray *bufferCache; 57 | @property (nonatomic, assign) NSTimeInterval lastBufferCachePurge; 58 | - (void)makeDeviceObjectsWithDevice:(id)device; 59 | - (void)makeFontTextureWithDevice:(id)device; 60 | - (MetalBuffer *)dequeueReusableBufferOfLength:(NSUInteger)length device:(id)device; 61 | - (void)enqueueReusableBuffer:(MetalBuffer *)buffer; 62 | - (id)renderPipelineStateForFrameAndDevice:(id)device; 63 | - (void)emptyRenderPipelineStateCache; 64 | - (void)setupRenderState:(ImDrawData *)drawData 65 | commandBuffer:(id)commandBuffer 66 | commandEncoder:(id)commandEncoder 67 | renderPipelineState:(id)renderPipelineState 68 | vertexBuffer:(MetalBuffer *)vertexBuffer 69 | vertexBufferOffset:(size_t)vertexBufferOffset; 70 | - (void)renderDrawData:(ImDrawData *)drawData 71 | commandBuffer:(id)commandBuffer 72 | commandEncoder:(id)commandEncoder; 73 | @end 74 | 75 | static MetalContext *g_sharedMetalContext = nil; 76 | 77 | #pragma mark - ImGui API implementation 78 | 79 | bool ImGui_ImplMetal_Init(id device) 80 | { 81 | ImGuiIO& io = ImGui::GetIO(); 82 | io.BackendRendererName = "imgui_impl_metal"; 83 | io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes. 84 | 85 | static dispatch_once_t onceToken; 86 | dispatch_once(&onceToken, ^{ 87 | g_sharedMetalContext = [[MetalContext alloc] init]; 88 | }); 89 | 90 | ImGui_ImplMetal_CreateDeviceObjects(device); 91 | 92 | return true; 93 | } 94 | 95 | void ImGui_ImplMetal_Shutdown() 96 | { 97 | ImGui_ImplMetal_DestroyDeviceObjects(); 98 | } 99 | 100 | void ImGui_ImplMetal_NewFrame(MTLRenderPassDescriptor *renderPassDescriptor) 101 | { 102 | IM_ASSERT(g_sharedMetalContext != nil && "No Metal context. Did you call ImGui_ImplMetal_Init() ?"); 103 | 104 | g_sharedMetalContext.framebufferDescriptor = [[FramebufferDescriptor alloc] initWithRenderPassDescriptor:renderPassDescriptor]; 105 | } 106 | 107 | // Metal Render function. 108 | void ImGui_ImplMetal_RenderDrawData(ImDrawData* draw_data, id commandBuffer, id commandEncoder) 109 | { 110 | [g_sharedMetalContext renderDrawData:draw_data commandBuffer:commandBuffer commandEncoder:commandEncoder]; 111 | } 112 | 113 | bool ImGui_ImplMetal_CreateFontsTexture(id device) 114 | { 115 | [g_sharedMetalContext makeFontTextureWithDevice:device]; 116 | 117 | ImGuiIO& io = ImGui::GetIO(); 118 | io.Fonts->SetTexID((__bridge void *)g_sharedMetalContext.fontTexture); // ImTextureID == void* 119 | 120 | return (g_sharedMetalContext.fontTexture != nil); 121 | } 122 | 123 | void ImGui_ImplMetal_DestroyFontsTexture() 124 | { 125 | ImGuiIO& io = ImGui::GetIO(); 126 | g_sharedMetalContext.fontTexture = nil; 127 | io.Fonts->SetTexID(nullptr); 128 | } 129 | 130 | bool ImGui_ImplMetal_CreateDeviceObjects(id device) 131 | { 132 | [g_sharedMetalContext makeDeviceObjectsWithDevice:device]; 133 | 134 | ImGui_ImplMetal_CreateFontsTexture(device); 135 | 136 | return true; 137 | } 138 | 139 | void ImGui_ImplMetal_DestroyDeviceObjects() 140 | { 141 | ImGui_ImplMetal_DestroyFontsTexture(); 142 | [g_sharedMetalContext emptyRenderPipelineStateCache]; 143 | } 144 | 145 | #pragma mark - MetalBuffer implementation 146 | 147 | @implementation MetalBuffer 148 | - (instancetype)initWithBuffer:(id)buffer 149 | { 150 | if ((self = [super init])) 151 | { 152 | _buffer = buffer; 153 | _lastReuseTime = [NSDate date].timeIntervalSince1970; 154 | } 155 | return self; 156 | } 157 | @end 158 | 159 | #pragma mark - FramebufferDescriptor implementation 160 | 161 | @implementation FramebufferDescriptor 162 | - (instancetype)initWithRenderPassDescriptor:(MTLRenderPassDescriptor *)renderPassDescriptor 163 | { 164 | if ((self = [super init])) 165 | { 166 | _sampleCount = renderPassDescriptor.colorAttachments[0].texture.sampleCount; 167 | _colorPixelFormat = renderPassDescriptor.colorAttachments[0].texture.pixelFormat; 168 | _depthPixelFormat = renderPassDescriptor.depthAttachment.texture.pixelFormat; 169 | _stencilPixelFormat = renderPassDescriptor.stencilAttachment.texture.pixelFormat; 170 | } 171 | return self; 172 | } 173 | 174 | - (nonnull id)copyWithZone:(nullable NSZone *)zone 175 | { 176 | FramebufferDescriptor *copy = [[FramebufferDescriptor allocWithZone:zone] init]; 177 | copy.sampleCount = self.sampleCount; 178 | copy.colorPixelFormat = self.colorPixelFormat; 179 | copy.depthPixelFormat = self.depthPixelFormat; 180 | copy.stencilPixelFormat = self.stencilPixelFormat; 181 | return copy; 182 | } 183 | 184 | - (NSUInteger)hash 185 | { 186 | NSUInteger sc = _sampleCount & 0x3; 187 | NSUInteger cf = _colorPixelFormat & 0x3FF; 188 | NSUInteger df = _depthPixelFormat & 0x3FF; 189 | NSUInteger sf = _stencilPixelFormat & 0x3FF; 190 | NSUInteger hash = (sf << 22) | (df << 12) | (cf << 2) | sc; 191 | return hash; 192 | } 193 | 194 | - (BOOL)isEqual:(id)object 195 | { 196 | FramebufferDescriptor *other = object; 197 | if (![other isKindOfClass:[FramebufferDescriptor class]]) 198 | return NO; 199 | return other.sampleCount == self.sampleCount && 200 | other.colorPixelFormat == self.colorPixelFormat && 201 | other.depthPixelFormat == self.depthPixelFormat && 202 | other.stencilPixelFormat == self.stencilPixelFormat; 203 | } 204 | 205 | @end 206 | 207 | #pragma mark - MetalContext implementation 208 | 209 | @implementation MetalContext 210 | - (instancetype)init { 211 | if ((self = [super init])) 212 | { 213 | _renderPipelineStateCache = [NSMutableDictionary dictionary]; 214 | _bufferCache = [NSMutableArray array]; 215 | _lastBufferCachePurge = [NSDate date].timeIntervalSince1970; 216 | } 217 | return self; 218 | } 219 | 220 | - (void)makeDeviceObjectsWithDevice:(id)device 221 | { 222 | MTLDepthStencilDescriptor *depthStencilDescriptor = [[MTLDepthStencilDescriptor alloc] init]; 223 | depthStencilDescriptor.depthWriteEnabled = NO; 224 | depthStencilDescriptor.depthCompareFunction = MTLCompareFunctionAlways; 225 | self.depthStencilState = [device newDepthStencilStateWithDescriptor:depthStencilDescriptor]; 226 | } 227 | 228 | // We are retrieving and uploading the font atlas as a 4-channels RGBA texture here. 229 | // In theory we could call GetTexDataAsAlpha8() and upload a 1-channel texture to save on memory access bandwidth. 230 | // However, using a shader designed for 1-channel texture would make it less obvious to use the ImTextureID facility to render users own textures. 231 | // You can make that change in your implementation. 232 | - (void)makeFontTextureWithDevice:(id)device 233 | { 234 | ImGuiIO &io = ImGui::GetIO(); 235 | unsigned char* pixels; 236 | int width, height; 237 | io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); 238 | MTLTextureDescriptor *textureDescriptor = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatRGBA8Unorm 239 | width:(NSUInteger)width 240 | height:(NSUInteger)height 241 | mipmapped:NO]; 242 | id texture = [device newTextureWithDescriptor:textureDescriptor]; 243 | [texture replaceRegion:MTLRegionMake2D(0, 0, (NSUInteger)width, (NSUInteger)height) mipmapLevel:0 withBytes:pixels bytesPerRow:(NSUInteger)width * 4]; 244 | self.fontTexture = texture; 245 | } 246 | 247 | - (MetalBuffer *)dequeueReusableBufferOfLength:(NSUInteger)length device:(id)device 248 | { 249 | NSTimeInterval now = [NSDate date].timeIntervalSince1970; 250 | 251 | // Purge old buffers that haven't been useful for a while 252 | if (now - self.lastBufferCachePurge > 1.0) 253 | { 254 | NSMutableArray *survivors = [NSMutableArray array]; 255 | for (MetalBuffer *candidate in self.bufferCache) 256 | { 257 | if (candidate.lastReuseTime > self.lastBufferCachePurge) 258 | { 259 | [survivors addObject:candidate]; 260 | } 261 | } 262 | self.bufferCache = [survivors mutableCopy]; 263 | self.lastBufferCachePurge = now; 264 | } 265 | 266 | // See if we have a buffer we can reuse 267 | MetalBuffer *bestCandidate = nil; 268 | for (MetalBuffer *candidate in self.bufferCache) 269 | if (candidate.buffer.length >= length && (bestCandidate == nil || bestCandidate.lastReuseTime > candidate.lastReuseTime)) 270 | bestCandidate = candidate; 271 | 272 | if (bestCandidate != nil) 273 | { 274 | [self.bufferCache removeObject:bestCandidate]; 275 | bestCandidate.lastReuseTime = now; 276 | return bestCandidate; 277 | } 278 | 279 | // No luck; make a new buffer 280 | id backing = [device newBufferWithLength:length options:MTLResourceStorageModeShared]; 281 | return [[MetalBuffer alloc] initWithBuffer:backing]; 282 | } 283 | 284 | - (void)enqueueReusableBuffer:(MetalBuffer *)buffer 285 | { 286 | [self.bufferCache addObject:buffer]; 287 | } 288 | 289 | - (_Nullable id)renderPipelineStateForFrameAndDevice:(id)device 290 | { 291 | // Try to retrieve a render pipeline state that is compatible with the framebuffer config for this frame 292 | // The hit rate for this cache should be very near 100%. 293 | id renderPipelineState = self.renderPipelineStateCache[self.framebufferDescriptor]; 294 | 295 | if (renderPipelineState == nil) 296 | { 297 | // No luck; make a new render pipeline state 298 | renderPipelineState = [self _renderPipelineStateForFramebufferDescriptor:self.framebufferDescriptor device:device]; 299 | // Cache render pipeline state for later reuse 300 | self.renderPipelineStateCache[self.framebufferDescriptor] = renderPipelineState; 301 | } 302 | 303 | return renderPipelineState; 304 | } 305 | 306 | - (id)_renderPipelineStateForFramebufferDescriptor:(FramebufferDescriptor *)descriptor device:(id)device 307 | { 308 | NSError *error = nil; 309 | 310 | NSString *shaderSource = @"" 311 | "#include \n" 312 | "using namespace metal;\n" 313 | "\n" 314 | "struct Uniforms {\n" 315 | " float4x4 projectionMatrix;\n" 316 | "};\n" 317 | "\n" 318 | "struct VertexIn {\n" 319 | " float2 position [[attribute(0)]];\n" 320 | " float2 texCoords [[attribute(1)]];\n" 321 | " uchar4 color [[attribute(2)]];\n" 322 | "};\n" 323 | "\n" 324 | "struct VertexOut {\n" 325 | " float4 position [[position]];\n" 326 | " float2 texCoords;\n" 327 | " float4 color;\n" 328 | "};\n" 329 | "\n" 330 | "vertex VertexOut vertex_main(VertexIn in [[stage_in]],\n" 331 | " constant Uniforms &uniforms [[buffer(1)]]) {\n" 332 | " VertexOut out;\n" 333 | " out.position = uniforms.projectionMatrix * float4(in.position, 0, 1);\n" 334 | " out.texCoords = in.texCoords;\n" 335 | " out.color = float4(in.color) / float4(255.0);\n" 336 | " return out;\n" 337 | "}\n" 338 | "\n" 339 | "fragment half4 fragment_main(VertexOut in [[stage_in]],\n" 340 | " texture2d texture [[texture(0)]]) {\n" 341 | " constexpr sampler linearSampler(coord::normalized, min_filter::linear, mag_filter::linear, mip_filter::linear);\n" 342 | " half4 texColor = texture.sample(linearSampler, in.texCoords);\n" 343 | " return half4(in.color) * texColor;\n" 344 | "}\n"; 345 | 346 | id library = [device newLibraryWithSource:shaderSource options:nil error:&error]; 347 | if (library == nil) 348 | { 349 | NSLog(@"Error: failed to create Metal library: %@", error); 350 | return nil; 351 | } 352 | 353 | id vertexFunction = [library newFunctionWithName:@"vertex_main"]; 354 | id fragmentFunction = [library newFunctionWithName:@"fragment_main"]; 355 | 356 | if (vertexFunction == nil || fragmentFunction == nil) 357 | { 358 | NSLog(@"Error: failed to find Metal shader functions in library: %@", error); 359 | return nil; 360 | } 361 | 362 | MTLVertexDescriptor *vertexDescriptor = [MTLVertexDescriptor vertexDescriptor]; 363 | vertexDescriptor.attributes[0].offset = IM_OFFSETOF(ImDrawVert, pos); 364 | vertexDescriptor.attributes[0].format = MTLVertexFormatFloat2; // position 365 | vertexDescriptor.attributes[0].bufferIndex = 0; 366 | vertexDescriptor.attributes[1].offset = IM_OFFSETOF(ImDrawVert, uv); 367 | vertexDescriptor.attributes[1].format = MTLVertexFormatFloat2; // texCoords 368 | vertexDescriptor.attributes[1].bufferIndex = 0; 369 | vertexDescriptor.attributes[2].offset = IM_OFFSETOF(ImDrawVert, col); 370 | vertexDescriptor.attributes[2].format = MTLVertexFormatUChar4; // color 371 | vertexDescriptor.attributes[2].bufferIndex = 0; 372 | vertexDescriptor.layouts[0].stepRate = 1; 373 | vertexDescriptor.layouts[0].stepFunction = MTLVertexStepFunctionPerVertex; 374 | vertexDescriptor.layouts[0].stride = sizeof(ImDrawVert); 375 | 376 | MTLRenderPipelineDescriptor *pipelineDescriptor = [[MTLRenderPipelineDescriptor alloc] init]; 377 | pipelineDescriptor.vertexFunction = vertexFunction; 378 | pipelineDescriptor.fragmentFunction = fragmentFunction; 379 | pipelineDescriptor.vertexDescriptor = vertexDescriptor; 380 | pipelineDescriptor.sampleCount = self.framebufferDescriptor.sampleCount; 381 | pipelineDescriptor.colorAttachments[0].pixelFormat = self.framebufferDescriptor.colorPixelFormat; 382 | pipelineDescriptor.colorAttachments[0].blendingEnabled = YES; 383 | pipelineDescriptor.colorAttachments[0].rgbBlendOperation = MTLBlendOperationAdd; 384 | pipelineDescriptor.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactorSourceAlpha; 385 | pipelineDescriptor.colorAttachments[0].destinationRGBBlendFactor = MTLBlendFactorOneMinusSourceAlpha; 386 | pipelineDescriptor.colorAttachments[0].alphaBlendOperation = MTLBlendOperationAdd; 387 | pipelineDescriptor.colorAttachments[0].sourceAlphaBlendFactor = MTLBlendFactorOne; 388 | pipelineDescriptor.colorAttachments[0].destinationAlphaBlendFactor = MTLBlendFactorOneMinusSourceAlpha; 389 | pipelineDescriptor.depthAttachmentPixelFormat = self.framebufferDescriptor.depthPixelFormat; 390 | pipelineDescriptor.stencilAttachmentPixelFormat = self.framebufferDescriptor.stencilPixelFormat; 391 | 392 | id renderPipelineState = [device newRenderPipelineStateWithDescriptor:pipelineDescriptor error:&error]; 393 | if (error != nil) 394 | { 395 | NSLog(@"Error: failed to create Metal pipeline state: %@", error); 396 | } 397 | 398 | return renderPipelineState; 399 | } 400 | 401 | - (void)emptyRenderPipelineStateCache 402 | { 403 | [self.renderPipelineStateCache removeAllObjects]; 404 | } 405 | 406 | - (void)setupRenderState:(ImDrawData *)drawData 407 | commandBuffer:(id)commandBuffer 408 | commandEncoder:(id)commandEncoder 409 | renderPipelineState:(id)renderPipelineState 410 | vertexBuffer:(MetalBuffer *)vertexBuffer 411 | vertexBufferOffset:(size_t)vertexBufferOffset 412 | { 413 | [commandEncoder setCullMode:MTLCullModeNone]; 414 | [commandEncoder setDepthStencilState:g_sharedMetalContext.depthStencilState]; 415 | 416 | // Setup viewport, orthographic projection matrix 417 | // Our visible imgui space lies from draw_data->DisplayPos (top left) to 418 | // draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayMin is typically (0,0) for single viewport apps. 419 | MTLViewport viewport = 420 | { 421 | .originX = 0.0, 422 | .originY = 0.0, 423 | .width = (double)(drawData->DisplaySize.x * drawData->FramebufferScale.x), 424 | .height = (double)(drawData->DisplaySize.y * drawData->FramebufferScale.y), 425 | .znear = 0.0, 426 | .zfar = 1.0 427 | }; 428 | [commandEncoder setViewport:viewport]; 429 | 430 | float L = drawData->DisplayPos.x; 431 | float R = drawData->DisplayPos.x + drawData->DisplaySize.x; 432 | float T = drawData->DisplayPos.y; 433 | float B = drawData->DisplayPos.y + drawData->DisplaySize.y; 434 | float N = (float)viewport.znear; 435 | float F = (float)viewport.zfar; 436 | const float ortho_projection[4][4] = 437 | { 438 | { 2.0f/(R-L), 0.0f, 0.0f, 0.0f }, 439 | { 0.0f, 2.0f/(T-B), 0.0f, 0.0f }, 440 | { 0.0f, 0.0f, 1/(F-N), 0.0f }, 441 | { (R+L)/(L-R), (T+B)/(B-T), N/(F-N), 1.0f }, 442 | }; 443 | [commandEncoder setVertexBytes:&ortho_projection length:sizeof(ortho_projection) atIndex:1]; 444 | 445 | [commandEncoder setRenderPipelineState:renderPipelineState]; 446 | 447 | [commandEncoder setVertexBuffer:vertexBuffer.buffer offset:0 atIndex:0]; 448 | [commandEncoder setVertexBufferOffset:vertexBufferOffset atIndex:0]; 449 | } 450 | 451 | - (void)renderDrawData:(ImDrawData *)drawData 452 | commandBuffer:(id)commandBuffer 453 | commandEncoder:(id)commandEncoder 454 | { 455 | // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) 456 | int fb_width = (int)(drawData->DisplaySize.x * drawData->FramebufferScale.x); 457 | int fb_height = (int)(drawData->DisplaySize.y * drawData->FramebufferScale.y); 458 | if (fb_width <= 0 || fb_height <= 0 || drawData->CmdListsCount == 0) 459 | return; 460 | 461 | id renderPipelineState = [self renderPipelineStateForFrameAndDevice:commandBuffer.device]; 462 | 463 | size_t vertexBufferLength = (size_t)drawData->TotalVtxCount * sizeof(ImDrawVert); 464 | size_t indexBufferLength = (size_t)drawData->TotalIdxCount * sizeof(ImDrawIdx); 465 | MetalBuffer* vertexBuffer = [self dequeueReusableBufferOfLength:vertexBufferLength device:commandBuffer.device]; 466 | MetalBuffer* indexBuffer = [self dequeueReusableBufferOfLength:indexBufferLength device:commandBuffer.device]; 467 | 468 | [self setupRenderState:drawData commandBuffer:commandBuffer commandEncoder:commandEncoder renderPipelineState:renderPipelineState vertexBuffer:vertexBuffer vertexBufferOffset:0]; 469 | 470 | // Will project scissor/clipping rectangles into framebuffer space 471 | ImVec2 clip_off = drawData->DisplayPos; // (0,0) unless using multi-viewports 472 | ImVec2 clip_scale = drawData->FramebufferScale; // (1,1) unless using retina display which are often (2,2) 473 | 474 | // Render command lists 475 | size_t vertexBufferOffset = 0; 476 | size_t indexBufferOffset = 0; 477 | for (int n = 0; n < drawData->CmdListsCount; n++) 478 | { 479 | const ImDrawList* cmd_list = drawData->CmdLists[n]; 480 | 481 | memcpy((char *)vertexBuffer.buffer.contents + vertexBufferOffset, cmd_list->VtxBuffer.Data, (size_t)cmd_list->VtxBuffer.Size * sizeof(ImDrawVert)); 482 | memcpy((char *)indexBuffer.buffer.contents + indexBufferOffset, cmd_list->IdxBuffer.Data, (size_t)cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx)); 483 | 484 | for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) 485 | { 486 | const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; 487 | if (pcmd->UserCallback) 488 | { 489 | // User callback, registered via ImDrawList::AddCallback() 490 | // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.) 491 | if (pcmd->UserCallback == ImDrawCallback_ResetRenderState) 492 | [self setupRenderState:drawData commandBuffer:commandBuffer commandEncoder:commandEncoder renderPipelineState:renderPipelineState vertexBuffer:vertexBuffer vertexBufferOffset:vertexBufferOffset]; 493 | else 494 | pcmd->UserCallback(cmd_list, pcmd); 495 | } 496 | else 497 | { 498 | // Project scissor/clipping rectangles into framebuffer space 499 | ImVec4 clip_rect; 500 | clip_rect.x = (pcmd->ClipRect.x - clip_off.x) * clip_scale.x; 501 | clip_rect.y = (pcmd->ClipRect.y - clip_off.y) * clip_scale.y; 502 | clip_rect.z = (pcmd->ClipRect.z - clip_off.x) * clip_scale.x; 503 | clip_rect.w = (pcmd->ClipRect.w - clip_off.y) * clip_scale.y; 504 | 505 | if (clip_rect.x < fb_width && clip_rect.y < fb_height && clip_rect.z >= 0.0f && clip_rect.w >= 0.0f) 506 | { 507 | // Apply scissor/clipping rectangle 508 | MTLScissorRect scissorRect = 509 | { 510 | .x = NSUInteger(clip_rect.x), 511 | .y = NSUInteger(clip_rect.y), 512 | .width = NSUInteger(clip_rect.z - clip_rect.x), 513 | .height = NSUInteger(clip_rect.w - clip_rect.y) 514 | }; 515 | [commandEncoder setScissorRect:scissorRect]; 516 | 517 | 518 | // Bind texture, Draw 519 | if (pcmd->TextureId != NULL) 520 | [commandEncoder setFragmentTexture:(__bridge id)(pcmd->TextureId) atIndex:0]; 521 | 522 | [commandEncoder setVertexBufferOffset:(vertexBufferOffset + pcmd->VtxOffset * sizeof(ImDrawVert)) atIndex:0]; 523 | [commandEncoder drawIndexedPrimitives:MTLPrimitiveTypeTriangle 524 | indexCount:pcmd->ElemCount 525 | indexType:sizeof(ImDrawIdx) == 2 ? MTLIndexTypeUInt16 : MTLIndexTypeUInt32 526 | indexBuffer:indexBuffer.buffer 527 | indexBufferOffset:indexBufferOffset + pcmd->IdxOffset * sizeof(ImDrawIdx)]; 528 | } 529 | } 530 | } 531 | 532 | vertexBufferOffset += (size_t)cmd_list->VtxBuffer.Size * sizeof(ImDrawVert); 533 | indexBufferOffset += (size_t)cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx); 534 | } 535 | 536 | __weak id weakSelf = self; 537 | [commandBuffer addCompletedHandler:^(id) 538 | { 539 | dispatch_async(dispatch_get_main_queue(), ^{ 540 | [weakSelf enqueueReusableBuffer:vertexBuffer]; 541 | [weakSelf enqueueReusableBuffer:indexBuffer]; 542 | }); 543 | }]; 544 | } 545 | 546 | @end 547 | -------------------------------------------------------------------------------- /workingMenu16.4/KittyMemory/imgui_memory_editor.h: -------------------------------------------------------------------------------- 1 | // Mini memory editor for Dear ImGui (to embed in your game/tools) 2 | // Get latest version at http://www.github.com/ocornut/imgui_club 3 | // 4 | // Right-click anywhere to access the Options menu! 5 | // You can adjust the keyboard repeat delay/rate in ImGuiIO. 6 | // The code assume a mono-space font for simplicity! 7 | // If you don't use the default font, use ImGui::PushFont()/PopFont() to switch to a mono-space font before calling this. 8 | // 9 | // Usage: 10 | // // Create a window and draw memory editor inside it: 11 | // static MemoryEditor mem_edit_1; 12 | // static char data[0x10000]; 13 | // size_t data_size = 0x10000; 14 | // mem_edit_1.DrawWindow("Memory Editor", data, data_size); 15 | // 16 | // Usage: 17 | // // If you already have a window, use DrawContents() instead: 18 | // static MemoryEditor mem_edit_2; 19 | // ImGui::Begin("MyWindow") 20 | // mem_edit_2.DrawContents(this, sizeof(*this), (size_t)this); 21 | // ImGui::End(); 22 | // 23 | // Changelog: 24 | // - v0.10: initial version 25 | // - v0.23 (2017/08/17): added to github. fixed right-arrow triggering a byte write. 26 | // - v0.24 (2018/06/02): changed DragInt("Rows" to use a %d data format (which is desirable since imgui 1.61). 27 | // - v0.25 (2018/07/11): fixed wording: all occurrences of "Rows" renamed to "Columns". 28 | // - v0.26 (2018/08/02): fixed clicking on hex region 29 | // - v0.30 (2018/08/02): added data preview for common data types 30 | // - v0.31 (2018/10/10): added OptUpperCaseHex option to select lower/upper casing display [@samhocevar] 31 | // - v0.32 (2018/10/10): changed signatures to use void* instead of unsigned char* 32 | // - v0.33 (2018/10/10): added OptShowOptions option to hide all the interactive option setting. 33 | // - v0.34 (2019/05/07): binary preview now applies endianness setting [@nicolasnoble] 34 | // - v0.35 (2020/01/29): using ImGuiDataType available since Dear ImGui 1.69. 35 | // - v0.36 (2020/05/05): minor tweaks, minor refactor. 36 | // - v0.40 (2020/10/04): fix misuse of ImGuiListClipper API, broke with Dear ImGui 1.79. made cursor position appears on left-side of edit box. option popup appears on mouse release. fix MSVC warnings where _CRT_SECURE_NO_WARNINGS wasn't working in recent versions. 37 | // - v0.41 (2020/10/05): fix when using with keyboard/gamepad navigation enabled. 38 | // - v0.42 (2020/10/14): fix for . character in ASCII view always being greyed out. 39 | // - v0.43 (2021/03/12): added OptFooterExtraHeight to allow for custom drawing at the bottom of the editor [@leiradel] 40 | // - v0.44 (2021/03/12): use ImGuiInputTextFlags_AlwaysOverwrite in 1.82 + fix hardcoded width. 41 | // - v0.50 (2021/11/12): various fixes for recent dear imgui versions (fixed misuse of clipper, relying on SetKeyboardFocusHere() handling scrolling from 1.85). added default size. 42 | // 43 | // Todo/Bugs: 44 | // - This is generally old/crappy code, it should work but isn't very good.. to be rewritten some day. 45 | // - PageUp/PageDown are supported because we use _NoNav. This is a good test scenario for working out idioms of how to mix natural nav and our own... 46 | // - Arrows are being sent to the InputText() about to disappear which for LeftArrow makes the text cursor appear at position 1 for one frame. 47 | // - Using InputText() is awkward and maybe overkill here, consider implementing something custom. 48 | 49 | #pragma once 50 | 51 | #include // sprintf, scanf 52 | #include // uint8_t, etc. 53 | 54 | #include "imgui.h" 55 | #include "imgui_internal.h" 56 | #include "imgui_impl_metal.h" 57 | 58 | #ifdef _MSC_VER 59 | #define _PRISizeT "I" 60 | #define ImSnprintf _snprintf 61 | #else 62 | #define _PRISizeT "z" 63 | #define ImSnprintf snprintf 64 | #endif 65 | 66 | #ifdef _MSC_VER 67 | #pragma warning (push) 68 | #pragma warning (disable: 4996) // warning C4996: 'sprintf': This function or variable may be unsafe. 69 | #endif 70 | 71 | struct MemoryEditor 72 | { 73 | enum DataFormat 74 | { 75 | DataFormat_Bin = 0, 76 | DataFormat_Dec = 1, 77 | DataFormat_Hex = 2, 78 | DataFormat_COUNT 79 | }; 80 | 81 | // Settings 82 | bool Open; // = true // set to false when DrawWindow() was closed. ignore if not using DrawWindow(). 83 | bool ReadOnly; // = false // disable any editing. 84 | int Cols; // = 16 // number of columns to display. 85 | bool OptShowOptions; // = true // display options button/context menu. when disabled, options will be locked unless you provide your own UI for them. 86 | bool OptShowDataPreview; // = false // display a footer previewing the decimal/binary/hex/float representation of the currently selected bytes. 87 | bool OptShowHexII; // = false // display values in HexII representation instead of regular hexadecimal: hide null/zero bytes, ascii values as ".X". 88 | bool OptShowAscii; // = true // display ASCII representation on the right side. 89 | bool OptGreyOutZeroes; // = true // display null/zero bytes using the TextDisabled color. 90 | bool OptUpperCaseHex; // = true // display hexadecimal values as "FF" instead of "ff". 91 | int OptMidColsCount; // = 8 // set to 0 to disable extra spacing between every mid-cols. 92 | int OptAddrDigitsCount; // = 0 // number of addr digits to display (default calculated based on maximum displayed addr). 93 | float OptFooterExtraHeight; // = 0 // space to reserve at the bottom of the widget to add custom widgets 94 | ImU32 HighlightColor; // // background color of highlighted bytes. 95 | ImU8 (*ReadFn)(const ImU8* data, size_t off); // = 0 // optional handler to read bytes. 96 | void (*WriteFn)(ImU8* data, size_t off, ImU8 d); // = 0 // optional handler to write bytes. 97 | bool (*HighlightFn)(const ImU8* data, size_t off);//= 0 // optional handler to return Highlight property (to support non-contiguous highlighting). 98 | 99 | // [Internal State] 100 | bool ContentsWidthChanged; 101 | size_t DataPreviewAddr; 102 | size_t DataEditingAddr; 103 | bool DataEditingTakeFocus; 104 | char DataInputBuf[32]; 105 | char AddrInputBuf[32]; 106 | size_t GotoAddr; 107 | size_t HighlightMin, HighlightMax; 108 | int PreviewEndianess; 109 | ImGuiDataType PreviewDataType; 110 | 111 | MemoryEditor() 112 | { 113 | // Settings 114 | Open = true; 115 | ReadOnly = false; 116 | Cols = 16; 117 | OptShowOptions = true; 118 | OptShowDataPreview = false; 119 | OptShowHexII = false; 120 | OptShowAscii = true; 121 | OptGreyOutZeroes = true; 122 | OptUpperCaseHex = true; 123 | OptMidColsCount = 8; 124 | OptAddrDigitsCount = 0; 125 | OptFooterExtraHeight = 0.0f; 126 | HighlightColor = IM_COL32(255, 255, 255, 50); 127 | ReadFn = NULL; 128 | WriteFn = NULL; 129 | HighlightFn = NULL; 130 | 131 | // State/Internals 132 | ContentsWidthChanged = false; 133 | DataPreviewAddr = DataEditingAddr = (size_t)-1; 134 | DataEditingTakeFocus = false; 135 | memset(DataInputBuf, 0, sizeof(DataInputBuf)); 136 | memset(AddrInputBuf, 0, sizeof(AddrInputBuf)); 137 | GotoAddr = (size_t)-1; 138 | HighlightMin = HighlightMax = (size_t)-1; 139 | PreviewEndianess = 0; 140 | PreviewDataType = ImGuiDataType_S32; 141 | } 142 | 143 | void GotoAddrAndHighlight(size_t addr_min, size_t addr_max) 144 | { 145 | GotoAddr = addr_min; 146 | HighlightMin = addr_min; 147 | HighlightMax = addr_max; 148 | } 149 | 150 | struct Sizes 151 | { 152 | int AddrDigitsCount; 153 | float LineHeight; 154 | float GlyphWidth; 155 | float HexCellWidth; 156 | float SpacingBetweenMidCols; 157 | float PosHexStart; 158 | float PosHexEnd; 159 | float PosAsciiStart; 160 | float PosAsciiEnd; 161 | float WindowWidth; 162 | 163 | Sizes() { memset(this, 0, sizeof(*this)); } 164 | }; 165 | 166 | void CalcSizes(Sizes& s, size_t mem_size, size_t base_display_addr) 167 | { 168 | ImGuiStyle& style = ImGui::GetStyle(); 169 | s.AddrDigitsCount = OptAddrDigitsCount; 170 | if (s.AddrDigitsCount == 0) 171 | for (size_t n = base_display_addr + mem_size - 1; n > 0; n >>= 4) 172 | s.AddrDigitsCount++; 173 | s.LineHeight = ImGui::GetTextLineHeight(); 174 | s.GlyphWidth = ImGui::CalcTextSize("F").x + 1; // We assume the font is mono-space 175 | s.HexCellWidth = (float)(int)(s.GlyphWidth * 2.5f); // "FF " we include trailing space in the width to easily catch clicks everywhere 176 | s.SpacingBetweenMidCols = (float)(int)(s.HexCellWidth * 0.25f); // Every OptMidColsCount columns we add a bit of extra spacing 177 | s.PosHexStart = (s.AddrDigitsCount + 2) * s.GlyphWidth; 178 | s.PosHexEnd = s.PosHexStart + (s.HexCellWidth * Cols); 179 | s.PosAsciiStart = s.PosAsciiEnd = s.PosHexEnd; 180 | if (OptShowAscii) 181 | { 182 | s.PosAsciiStart = s.PosHexEnd + s.GlyphWidth * 1; 183 | if (OptMidColsCount > 0) 184 | s.PosAsciiStart += (float)((Cols + OptMidColsCount - 1) / OptMidColsCount) * s.SpacingBetweenMidCols; 185 | s.PosAsciiEnd = s.PosAsciiStart + Cols * s.GlyphWidth; 186 | } 187 | s.WindowWidth = s.PosAsciiEnd + style.ScrollbarSize + style.WindowPadding.x * 2 + s.GlyphWidth; 188 | } 189 | 190 | // Standalone Memory Editor window 191 | void DrawWindow(const char* title, void* mem_data, size_t mem_size, size_t base_display_addr = 0x0000) 192 | { 193 | Sizes s; 194 | CalcSizes(s, mem_size, base_display_addr); 195 | ImGui::SetNextWindowSize(ImVec2(s.WindowWidth, s.WindowWidth * 0.60f), ImGuiCond_FirstUseEver); 196 | ImGui::SetNextWindowSizeConstraints(ImVec2(0.0f, 0.0f), ImVec2(s.WindowWidth, FLT_MAX)); 197 | 198 | Open = true; 199 | if (ImGui::Begin(title, &Open, ImGuiWindowFlags_NoScrollbar)) 200 | { 201 | if (ImGui::IsWindowHovered(ImGuiHoveredFlags_RootAndChildWindows) && ImGui::IsMouseReleased(ImGuiMouseButton_Right)) 202 | ImGui::OpenPopup("context"); 203 | DrawContents(mem_data, mem_size, base_display_addr); 204 | if (ContentsWidthChanged) 205 | { 206 | CalcSizes(s, mem_size, base_display_addr); 207 | ImGui::SetWindowSize(ImVec2(s.WindowWidth, ImGui::GetWindowSize().y)); 208 | } 209 | } 210 | ImGui::End(); 211 | } 212 | 213 | // Memory Editor contents only 214 | void DrawContents(void* mem_data_void, size_t mem_size, size_t base_display_addr = 0x0000) 215 | { 216 | if (Cols < 1) 217 | Cols = 1; 218 | 219 | ImU8* mem_data = (ImU8*)mem_data_void; 220 | Sizes s; 221 | CalcSizes(s, mem_size, base_display_addr); 222 | ImGuiStyle& style = ImGui::GetStyle(); 223 | 224 | // We begin into our scrolling region with the 'ImGuiWindowFlags_NoMove' in order to prevent click from moving the window. 225 | // This is used as a facility since our main click detection code doesn't assign an ActiveId so the click would normally be caught as a window-move. 226 | const float height_separator = style.ItemSpacing.y; 227 | float footer_height = OptFooterExtraHeight; 228 | if (OptShowOptions) 229 | footer_height += height_separator + ImGui::GetFrameHeightWithSpacing() * 1; 230 | if (OptShowDataPreview) 231 | footer_height += height_separator + ImGui::GetFrameHeightWithSpacing() * 1 + ImGui::GetTextLineHeightWithSpacing() * 3; 232 | ImGui::BeginChild("##scrolling", ImVec2(0, -footer_height), false, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoNav); 233 | ImDrawList* draw_list = ImGui::GetWindowDrawList(); 234 | 235 | ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0)); 236 | ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); 237 | 238 | // We are not really using the clipper API correctly here, because we rely on visible_start_addr/visible_end_addr for our scrolling function. 239 | const int line_total_count = (int)((mem_size + Cols - 1) / Cols); 240 | ImGuiListClipper clipper; 241 | clipper.Begin(line_total_count, s.LineHeight); 242 | 243 | bool data_next = false; 244 | 245 | if (ReadOnly || DataEditingAddr >= mem_size) 246 | DataEditingAddr = (size_t)-1; 247 | if (DataPreviewAddr >= mem_size) 248 | DataPreviewAddr = (size_t)-1; 249 | 250 | size_t preview_data_type_size = OptShowDataPreview ? DataTypeGetSize(PreviewDataType) : 0; 251 | 252 | size_t data_editing_addr_next = (size_t)-1; 253 | if (DataEditingAddr != (size_t)-1) 254 | { 255 | // Move cursor but only apply on next frame so scrolling with be synchronized (because currently we can't change the scrolling while the window is being rendered) 256 | if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_UpArrow)) && (ptrdiff_t)DataEditingAddr >= (ptrdiff_t)Cols) { data_editing_addr_next = DataEditingAddr - Cols; } 257 | else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_DownArrow)) && (ptrdiff_t)DataEditingAddr < (ptrdiff_t)mem_size - Cols) { data_editing_addr_next = DataEditingAddr + Cols; } 258 | else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_LeftArrow)) && (ptrdiff_t)DataEditingAddr > (ptrdiff_t)0) { data_editing_addr_next = DataEditingAddr - 1; } 259 | else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_RightArrow)) && (ptrdiff_t)DataEditingAddr < (ptrdiff_t)mem_size - 1) { data_editing_addr_next = DataEditingAddr + 1; } 260 | } 261 | 262 | // Draw vertical separator 263 | ImVec2 window_pos = ImGui::GetWindowPos(); 264 | if (OptShowAscii) 265 | draw_list->AddLine(ImVec2(window_pos.x + s.PosAsciiStart - s.GlyphWidth, window_pos.y), ImVec2(window_pos.x + s.PosAsciiStart - s.GlyphWidth, window_pos.y + 9999), ImGui::GetColorU32(ImGuiCol_Border)); 266 | 267 | const ImU32 color_text = ImGui::GetColorU32(ImGuiCol_Text); 268 | const ImU32 color_disabled = OptGreyOutZeroes ? ImGui::GetColorU32(ImGuiCol_TextDisabled) : color_text; 269 | 270 | const char* format_address = OptUpperCaseHex ? "%0*" _PRISizeT "X: " : "%0*" _PRISizeT "x: "; 271 | const char* format_data = OptUpperCaseHex ? "%0*" _PRISizeT "X" : "%0*" _PRISizeT "x"; 272 | const char* format_byte = OptUpperCaseHex ? "%02X" : "%02x"; 273 | const char* format_byte_space = OptUpperCaseHex ? "%02X " : "%02x "; 274 | 275 | while (clipper.Step()) 276 | for (int line_i = clipper.DisplayStart; line_i < clipper.DisplayEnd; line_i++) // display only visible lines 277 | { 278 | size_t addr = (size_t)(line_i * Cols); 279 | ImGui::Text(format_address, s.AddrDigitsCount, base_display_addr + addr); 280 | 281 | // Draw Hexadecimal 282 | for (int n = 0; n < Cols && addr < mem_size; n++, addr++) 283 | { 284 | float byte_pos_x = s.PosHexStart + s.HexCellWidth * n; 285 | if (OptMidColsCount > 0) 286 | byte_pos_x += (float)(n / OptMidColsCount) * s.SpacingBetweenMidCols; 287 | ImGui::SameLine(byte_pos_x); 288 | 289 | // Draw highlight 290 | bool is_highlight_from_user_range = (addr >= HighlightMin && addr < HighlightMax); 291 | bool is_highlight_from_user_func = (HighlightFn && HighlightFn(mem_data, addr)); 292 | bool is_highlight_from_preview = (addr >= DataPreviewAddr && addr < DataPreviewAddr + preview_data_type_size); 293 | if (is_highlight_from_user_range || is_highlight_from_user_func || is_highlight_from_preview) 294 | { 295 | ImVec2 pos = ImGui::GetCursorScreenPos(); 296 | float highlight_width = s.GlyphWidth * 2; 297 | bool is_next_byte_highlighted = (addr + 1 < mem_size) && ((HighlightMax != (size_t)-1 && addr + 1 < HighlightMax) || (HighlightFn && HighlightFn(mem_data, addr + 1))); 298 | if (is_next_byte_highlighted || (n + 1 == Cols)) 299 | { 300 | highlight_width = s.HexCellWidth; 301 | if (OptMidColsCount > 0 && n > 0 && (n + 1) < Cols && ((n + 1) % OptMidColsCount) == 0) 302 | highlight_width += s.SpacingBetweenMidCols; 303 | } 304 | draw_list->AddRectFilled(pos, ImVec2(pos.x + highlight_width, pos.y + s.LineHeight), HighlightColor); 305 | } 306 | 307 | if (DataEditingAddr == addr) 308 | { 309 | // Display text input on current byte 310 | bool data_write = false; 311 | ImGui::PushID((void*)addr); 312 | if (DataEditingTakeFocus) 313 | { 314 | ImGui::SetKeyboardFocusHere(0); 315 | sprintf(AddrInputBuf, format_data, s.AddrDigitsCount, base_display_addr + addr); 316 | sprintf(DataInputBuf, format_byte, ReadFn ? ReadFn(mem_data, addr) : mem_data[addr]); 317 | } 318 | struct UserData 319 | { 320 | // FIXME: We should have a way to retrieve the text edit cursor position more easily in the API, this is rather tedious. This is such a ugly mess we may be better off not using InputText() at all here. 321 | static int Callback(ImGuiInputTextCallbackData* data) 322 | { 323 | UserData* user_data = (UserData*)data->UserData; 324 | if (!data->HasSelection()) 325 | user_data->CursorPos = data->CursorPos; 326 | if (data->SelectionStart == 0 && data->SelectionEnd == data->BufTextLen) 327 | { 328 | // When not editing a byte, always refresh its InputText content pulled from underlying memory data 329 | // (this is a bit tricky, since InputText technically "owns" the master copy of the buffer we edit it in there) 330 | data->DeleteChars(0, data->BufTextLen); 331 | data->InsertChars(0, user_data->CurrentBufOverwrite); 332 | data->SelectionStart = 0; 333 | data->SelectionEnd = 2; 334 | data->CursorPos = 0; 335 | } 336 | return 0; 337 | } 338 | char CurrentBufOverwrite[3]; // Input 339 | int CursorPos; // Output 340 | }; 341 | UserData user_data; 342 | user_data.CursorPos = -1; 343 | sprintf(user_data.CurrentBufOverwrite, format_byte, ReadFn ? ReadFn(mem_data, addr) : mem_data[addr]); 344 | ImGuiInputTextFlags flags = ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_AutoSelectAll | ImGuiInputTextFlags_NoHorizontalScroll | ImGuiInputTextFlags_CallbackAlways; 345 | #if IMGUI_VERSION_NUM >= 18104 346 | flags |= ImGuiInputTextFlags_AlwaysOverwrite; 347 | #else 348 | flags |= ImGuiInputTextFlags_AlwaysInsertMode; 349 | #endif 350 | ImGui::SetNextItemWidth(s.GlyphWidth * 2); 351 | if (ImGui::InputText("##data", DataInputBuf, IM_ARRAYSIZE(DataInputBuf), flags, UserData::Callback, &user_data)) 352 | data_write = data_next = true; 353 | else if (!DataEditingTakeFocus && !ImGui::IsItemActive()) 354 | DataEditingAddr = data_editing_addr_next = (size_t)-1; 355 | DataEditingTakeFocus = false; 356 | if (user_data.CursorPos >= 2) 357 | data_write = data_next = true; 358 | if (data_editing_addr_next != (size_t)-1) 359 | data_write = data_next = false; 360 | unsigned int data_input_value = 0; 361 | if (data_write && sscanf(DataInputBuf, "%X", &data_input_value) == 1) 362 | { 363 | if (WriteFn) 364 | WriteFn(mem_data, addr, (ImU8)data_input_value); 365 | else 366 | mem_data[addr] = (ImU8)data_input_value; 367 | } 368 | ImGui::PopID(); 369 | } 370 | else 371 | { 372 | // NB: The trailing space is not visible but ensure there's no gap that the mouse cannot click on. 373 | ImU8 b = ReadFn ? ReadFn(mem_data, addr) : mem_data[addr]; 374 | 375 | if (OptShowHexII) 376 | { 377 | if ((b >= 32 && b < 128)) 378 | ImGui::Text(".%c ", b); 379 | else if (b == 0xFF && OptGreyOutZeroes) 380 | ImGui::TextDisabled("## "); 381 | else if (b == 0x00) 382 | ImGui::Text(" "); 383 | else 384 | ImGui::Text(format_byte_space, b); 385 | } 386 | else 387 | { 388 | if (b == 0 && OptGreyOutZeroes) 389 | ImGui::TextDisabled("00 "); 390 | else 391 | ImGui::Text(format_byte_space, b); 392 | } 393 | if (!ReadOnly && ImGui::IsItemHovered() && ImGui::IsMouseClicked(0)) 394 | { 395 | DataEditingTakeFocus = true; 396 | data_editing_addr_next = addr; 397 | } 398 | } 399 | } 400 | 401 | if (OptShowAscii) 402 | { 403 | // Draw ASCII values 404 | ImGui::SameLine(s.PosAsciiStart); 405 | ImVec2 pos = ImGui::GetCursorScreenPos(); 406 | addr = line_i * Cols; 407 | ImGui::PushID(line_i); 408 | if (ImGui::InvisibleButton("ascii", ImVec2(s.PosAsciiEnd - s.PosAsciiStart, s.LineHeight))) 409 | { 410 | DataEditingAddr = DataPreviewAddr = addr + (size_t)((ImGui::GetIO().MousePos.x - pos.x) / s.GlyphWidth); 411 | DataEditingTakeFocus = true; 412 | } 413 | ImGui::PopID(); 414 | for (int n = 0; n < Cols && addr < mem_size; n++, addr++) 415 | { 416 | if (addr == DataEditingAddr) 417 | { 418 | draw_list->AddRectFilled(pos, ImVec2(pos.x + s.GlyphWidth, pos.y + s.LineHeight), ImGui::GetColorU32(ImGuiCol_FrameBg)); 419 | draw_list->AddRectFilled(pos, ImVec2(pos.x + s.GlyphWidth, pos.y + s.LineHeight), ImGui::GetColorU32(ImGuiCol_TextSelectedBg)); 420 | } 421 | unsigned char c = ReadFn ? ReadFn(mem_data, addr) : mem_data[addr]; 422 | char display_c = (c < 32 || c >= 128) ? '.' : c; 423 | draw_list->AddText(pos, (display_c == c) ? color_text : color_disabled, &display_c, &display_c + 1); 424 | pos.x += s.GlyphWidth; 425 | } 426 | } 427 | } 428 | ImGui::PopStyleVar(2); 429 | ImGui::EndChild(); 430 | 431 | // Notify the main window of our ideal child content size (FIXME: we are missing an API to get the contents size from the child) 432 | ImGui::SetCursorPosX(s.WindowWidth); 433 | 434 | if (data_next && DataEditingAddr + 1 < mem_size) 435 | { 436 | DataEditingAddr = DataPreviewAddr = DataEditingAddr + 1; 437 | DataEditingTakeFocus = true; 438 | } 439 | else if (data_editing_addr_next != (size_t)-1) 440 | { 441 | DataEditingAddr = DataPreviewAddr = data_editing_addr_next; 442 | DataEditingTakeFocus = true; 443 | } 444 | 445 | const bool lock_show_data_preview = OptShowDataPreview; 446 | if (OptShowOptions) 447 | { 448 | ImGui::Separator(); 449 | DrawOptionsLine(s, mem_data, mem_size, base_display_addr); 450 | } 451 | 452 | if (lock_show_data_preview) 453 | { 454 | ImGui::Separator(); 455 | DrawPreviewLine(s, mem_data, mem_size, base_display_addr); 456 | } 457 | } 458 | 459 | void DrawOptionsLine(const Sizes& s, void* mem_data, size_t mem_size, size_t base_display_addr) 460 | { 461 | IM_UNUSED(mem_data); 462 | ImGuiStyle& style = ImGui::GetStyle(); 463 | const char* format_range = OptUpperCaseHex ? "Range %0*" _PRISizeT "X..%0*" _PRISizeT "X" : "Range %0*" _PRISizeT "x..%0*" _PRISizeT "x"; 464 | 465 | // Options menu 466 | if (ImGui::Button("Options")) 467 | ImGui::OpenPopup("context"); 468 | if (ImGui::BeginPopup("context")) 469 | { 470 | ImGui::SetNextItemWidth(s.GlyphWidth * 7 + style.FramePadding.x * 2.0f); 471 | if (ImGui::DragInt("##cols", &Cols, 0.2f, 4, 32, "%d cols")) { ContentsWidthChanged = true; if (Cols < 1) Cols = 1; } 472 | ImGui::Checkbox("Show Data Preview", &OptShowDataPreview); 473 | ImGui::Checkbox("Show HexII", &OptShowHexII); 474 | if (ImGui::Checkbox("Show Ascii", &OptShowAscii)) { ContentsWidthChanged = true; } 475 | ImGui::Checkbox("Grey out zeroes", &OptGreyOutZeroes); 476 | ImGui::Checkbox("Uppercase Hex", &OptUpperCaseHex); 477 | 478 | ImGui::EndPopup(); 479 | } 480 | 481 | ImGui::SameLine(); 482 | ImGui::Text(format_range, s.AddrDigitsCount, base_display_addr, s.AddrDigitsCount, base_display_addr + mem_size - 1); 483 | ImGui::SameLine(); 484 | ImGui::SetNextItemWidth((s.AddrDigitsCount + 1) * s.GlyphWidth + style.FramePadding.x * 2.0f); 485 | if (ImGui::InputText("##addr", AddrInputBuf, IM_ARRAYSIZE(AddrInputBuf), ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_EnterReturnsTrue)) 486 | { 487 | size_t goto_addr; 488 | if (sscanf(AddrInputBuf, "%" _PRISizeT "X", &goto_addr) == 1) 489 | { 490 | GotoAddr = goto_addr - base_display_addr; 491 | HighlightMin = HighlightMax = (size_t)-1; 492 | } 493 | } 494 | 495 | if (GotoAddr != (size_t)-1) 496 | { 497 | if (GotoAddr < mem_size) 498 | { 499 | ImGui::BeginChild("##scrolling"); 500 | ImGui::SetScrollFromPosY(ImGui::GetCursorStartPos().y + (GotoAddr / Cols) * ImGui::GetTextLineHeight()); 501 | ImGui::EndChild(); 502 | DataEditingAddr = DataPreviewAddr = GotoAddr; 503 | DataEditingTakeFocus = true; 504 | } 505 | GotoAddr = (size_t)-1; 506 | } 507 | } 508 | 509 | void DrawPreviewLine(const Sizes& s, void* mem_data_void, size_t mem_size, size_t base_display_addr) 510 | { 511 | IM_UNUSED(base_display_addr); 512 | ImU8* mem_data = (ImU8*)mem_data_void; 513 | ImGuiStyle& style = ImGui::GetStyle(); 514 | ImGui::AlignTextToFramePadding(); 515 | ImGui::Text("Preview as:"); 516 | ImGui::SameLine(); 517 | ImGui::SetNextItemWidth((s.GlyphWidth * 10.0f) + style.FramePadding.x * 2.0f + style.ItemInnerSpacing.x); 518 | if (ImGui::BeginCombo("##combo_type", DataTypeGetDesc(PreviewDataType), ImGuiComboFlags_HeightLargest)) 519 | { 520 | for (int n = 0; n < ImGuiDataType_COUNT; n++) 521 | if (ImGui::Selectable(DataTypeGetDesc((ImGuiDataType)n), PreviewDataType == n)) 522 | PreviewDataType = (ImGuiDataType)n; 523 | ImGui::EndCombo(); 524 | } 525 | ImGui::SameLine(); 526 | ImGui::SetNextItemWidth((s.GlyphWidth * 6.0f) + style.FramePadding.x * 2.0f + style.ItemInnerSpacing.x); 527 | ImGui::Combo("##combo_endianess", &PreviewEndianess, "LE\0BE\0\0"); 528 | 529 | char buf[128] = ""; 530 | float x = s.GlyphWidth * 6.0f; 531 | bool has_value = DataPreviewAddr != (size_t)-1; 532 | if (has_value) 533 | DrawPreviewData(DataPreviewAddr, mem_data, mem_size, PreviewDataType, DataFormat_Dec, buf, (size_t)IM_ARRAYSIZE(buf)); 534 | ImGui::Text("Dec"); ImGui::SameLine(x); ImGui::TextUnformatted(has_value ? buf : "N/A"); 535 | if (has_value) 536 | DrawPreviewData(DataPreviewAddr, mem_data, mem_size, PreviewDataType, DataFormat_Hex, buf, (size_t)IM_ARRAYSIZE(buf)); 537 | ImGui::Text("Hex"); ImGui::SameLine(x); ImGui::TextUnformatted(has_value ? buf : "N/A"); 538 | if (has_value) 539 | DrawPreviewData(DataPreviewAddr, mem_data, mem_size, PreviewDataType, DataFormat_Bin, buf, (size_t)IM_ARRAYSIZE(buf)); 540 | buf[IM_ARRAYSIZE(buf) - 1] = 0; 541 | ImGui::Text("Bin"); ImGui::SameLine(x); ImGui::TextUnformatted(has_value ? buf : "N/A"); 542 | } 543 | 544 | // Utilities for Data Preview 545 | const char* DataTypeGetDesc(ImGuiDataType data_type) const 546 | { 547 | const char* descs[] = { "Int8", "Uint8", "Int16", "Uint16", "Int32", "Uint32", "Int64", "Uint64", "Float", "Double" }; 548 | IM_ASSERT(data_type >= 0 && data_type < ImGuiDataType_COUNT); 549 | return descs[data_type]; 550 | } 551 | 552 | size_t DataTypeGetSize(ImGuiDataType data_type) const 553 | { 554 | const size_t sizes[] = { 1, 1, 2, 2, 4, 4, 8, 8, sizeof(float), sizeof(double) }; 555 | IM_ASSERT(data_type >= 0 && data_type < ImGuiDataType_COUNT); 556 | return sizes[data_type]; 557 | } 558 | 559 | const char* DataFormatGetDesc(DataFormat data_format) const 560 | { 561 | const char* descs[] = { "Bin", "Dec", "Hex" }; 562 | IM_ASSERT(data_format >= 0 && data_format < DataFormat_COUNT); 563 | return descs[data_format]; 564 | } 565 | 566 | bool IsBigEndian() const 567 | { 568 | uint16_t x = 1; 569 | char c[2]; 570 | memcpy(c, &x, 2); 571 | return c[0] != 0; 572 | } 573 | 574 | static void* EndianessCopyBigEndian(void* _dst, void* _src, size_t s, int is_little_endian) 575 | { 576 | if (is_little_endian) 577 | { 578 | uint8_t* dst = (uint8_t*)_dst; 579 | uint8_t* src = (uint8_t*)_src + s - 1; 580 | for (int i = 0, n = (int)s; i < n; ++i) 581 | memcpy(dst++, src--, 1); 582 | return _dst; 583 | } 584 | else 585 | { 586 | return memcpy(_dst, _src, s); 587 | } 588 | } 589 | 590 | static void* EndianessCopyLittleEndian(void* _dst, void* _src, size_t s, int is_little_endian) 591 | { 592 | if (is_little_endian) 593 | { 594 | return memcpy(_dst, _src, s); 595 | } 596 | else 597 | { 598 | uint8_t* dst = (uint8_t*)_dst; 599 | uint8_t* src = (uint8_t*)_src + s - 1; 600 | for (int i = 0, n = (int)s; i < n; ++i) 601 | memcpy(dst++, src--, 1); 602 | return _dst; 603 | } 604 | } 605 | 606 | void* EndianessCopy(void* dst, void* src, size_t size) const 607 | { 608 | static void* (*fp)(void*, void*, size_t, int) = NULL; 609 | if (fp == NULL) 610 | fp = IsBigEndian() ? EndianessCopyBigEndian : EndianessCopyLittleEndian; 611 | return fp(dst, src, size, PreviewEndianess); 612 | } 613 | 614 | const char* FormatBinary(const uint8_t* buf, int width) const 615 | { 616 | IM_ASSERT(width <= 64); 617 | size_t out_n = 0; 618 | static char out_buf[64 + 8 + 1]; 619 | int n = width / 8; 620 | for (int j = n - 1; j >= 0; --j) 621 | { 622 | for (int i = 0; i < 8; ++i) 623 | out_buf[out_n++] = (buf[j] & (1 << (7 - i))) ? '1' : '0'; 624 | out_buf[out_n++] = ' '; 625 | } 626 | IM_ASSERT(out_n < IM_ARRAYSIZE(out_buf)); 627 | out_buf[out_n] = 0; 628 | return out_buf; 629 | } 630 | 631 | // [Internal] 632 | void DrawPreviewData(size_t addr, const ImU8* mem_data, size_t mem_size, ImGuiDataType data_type, DataFormat data_format, char* out_buf, size_t out_buf_size) const 633 | { 634 | uint8_t buf[8]; 635 | size_t elem_size = DataTypeGetSize(data_type); 636 | size_t size = addr + elem_size > mem_size ? mem_size - addr : elem_size; 637 | if (ReadFn) 638 | for (int i = 0, n = (int)size; i < n; ++i) 639 | buf[i] = ReadFn(mem_data, addr + i); 640 | else 641 | memcpy(buf, mem_data + addr, size); 642 | 643 | if (data_format == DataFormat_Bin) 644 | { 645 | uint8_t binbuf[8]; 646 | EndianessCopy(binbuf, buf, size); 647 | ImSnprintf(out_buf, out_buf_size, "%s", FormatBinary(binbuf, (int)size * 8)); 648 | return; 649 | } 650 | 651 | out_buf[0] = 0; 652 | switch (data_type) 653 | { 654 | case ImGuiDataType_S8: 655 | { 656 | int8_t int8 = 0; 657 | EndianessCopy(&int8, buf, size); 658 | if (data_format == DataFormat_Dec) { ImSnprintf(out_buf, out_buf_size, "%hhd", int8); return; } 659 | if (data_format == DataFormat_Hex) { ImSnprintf(out_buf, out_buf_size, "0x%02x", int8 & 0xFF); return; } 660 | break; 661 | } 662 | case ImGuiDataType_U8: 663 | { 664 | uint8_t uint8 = 0; 665 | EndianessCopy(&uint8, buf, size); 666 | if (data_format == DataFormat_Dec) { ImSnprintf(out_buf, out_buf_size, "%hhu", uint8); return; } 667 | if (data_format == DataFormat_Hex) { ImSnprintf(out_buf, out_buf_size, "0x%02x", uint8 & 0XFF); return; } 668 | break; 669 | } 670 | case ImGuiDataType_S16: 671 | { 672 | int16_t int16 = 0; 673 | EndianessCopy(&int16, buf, size); 674 | if (data_format == DataFormat_Dec) { ImSnprintf(out_buf, out_buf_size, "%hd", int16); return; } 675 | if (data_format == DataFormat_Hex) { ImSnprintf(out_buf, out_buf_size, "0x%04x", int16 & 0xFFFF); return; } 676 | break; 677 | } 678 | case ImGuiDataType_U16: 679 | { 680 | uint16_t uint16 = 0; 681 | EndianessCopy(&uint16, buf, size); 682 | if (data_format == DataFormat_Dec) { ImSnprintf(out_buf, out_buf_size, "%hu", uint16); return; } 683 | if (data_format == DataFormat_Hex) { ImSnprintf(out_buf, out_buf_size, "0x%04x", uint16 & 0xFFFF); return; } 684 | break; 685 | } 686 | case ImGuiDataType_S32: 687 | { 688 | int32_t int32 = 0; 689 | EndianessCopy(&int32, buf, size); 690 | if (data_format == DataFormat_Dec) { ImSnprintf(out_buf, out_buf_size, "%d", int32); return; } 691 | if (data_format == DataFormat_Hex) { ImSnprintf(out_buf, out_buf_size, "0x%08x", int32); return; } 692 | break; 693 | } 694 | case ImGuiDataType_U32: 695 | { 696 | uint32_t uint32 = 0; 697 | EndianessCopy(&uint32, buf, size); 698 | if (data_format == DataFormat_Dec) { ImSnprintf(out_buf, out_buf_size, "%u", uint32); return; } 699 | if (data_format == DataFormat_Hex) { ImSnprintf(out_buf, out_buf_size, "0x%08x", uint32); return; } 700 | break; 701 | } 702 | case ImGuiDataType_S64: 703 | { 704 | int64_t int64 = 0; 705 | EndianessCopy(&int64, buf, size); 706 | if (data_format == DataFormat_Dec) { ImSnprintf(out_buf, out_buf_size, "%lld", (long long)int64); return; } 707 | if (data_format == DataFormat_Hex) { ImSnprintf(out_buf, out_buf_size, "0x%016llx", (long long)int64); return; } 708 | break; 709 | } 710 | case ImGuiDataType_U64: 711 | { 712 | uint64_t uint64 = 0; 713 | EndianessCopy(&uint64, buf, size); 714 | if (data_format == DataFormat_Dec) { ImSnprintf(out_buf, out_buf_size, "%llu", (long long)uint64); return; } 715 | if (data_format == DataFormat_Hex) { ImSnprintf(out_buf, out_buf_size, "0x%016llx", (long long)uint64); return; } 716 | break; 717 | } 718 | case ImGuiDataType_Float: 719 | { 720 | float float32 = 0.0f; 721 | EndianessCopy(&float32, buf, size); 722 | if (data_format == DataFormat_Dec) { ImSnprintf(out_buf, out_buf_size, "%f", float32); return; } 723 | if (data_format == DataFormat_Hex) { ImSnprintf(out_buf, out_buf_size, "%a", float32); return; } 724 | break; 725 | } 726 | case ImGuiDataType_Double: 727 | { 728 | double float64 = 0.0; 729 | EndianessCopy(&float64, buf, size); 730 | if (data_format == DataFormat_Dec) { ImSnprintf(out_buf, out_buf_size, "%f", float64); return; } 731 | if (data_format == DataFormat_Hex) { ImSnprintf(out_buf, out_buf_size, "%a", float64); return; } 732 | break; 733 | } 734 | case ImGuiDataType_COUNT: 735 | break; 736 | } // Switch 737 | IM_ASSERT(0); // Shouldn't reach 738 | } 739 | }; 740 | 741 | #undef _PRISizeT 742 | #undef ImSnprintf 743 | 744 | #ifdef _MSC_VER 745 | #pragma warning (pop) 746 | #endif 747 | -------------------------------------------------------------------------------- /workingMenu16.4/KittyMemory/imstb_rectpack.h: -------------------------------------------------------------------------------- 1 | // [DEAR IMGUI] 2 | // This is a slightly modified version of stb_rect_pack.h 1.00. 3 | // Those changes would need to be pushed into nothings/stb: 4 | // - Added STBRP__CDECL 5 | // Grep for [DEAR IMGUI] to find the changes. 6 | 7 | // stb_rect_pack.h - v1.00 - public domain - rectangle packing 8 | // Sean Barrett 2014 9 | // 10 | // Useful for e.g. packing rectangular textures into an atlas. 11 | // Does not do rotation. 12 | // 13 | // Not necessarily the awesomest packing method, but better than 14 | // the totally naive one in stb_truetype (which is primarily what 15 | // this is meant to replace). 16 | // 17 | // Has only had a few tests run, may have issues. 18 | // 19 | // More docs to come. 20 | // 21 | // No memory allocations; uses qsort() and assert() from stdlib. 22 | // Can override those by defining STBRP_SORT and STBRP_ASSERT. 23 | // 24 | // This library currently uses the Skyline Bottom-Left algorithm. 25 | // 26 | // Please note: better rectangle packers are welcome! Please 27 | // implement them to the same API, but with a different init 28 | // function. 29 | // 30 | // Credits 31 | // 32 | // Library 33 | // Sean Barrett 34 | // Minor features 35 | // Martins Mozeiko 36 | // github:IntellectualKitty 37 | // 38 | // Bugfixes / warning fixes 39 | // Jeremy Jaussaud 40 | // Fabian Giesen 41 | // 42 | // Version history: 43 | // 44 | // 1.00 (2019-02-25) avoid small space waste; gracefully fail too-wide rectangles 45 | // 0.99 (2019-02-07) warning fixes 46 | // 0.11 (2017-03-03) return packing success/fail result 47 | // 0.10 (2016-10-25) remove cast-away-const to avoid warnings 48 | // 0.09 (2016-08-27) fix compiler warnings 49 | // 0.08 (2015-09-13) really fix bug with empty rects (w=0 or h=0) 50 | // 0.07 (2015-09-13) fix bug with empty rects (w=0 or h=0) 51 | // 0.06 (2015-04-15) added STBRP_SORT to allow replacing qsort 52 | // 0.05: added STBRP_ASSERT to allow replacing assert 53 | // 0.04: fixed minor bug in STBRP_LARGE_RECTS support 54 | // 0.01: initial release 55 | // 56 | // LICENSE 57 | // 58 | // See end of file for license information. 59 | 60 | ////////////////////////////////////////////////////////////////////////////// 61 | // 62 | // INCLUDE SECTION 63 | // 64 | 65 | #ifndef STB_INCLUDE_STB_RECT_PACK_H 66 | #define STB_INCLUDE_STB_RECT_PACK_H 67 | 68 | #define STB_RECT_PACK_VERSION 1 69 | 70 | #ifdef STBRP_STATIC 71 | #define STBRP_DEF static 72 | #else 73 | #define STBRP_DEF extern 74 | #endif 75 | 76 | #ifdef __cplusplus 77 | extern "C" { 78 | #endif 79 | 80 | typedef struct stbrp_context stbrp_context; 81 | typedef struct stbrp_node stbrp_node; 82 | typedef struct stbrp_rect stbrp_rect; 83 | 84 | #ifdef STBRP_LARGE_RECTS 85 | typedef int stbrp_coord; 86 | #else 87 | typedef unsigned short stbrp_coord; 88 | #endif 89 | 90 | STBRP_DEF int stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects); 91 | // Assign packed locations to rectangles. The rectangles are of type 92 | // 'stbrp_rect' defined below, stored in the array 'rects', and there 93 | // are 'num_rects' many of them. 94 | // 95 | // Rectangles which are successfully packed have the 'was_packed' flag 96 | // set to a non-zero value and 'x' and 'y' store the minimum location 97 | // on each axis (i.e. bottom-left in cartesian coordinates, top-left 98 | // if you imagine y increasing downwards). Rectangles which do not fit 99 | // have the 'was_packed' flag set to 0. 100 | // 101 | // You should not try to access the 'rects' array from another thread 102 | // while this function is running, as the function temporarily reorders 103 | // the array while it executes. 104 | // 105 | // To pack into another rectangle, you need to call stbrp_init_target 106 | // again. To continue packing into the same rectangle, you can call 107 | // this function again. Calling this multiple times with multiple rect 108 | // arrays will probably produce worse packing results than calling it 109 | // a single time with the full rectangle array, but the option is 110 | // available. 111 | // 112 | // The function returns 1 if all of the rectangles were successfully 113 | // packed and 0 otherwise. 114 | 115 | struct stbrp_rect 116 | { 117 | // reserved for your use: 118 | int id; 119 | 120 | // input: 121 | stbrp_coord w, h; 122 | 123 | // output: 124 | stbrp_coord x, y; 125 | int was_packed; // non-zero if valid packing 126 | 127 | }; // 16 bytes, nominally 128 | 129 | 130 | STBRP_DEF void stbrp_init_target (stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes); 131 | // Initialize a rectangle packer to: 132 | // pack a rectangle that is 'width' by 'height' in dimensions 133 | // using temporary storage provided by the array 'nodes', which is 'num_nodes' long 134 | // 135 | // You must call this function every time you start packing into a new target. 136 | // 137 | // There is no "shutdown" function. The 'nodes' memory must stay valid for 138 | // the following stbrp_pack_rects() call (or calls), but can be freed after 139 | // the call (or calls) finish. 140 | // 141 | // Note: to guarantee best results, either: 142 | // 1. make sure 'num_nodes' >= 'width' 143 | // or 2. call stbrp_allow_out_of_mem() defined below with 'allow_out_of_mem = 1' 144 | // 145 | // If you don't do either of the above things, widths will be quantized to multiples 146 | // of small integers to guarantee the algorithm doesn't run out of temporary storage. 147 | // 148 | // If you do #2, then the non-quantized algorithm will be used, but the algorithm 149 | // may run out of temporary storage and be unable to pack some rectangles. 150 | 151 | STBRP_DEF void stbrp_setup_allow_out_of_mem (stbrp_context *context, int allow_out_of_mem); 152 | // Optionally call this function after init but before doing any packing to 153 | // change the handling of the out-of-temp-memory scenario, described above. 154 | // If you call init again, this will be reset to the default (false). 155 | 156 | 157 | STBRP_DEF void stbrp_setup_heuristic (stbrp_context *context, int heuristic); 158 | // Optionally select which packing heuristic the library should use. Different 159 | // heuristics will produce better/worse results for different data sets. 160 | // If you call init again, this will be reset to the default. 161 | 162 | enum 163 | { 164 | STBRP_HEURISTIC_Skyline_default=0, 165 | STBRP_HEURISTIC_Skyline_BL_sortHeight = STBRP_HEURISTIC_Skyline_default, 166 | STBRP_HEURISTIC_Skyline_BF_sortHeight 167 | }; 168 | 169 | 170 | ////////////////////////////////////////////////////////////////////////////// 171 | // 172 | // the details of the following structures don't matter to you, but they must 173 | // be visible so you can handle the memory allocations for them 174 | 175 | struct stbrp_node 176 | { 177 | stbrp_coord x,y; 178 | stbrp_node *next; 179 | }; 180 | 181 | struct stbrp_context 182 | { 183 | int width; 184 | int height; 185 | int align; 186 | int init_mode; 187 | int heuristic; 188 | int num_nodes; 189 | stbrp_node *active_head; 190 | stbrp_node *free_head; 191 | stbrp_node extra[2]; // we allocate two extra nodes so optimal user-node-count is 'width' not 'width+2' 192 | }; 193 | 194 | #ifdef __cplusplus 195 | } 196 | #endif 197 | 198 | #endif 199 | 200 | ////////////////////////////////////////////////////////////////////////////// 201 | // 202 | // IMPLEMENTATION SECTION 203 | // 204 | 205 | #ifdef STB_RECT_PACK_IMPLEMENTATION 206 | #ifndef STBRP_SORT 207 | #include 208 | #define STBRP_SORT qsort 209 | #endif 210 | 211 | #ifndef STBRP_ASSERT 212 | #include 213 | #define STBRP_ASSERT assert 214 | #endif 215 | 216 | // [DEAR IMGUI] Added STBRP__CDECL 217 | #ifdef _MSC_VER 218 | #define STBRP__NOTUSED(v) (void)(v) 219 | #define STBRP__CDECL __cdecl 220 | #else 221 | #define STBRP__NOTUSED(v) (void)sizeof(v) 222 | #define STBRP__CDECL 223 | #endif 224 | 225 | enum 226 | { 227 | STBRP__INIT_skyline = 1 228 | }; 229 | 230 | STBRP_DEF void stbrp_setup_heuristic(stbrp_context *context, int heuristic) 231 | { 232 | switch (context->init_mode) { 233 | case STBRP__INIT_skyline: 234 | STBRP_ASSERT(heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight || heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight); 235 | context->heuristic = heuristic; 236 | break; 237 | default: 238 | STBRP_ASSERT(0); 239 | } 240 | } 241 | 242 | STBRP_DEF void stbrp_setup_allow_out_of_mem(stbrp_context *context, int allow_out_of_mem) 243 | { 244 | if (allow_out_of_mem) 245 | // if it's ok to run out of memory, then don't bother aligning them; 246 | // this gives better packing, but may fail due to OOM (even though 247 | // the rectangles easily fit). @TODO a smarter approach would be to only 248 | // quantize once we've hit OOM, then we could get rid of this parameter. 249 | context->align = 1; 250 | else { 251 | // if it's not ok to run out of memory, then quantize the widths 252 | // so that num_nodes is always enough nodes. 253 | // 254 | // I.e. num_nodes * align >= width 255 | // align >= width / num_nodes 256 | // align = ceil(width/num_nodes) 257 | 258 | context->align = (context->width + context->num_nodes-1) / context->num_nodes; 259 | } 260 | } 261 | 262 | STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes) 263 | { 264 | int i; 265 | #ifndef STBRP_LARGE_RECTS 266 | STBRP_ASSERT(width <= 0xffff && height <= 0xffff); 267 | #endif 268 | 269 | for (i=0; i < num_nodes-1; ++i) 270 | nodes[i].next = &nodes[i+1]; 271 | nodes[i].next = NULL; 272 | context->init_mode = STBRP__INIT_skyline; 273 | context->heuristic = STBRP_HEURISTIC_Skyline_default; 274 | context->free_head = &nodes[0]; 275 | context->active_head = &context->extra[0]; 276 | context->width = width; 277 | context->height = height; 278 | context->num_nodes = num_nodes; 279 | stbrp_setup_allow_out_of_mem(context, 0); 280 | 281 | // node 0 is the full width, node 1 is the sentinel (lets us not store width explicitly) 282 | context->extra[0].x = 0; 283 | context->extra[0].y = 0; 284 | context->extra[0].next = &context->extra[1]; 285 | context->extra[1].x = (stbrp_coord) width; 286 | #ifdef STBRP_LARGE_RECTS 287 | context->extra[1].y = (1<<30); 288 | #else 289 | context->extra[1].y = 65535; 290 | #endif 291 | context->extra[1].next = NULL; 292 | } 293 | 294 | // find minimum y position if it starts at x1 295 | static int stbrp__skyline_find_min_y(stbrp_context *c, stbrp_node *first, int x0, int width, int *pwaste) 296 | { 297 | stbrp_node *node = first; 298 | int x1 = x0 + width; 299 | int min_y, visited_width, waste_area; 300 | 301 | STBRP__NOTUSED(c); 302 | 303 | STBRP_ASSERT(first->x <= x0); 304 | 305 | #if 0 306 | // skip in case we're past the node 307 | while (node->next->x <= x0) 308 | ++node; 309 | #else 310 | STBRP_ASSERT(node->next->x > x0); // we ended up handling this in the caller for efficiency 311 | #endif 312 | 313 | STBRP_ASSERT(node->x <= x0); 314 | 315 | min_y = 0; 316 | waste_area = 0; 317 | visited_width = 0; 318 | while (node->x < x1) { 319 | if (node->y > min_y) { 320 | // raise min_y higher. 321 | // we've accounted for all waste up to min_y, 322 | // but we'll now add more waste for everything we've visted 323 | waste_area += visited_width * (node->y - min_y); 324 | min_y = node->y; 325 | // the first time through, visited_width might be reduced 326 | if (node->x < x0) 327 | visited_width += node->next->x - x0; 328 | else 329 | visited_width += node->next->x - node->x; 330 | } else { 331 | // add waste area 332 | int under_width = node->next->x - node->x; 333 | if (under_width + visited_width > width) 334 | under_width = width - visited_width; 335 | waste_area += under_width * (min_y - node->y); 336 | visited_width += under_width; 337 | } 338 | node = node->next; 339 | } 340 | 341 | *pwaste = waste_area; 342 | return min_y; 343 | } 344 | 345 | typedef struct 346 | { 347 | int x,y; 348 | stbrp_node **prev_link; 349 | } stbrp__findresult; 350 | 351 | static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int width, int height) 352 | { 353 | int best_waste = (1<<30), best_x, best_y = (1 << 30); 354 | stbrp__findresult fr; 355 | stbrp_node **prev, *node, *tail, **best = NULL; 356 | 357 | // align to multiple of c->align 358 | width = (width + c->align - 1); 359 | width -= width % c->align; 360 | STBRP_ASSERT(width % c->align == 0); 361 | 362 | // if it can't possibly fit, bail immediately 363 | if (width > c->width || height > c->height) { 364 | fr.prev_link = NULL; 365 | fr.x = fr.y = 0; 366 | return fr; 367 | } 368 | 369 | node = c->active_head; 370 | prev = &c->active_head; 371 | while (node->x + width <= c->width) { 372 | int y,waste; 373 | y = stbrp__skyline_find_min_y(c, node, node->x, width, &waste); 374 | if (c->heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight) { // actually just want to test BL 375 | // bottom left 376 | if (y < best_y) { 377 | best_y = y; 378 | best = prev; 379 | } 380 | } else { 381 | // best-fit 382 | if (y + height <= c->height) { 383 | // can only use it if it first vertically 384 | if (y < best_y || (y == best_y && waste < best_waste)) { 385 | best_y = y; 386 | best_waste = waste; 387 | best = prev; 388 | } 389 | } 390 | } 391 | prev = &node->next; 392 | node = node->next; 393 | } 394 | 395 | best_x = (best == NULL) ? 0 : (*best)->x; 396 | 397 | // if doing best-fit (BF), we also have to try aligning right edge to each node position 398 | // 399 | // e.g, if fitting 400 | // 401 | // ____________________ 402 | // |____________________| 403 | // 404 | // into 405 | // 406 | // | | 407 | // | ____________| 408 | // |____________| 409 | // 410 | // then right-aligned reduces waste, but bottom-left BL is always chooses left-aligned 411 | // 412 | // This makes BF take about 2x the time 413 | 414 | if (c->heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight) { 415 | tail = c->active_head; 416 | node = c->active_head; 417 | prev = &c->active_head; 418 | // find first node that's admissible 419 | while (tail->x < width) 420 | tail = tail->next; 421 | while (tail) { 422 | int xpos = tail->x - width; 423 | int y,waste; 424 | STBRP_ASSERT(xpos >= 0); 425 | // find the left position that matches this 426 | while (node->next->x <= xpos) { 427 | prev = &node->next; 428 | node = node->next; 429 | } 430 | STBRP_ASSERT(node->next->x > xpos && node->x <= xpos); 431 | y = stbrp__skyline_find_min_y(c, node, xpos, width, &waste); 432 | if (y + height <= c->height) { 433 | if (y <= best_y) { 434 | if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) { 435 | best_x = xpos; 436 | STBRP_ASSERT(y <= best_y); 437 | best_y = y; 438 | best_waste = waste; 439 | best = prev; 440 | } 441 | } 442 | } 443 | tail = tail->next; 444 | } 445 | } 446 | 447 | fr.prev_link = best; 448 | fr.x = best_x; 449 | fr.y = best_y; 450 | return fr; 451 | } 452 | 453 | static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, int width, int height) 454 | { 455 | // find best position according to heuristic 456 | stbrp__findresult res = stbrp__skyline_find_best_pos(context, width, height); 457 | stbrp_node *node, *cur; 458 | 459 | // bail if: 460 | // 1. it failed 461 | // 2. the best node doesn't fit (we don't always check this) 462 | // 3. we're out of memory 463 | if (res.prev_link == NULL || res.y + height > context->height || context->free_head == NULL) { 464 | res.prev_link = NULL; 465 | return res; 466 | } 467 | 468 | // on success, create new node 469 | node = context->free_head; 470 | node->x = (stbrp_coord) res.x; 471 | node->y = (stbrp_coord) (res.y + height); 472 | 473 | context->free_head = node->next; 474 | 475 | // insert the new node into the right starting point, and 476 | // let 'cur' point to the remaining nodes needing to be 477 | // stiched back in 478 | 479 | cur = *res.prev_link; 480 | if (cur->x < res.x) { 481 | // preserve the existing one, so start testing with the next one 482 | stbrp_node *next = cur->next; 483 | cur->next = node; 484 | cur = next; 485 | } else { 486 | *res.prev_link = node; 487 | } 488 | 489 | // from here, traverse cur and free the nodes, until we get to one 490 | // that shouldn't be freed 491 | while (cur->next && cur->next->x <= res.x + width) { 492 | stbrp_node *next = cur->next; 493 | // move the current node to the free list 494 | cur->next = context->free_head; 495 | context->free_head = cur; 496 | cur = next; 497 | } 498 | 499 | // stitch the list back in 500 | node->next = cur; 501 | 502 | if (cur->x < res.x + width) 503 | cur->x = (stbrp_coord) (res.x + width); 504 | 505 | #ifdef _DEBUG 506 | cur = context->active_head; 507 | while (cur->x < context->width) { 508 | STBRP_ASSERT(cur->x < cur->next->x); 509 | cur = cur->next; 510 | } 511 | STBRP_ASSERT(cur->next == NULL); 512 | 513 | { 514 | int count=0; 515 | cur = context->active_head; 516 | while (cur) { 517 | cur = cur->next; 518 | ++count; 519 | } 520 | cur = context->free_head; 521 | while (cur) { 522 | cur = cur->next; 523 | ++count; 524 | } 525 | STBRP_ASSERT(count == context->num_nodes+2); 526 | } 527 | #endif 528 | 529 | return res; 530 | } 531 | 532 | // [DEAR IMGUI] Added STBRP__CDECL 533 | static int STBRP__CDECL rect_height_compare(const void *a, const void *b) 534 | { 535 | const stbrp_rect *p = (const stbrp_rect *) a; 536 | const stbrp_rect *q = (const stbrp_rect *) b; 537 | if (p->h > q->h) 538 | return -1; 539 | if (p->h < q->h) 540 | return 1; 541 | return (p->w > q->w) ? -1 : (p->w < q->w); 542 | } 543 | 544 | // [DEAR IMGUI] Added STBRP__CDECL 545 | static int STBRP__CDECL rect_original_order(const void *a, const void *b) 546 | { 547 | const stbrp_rect *p = (const stbrp_rect *) a; 548 | const stbrp_rect *q = (const stbrp_rect *) b; 549 | return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed); 550 | } 551 | 552 | #ifdef STBRP_LARGE_RECTS 553 | #define STBRP__MAXVAL 0xffffffff 554 | #else 555 | #define STBRP__MAXVAL 0xffff 556 | #endif 557 | 558 | STBRP_DEF int stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects) 559 | { 560 | int i, all_rects_packed = 1; 561 | 562 | // we use the 'was_packed' field internally to allow sorting/unsorting 563 | for (i=0; i < num_rects; ++i) { 564 | rects[i].was_packed = i; 565 | } 566 | 567 | // sort according to heuristic 568 | STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_height_compare); 569 | 570 | for (i=0; i < num_rects; ++i) { 571 | if (rects[i].w == 0 || rects[i].h == 0) { 572 | rects[i].x = rects[i].y = 0; // empty rect needs no space 573 | } else { 574 | stbrp__findresult fr = stbrp__skyline_pack_rectangle(context, rects[i].w, rects[i].h); 575 | if (fr.prev_link) { 576 | rects[i].x = (stbrp_coord) fr.x; 577 | rects[i].y = (stbrp_coord) fr.y; 578 | } else { 579 | rects[i].x = rects[i].y = STBRP__MAXVAL; 580 | } 581 | } 582 | } 583 | 584 | // unsort 585 | STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_original_order); 586 | 587 | // set was_packed flags and all_rects_packed status 588 | for (i=0; i < num_rects; ++i) { 589 | rects[i].was_packed = !(rects[i].x == STBRP__MAXVAL && rects[i].y == STBRP__MAXVAL); 590 | if (!rects[i].was_packed) 591 | all_rects_packed = 0; 592 | } 593 | 594 | // return the all_rects_packed status 595 | return all_rects_packed; 596 | } 597 | #endif 598 | 599 | /* 600 | ------------------------------------------------------------------------------ 601 | This software is available under 2 licenses -- choose whichever you prefer. 602 | ------------------------------------------------------------------------------ 603 | ALTERNATIVE A - MIT License 604 | Copyright (c) 2017 Sean Barrett 605 | Permission is hereby granted, free of charge, to any person obtaining a copy of 606 | this software and associated documentation files (the "Software"), to deal in 607 | the Software without restriction, including without limitation the rights to 608 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 609 | of the Software, and to permit persons to whom the Software is furnished to do 610 | so, subject to the following conditions: 611 | The above copyright notice and this permission notice shall be included in all 612 | copies or substantial portions of the Software. 613 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 614 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 615 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 616 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 617 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 618 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 619 | SOFTWARE. 620 | ------------------------------------------------------------------------------ 621 | ALTERNATIVE B - Public Domain (www.unlicense.org) 622 | This is free and unencumbered software released into the public domain. 623 | Anyone is free to copy, modify, publish, use, compile, sell, or distribute this 624 | software, either in source code form or as a compiled binary, for any purpose, 625 | commercial or non-commercial, and by any means. 626 | In jurisdictions that recognize copyright laws, the author or authors of this 627 | software dedicate any and all copyright interest in the software to the public 628 | domain. We make this dedication for the benefit of the public at large and to 629 | the detriment of our heirs and successors. We intend this dedication to be an 630 | overt act of relinquishment in perpetuity of all present and future rights to 631 | this software under copyright law. 632 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 633 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 634 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 635 | AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 636 | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 637 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 638 | ------------------------------------------------------------------------------ 639 | */ 640 | -------------------------------------------------------------------------------- /workingMenu16.4/KittyMemory/imstb_textedit.h: -------------------------------------------------------------------------------- 1 | // [DEAR IMGUI] 2 | // This is a slightly modified version of stb_textedit.h 1.13. 3 | // Those changes would need to be pushed into nothings/stb: 4 | // - Fix in stb_textedit_discard_redo (see https://github.com/nothings/stb/issues/321) 5 | // Grep for [DEAR IMGUI] to find the changes. 6 | 7 | // stb_textedit.h - v1.13 - public domain - Sean Barrett 8 | // Development of this library was sponsored by RAD Game Tools 9 | // 10 | // This C header file implements the guts of a multi-line text-editing 11 | // widget; you implement display, word-wrapping, and low-level string 12 | // insertion/deletion, and stb_textedit will map user inputs into 13 | // insertions & deletions, plus updates to the cursor position, 14 | // selection state, and undo state. 15 | // 16 | // It is intended for use in games and other systems that need to build 17 | // their own custom widgets and which do not have heavy text-editing 18 | // requirements (this library is not recommended for use for editing large 19 | // texts, as its performance does not scale and it has limited undo). 20 | // 21 | // Non-trivial behaviors are modelled after Windows text controls. 22 | // 23 | // 24 | // LICENSE 25 | // 26 | // See end of file for license information. 27 | // 28 | // 29 | // DEPENDENCIES 30 | // 31 | // Uses the C runtime function 'memmove', which you can override 32 | // by defining STB_TEXTEDIT_memmove before the implementation. 33 | // Uses no other functions. Performs no runtime allocations. 34 | // 35 | // 36 | // VERSION HISTORY 37 | // 38 | // 1.13 (2019-02-07) fix bug in undo size management 39 | // 1.12 (2018-01-29) user can change STB_TEXTEDIT_KEYTYPE, fix redo to avoid crash 40 | // 1.11 (2017-03-03) fix HOME on last line, dragging off single-line textfield 41 | // 1.10 (2016-10-25) supress warnings about casting away const with -Wcast-qual 42 | // 1.9 (2016-08-27) customizable move-by-word 43 | // 1.8 (2016-04-02) better keyboard handling when mouse button is down 44 | // 1.7 (2015-09-13) change y range handling in case baseline is non-0 45 | // 1.6 (2015-04-15) allow STB_TEXTEDIT_memmove 46 | // 1.5 (2014-09-10) add support for secondary keys for OS X 47 | // 1.4 (2014-08-17) fix signed/unsigned warnings 48 | // 1.3 (2014-06-19) fix mouse clicking to round to nearest char boundary 49 | // 1.2 (2014-05-27) fix some RAD types that had crept into the new code 50 | // 1.1 (2013-12-15) move-by-word (requires STB_TEXTEDIT_IS_SPACE ) 51 | // 1.0 (2012-07-26) improve documentation, initial public release 52 | // 0.3 (2012-02-24) bugfixes, single-line mode; insert mode 53 | // 0.2 (2011-11-28) fixes to undo/redo 54 | // 0.1 (2010-07-08) initial version 55 | // 56 | // ADDITIONAL CONTRIBUTORS 57 | // 58 | // Ulf Winklemann: move-by-word in 1.1 59 | // Fabian Giesen: secondary key inputs in 1.5 60 | // Martins Mozeiko: STB_TEXTEDIT_memmove in 1.6 61 | // 62 | // Bugfixes: 63 | // Scott Graham 64 | // Daniel Keller 65 | // Omar Cornut 66 | // Dan Thompson 67 | // 68 | // USAGE 69 | // 70 | // This file behaves differently depending on what symbols you define 71 | // before including it. 72 | // 73 | // 74 | // Header-file mode: 75 | // 76 | // If you do not define STB_TEXTEDIT_IMPLEMENTATION before including this, 77 | // it will operate in "header file" mode. In this mode, it declares a 78 | // single public symbol, STB_TexteditState, which encapsulates the current 79 | // state of a text widget (except for the string, which you will store 80 | // separately). 81 | // 82 | // To compile in this mode, you must define STB_TEXTEDIT_CHARTYPE to a 83 | // primitive type that defines a single character (e.g. char, wchar_t, etc). 84 | // 85 | // To save space or increase undo-ability, you can optionally define the 86 | // following things that are used by the undo system: 87 | // 88 | // STB_TEXTEDIT_POSITIONTYPE small int type encoding a valid cursor position 89 | // STB_TEXTEDIT_UNDOSTATECOUNT the number of undo states to allow 90 | // STB_TEXTEDIT_UNDOCHARCOUNT the number of characters to store in the undo buffer 91 | // 92 | // If you don't define these, they are set to permissive types and 93 | // moderate sizes. The undo system does no memory allocations, so 94 | // it grows STB_TexteditState by the worst-case storage which is (in bytes): 95 | // 96 | // [4 + 3 * sizeof(STB_TEXTEDIT_POSITIONTYPE)] * STB_TEXTEDIT_UNDOSTATE_COUNT 97 | // + sizeof(STB_TEXTEDIT_CHARTYPE) * STB_TEXTEDIT_UNDOCHAR_COUNT 98 | // 99 | // 100 | // Implementation mode: 101 | // 102 | // If you define STB_TEXTEDIT_IMPLEMENTATION before including this, it 103 | // will compile the implementation of the text edit widget, depending 104 | // on a large number of symbols which must be defined before the include. 105 | // 106 | // The implementation is defined only as static functions. You will then 107 | // need to provide your own APIs in the same file which will access the 108 | // static functions. 109 | // 110 | // The basic concept is that you provide a "string" object which 111 | // behaves like an array of characters. stb_textedit uses indices to 112 | // refer to positions in the string, implicitly representing positions 113 | // in the displayed textedit. This is true for both plain text and 114 | // rich text; even with rich text stb_truetype interacts with your 115 | // code as if there was an array of all the displayed characters. 116 | // 117 | // Symbols that must be the same in header-file and implementation mode: 118 | // 119 | // STB_TEXTEDIT_CHARTYPE the character type 120 | // STB_TEXTEDIT_POSITIONTYPE small type that is a valid cursor position 121 | // STB_TEXTEDIT_UNDOSTATECOUNT the number of undo states to allow 122 | // STB_TEXTEDIT_UNDOCHARCOUNT the number of characters to store in the undo buffer 123 | // 124 | // Symbols you must define for implementation mode: 125 | // 126 | // STB_TEXTEDIT_STRING the type of object representing a string being edited, 127 | // typically this is a wrapper object with other data you need 128 | // 129 | // STB_TEXTEDIT_STRINGLEN(obj) the length of the string (ideally O(1)) 130 | // STB_TEXTEDIT_LAYOUTROW(&r,obj,n) returns the results of laying out a line of characters 131 | // starting from character #n (see discussion below) 132 | // STB_TEXTEDIT_GETWIDTH(obj,n,i) returns the pixel delta from the xpos of the i'th character 133 | // to the xpos of the i+1'th char for a line of characters 134 | // starting at character #n (i.e. accounts for kerning 135 | // with previous char) 136 | // STB_TEXTEDIT_KEYTOTEXT(k) maps a keyboard input to an insertable character 137 | // (return type is int, -1 means not valid to insert) 138 | // STB_TEXTEDIT_GETCHAR(obj,i) returns the i'th character of obj, 0-based 139 | // STB_TEXTEDIT_NEWLINE the character returned by _GETCHAR() we recognize 140 | // as manually wordwrapping for end-of-line positioning 141 | // 142 | // STB_TEXTEDIT_DELETECHARS(obj,i,n) delete n characters starting at i 143 | // STB_TEXTEDIT_INSERTCHARS(obj,i,c*,n) insert n characters at i (pointed to by STB_TEXTEDIT_CHARTYPE*) 144 | // 145 | // STB_TEXTEDIT_K_SHIFT a power of two that is or'd in to a keyboard input to represent the shift key 146 | // 147 | // STB_TEXTEDIT_K_LEFT keyboard input to move cursor left 148 | // STB_TEXTEDIT_K_RIGHT keyboard input to move cursor right 149 | // STB_TEXTEDIT_K_UP keyboard input to move cursor up 150 | // STB_TEXTEDIT_K_DOWN keyboard input to move cursor down 151 | // STB_TEXTEDIT_K_PGUP keyboard input to move cursor up a page 152 | // STB_TEXTEDIT_K_PGDOWN keyboard input to move cursor down a page 153 | // STB_TEXTEDIT_K_LINESTART keyboard input to move cursor to start of line // e.g. HOME 154 | // STB_TEXTEDIT_K_LINEEND keyboard input to move cursor to end of line // e.g. END 155 | // STB_TEXTEDIT_K_TEXTSTART keyboard input to move cursor to start of text // e.g. ctrl-HOME 156 | // STB_TEXTEDIT_K_TEXTEND keyboard input to move cursor to end of text // e.g. ctrl-END 157 | // STB_TEXTEDIT_K_DELETE keyboard input to delete selection or character under cursor 158 | // STB_TEXTEDIT_K_BACKSPACE keyboard input to delete selection or character left of cursor 159 | // STB_TEXTEDIT_K_UNDO keyboard input to perform undo 160 | // STB_TEXTEDIT_K_REDO keyboard input to perform redo 161 | // 162 | // Optional: 163 | // STB_TEXTEDIT_K_INSERT keyboard input to toggle insert mode 164 | // STB_TEXTEDIT_IS_SPACE(ch) true if character is whitespace (e.g. 'isspace'), 165 | // required for default WORDLEFT/WORDRIGHT handlers 166 | // STB_TEXTEDIT_MOVEWORDLEFT(obj,i) custom handler for WORDLEFT, returns index to move cursor to 167 | // STB_TEXTEDIT_MOVEWORDRIGHT(obj,i) custom handler for WORDRIGHT, returns index to move cursor to 168 | // STB_TEXTEDIT_K_WORDLEFT keyboard input to move cursor left one word // e.g. ctrl-LEFT 169 | // STB_TEXTEDIT_K_WORDRIGHT keyboard input to move cursor right one word // e.g. ctrl-RIGHT 170 | // STB_TEXTEDIT_K_LINESTART2 secondary keyboard input to move cursor to start of line 171 | // STB_TEXTEDIT_K_LINEEND2 secondary keyboard input to move cursor to end of line 172 | // STB_TEXTEDIT_K_TEXTSTART2 secondary keyboard input to move cursor to start of text 173 | // STB_TEXTEDIT_K_TEXTEND2 secondary keyboard input to move cursor to end of text 174 | // 175 | // Keyboard input must be encoded as a single integer value; e.g. a character code 176 | // and some bitflags that represent shift states. to simplify the interface, SHIFT must 177 | // be a bitflag, so we can test the shifted state of cursor movements to allow selection, 178 | // i.e. (STB_TEXTEDIT_K_RIGHT|STB_TEXTEDIT_K_SHIFT) should be shifted right-arrow. 179 | // 180 | // You can encode other things, such as CONTROL or ALT, in additional bits, and 181 | // then test for their presence in e.g. STB_TEXTEDIT_K_WORDLEFT. For example, 182 | // my Windows implementations add an additional CONTROL bit, and an additional KEYDOWN 183 | // bit. Then all of the STB_TEXTEDIT_K_ values bitwise-or in the KEYDOWN bit, 184 | // and I pass both WM_KEYDOWN and WM_CHAR events to the "key" function in the 185 | // API below. The control keys will only match WM_KEYDOWN events because of the 186 | // keydown bit I add, and STB_TEXTEDIT_KEYTOTEXT only tests for the KEYDOWN 187 | // bit so it only decodes WM_CHAR events. 188 | // 189 | // STB_TEXTEDIT_LAYOUTROW returns information about the shape of one displayed 190 | // row of characters assuming they start on the i'th character--the width and 191 | // the height and the number of characters consumed. This allows this library 192 | // to traverse the entire layout incrementally. You need to compute word-wrapping 193 | // here. 194 | // 195 | // Each textfield keeps its own insert mode state, which is not how normal 196 | // applications work. To keep an app-wide insert mode, update/copy the 197 | // "insert_mode" field of STB_TexteditState before/after calling API functions. 198 | // 199 | // API 200 | // 201 | // void stb_textedit_initialize_state(STB_TexteditState *state, int is_single_line) 202 | // 203 | // void stb_textedit_click(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y) 204 | // void stb_textedit_drag(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y) 205 | // int stb_textedit_cut(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) 206 | // int stb_textedit_paste(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE *text, int len) 207 | // void stb_textedit_key(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXEDIT_KEYTYPE key) 208 | // 209 | // Each of these functions potentially updates the string and updates the 210 | // state. 211 | // 212 | // initialize_state: 213 | // set the textedit state to a known good default state when initially 214 | // constructing the textedit. 215 | // 216 | // click: 217 | // call this with the mouse x,y on a mouse down; it will update the cursor 218 | // and reset the selection start/end to the cursor point. the x,y must 219 | // be relative to the text widget, with (0,0) being the top left. 220 | // 221 | // drag: 222 | // call this with the mouse x,y on a mouse drag/up; it will update the 223 | // cursor and the selection end point 224 | // 225 | // cut: 226 | // call this to delete the current selection; returns true if there was 227 | // one. you should FIRST copy the current selection to the system paste buffer. 228 | // (To copy, just copy the current selection out of the string yourself.) 229 | // 230 | // paste: 231 | // call this to paste text at the current cursor point or over the current 232 | // selection if there is one. 233 | // 234 | // key: 235 | // call this for keyboard inputs sent to the textfield. you can use it 236 | // for "key down" events or for "translated" key events. if you need to 237 | // do both (as in Win32), or distinguish Unicode characters from control 238 | // inputs, set a high bit to distinguish the two; then you can define the 239 | // various definitions like STB_TEXTEDIT_K_LEFT have the is-key-event bit 240 | // set, and make STB_TEXTEDIT_KEYTOCHAR check that the is-key-event bit is 241 | // clear. STB_TEXTEDIT_KEYTYPE defaults to int, but you can #define it to 242 | // anything other type you wante before including. 243 | // 244 | // 245 | // When rendering, you can read the cursor position and selection state from 246 | // the STB_TexteditState. 247 | // 248 | // 249 | // Notes: 250 | // 251 | // This is designed to be usable in IMGUI, so it allows for the possibility of 252 | // running in an IMGUI that has NOT cached the multi-line layout. For this 253 | // reason, it provides an interface that is compatible with computing the 254 | // layout incrementally--we try to make sure we make as few passes through 255 | // as possible. (For example, to locate the mouse pointer in the text, we 256 | // could define functions that return the X and Y positions of characters 257 | // and binary search Y and then X, but if we're doing dynamic layout this 258 | // will run the layout algorithm many times, so instead we manually search 259 | // forward in one pass. Similar logic applies to e.g. up-arrow and 260 | // down-arrow movement.) 261 | // 262 | // If it's run in a widget that *has* cached the layout, then this is less 263 | // efficient, but it's not horrible on modern computers. But you wouldn't 264 | // want to edit million-line files with it. 265 | 266 | 267 | //////////////////////////////////////////////////////////////////////////// 268 | //////////////////////////////////////////////////////////////////////////// 269 | //// 270 | //// Header-file mode 271 | //// 272 | //// 273 | 274 | #ifndef INCLUDE_STB_TEXTEDIT_H 275 | #define INCLUDE_STB_TEXTEDIT_H 276 | 277 | //////////////////////////////////////////////////////////////////////// 278 | // 279 | // STB_TexteditState 280 | // 281 | // Definition of STB_TexteditState which you should store 282 | // per-textfield; it includes cursor position, selection state, 283 | // and undo state. 284 | // 285 | 286 | #ifndef STB_TEXTEDIT_UNDOSTATECOUNT 287 | #define STB_TEXTEDIT_UNDOSTATECOUNT 99 288 | #endif 289 | #ifndef STB_TEXTEDIT_UNDOCHARCOUNT 290 | #define STB_TEXTEDIT_UNDOCHARCOUNT 999 291 | #endif 292 | #ifndef STB_TEXTEDIT_CHARTYPE 293 | #define STB_TEXTEDIT_CHARTYPE int 294 | #endif 295 | #ifndef STB_TEXTEDIT_POSITIONTYPE 296 | #define STB_TEXTEDIT_POSITIONTYPE int 297 | #endif 298 | 299 | typedef struct 300 | { 301 | // private data 302 | STB_TEXTEDIT_POSITIONTYPE where; 303 | STB_TEXTEDIT_POSITIONTYPE insert_length; 304 | STB_TEXTEDIT_POSITIONTYPE delete_length; 305 | int char_storage; 306 | } StbUndoRecord; 307 | 308 | typedef struct 309 | { 310 | // private data 311 | StbUndoRecord undo_rec [STB_TEXTEDIT_UNDOSTATECOUNT]; 312 | STB_TEXTEDIT_CHARTYPE undo_char[STB_TEXTEDIT_UNDOCHARCOUNT]; 313 | short undo_point, redo_point; 314 | int undo_char_point, redo_char_point; 315 | } StbUndoState; 316 | 317 | typedef struct 318 | { 319 | ///////////////////// 320 | // 321 | // public data 322 | // 323 | 324 | int cursor; 325 | // position of the text cursor within the string 326 | 327 | int select_start; // selection start point 328 | int select_end; 329 | // selection start and end point in characters; if equal, no selection. 330 | // note that start may be less than or greater than end (e.g. when 331 | // dragging the mouse, start is where the initial click was, and you 332 | // can drag in either direction) 333 | 334 | unsigned char insert_mode; 335 | // each textfield keeps its own insert mode state. to keep an app-wide 336 | // insert mode, copy this value in/out of the app state 337 | 338 | int row_count_per_page; 339 | // page size in number of row. 340 | // this value MUST be set to >0 for pageup or pagedown in multilines documents. 341 | 342 | ///////////////////// 343 | // 344 | // private data 345 | // 346 | unsigned char cursor_at_end_of_line; // not implemented yet 347 | unsigned char initialized; 348 | unsigned char has_preferred_x; 349 | unsigned char single_line; 350 | unsigned char padding1, padding2, padding3; 351 | float preferred_x; // this determines where the cursor up/down tries to seek to along x 352 | StbUndoState undostate; 353 | } STB_TexteditState; 354 | 355 | 356 | //////////////////////////////////////////////////////////////////////// 357 | // 358 | // StbTexteditRow 359 | // 360 | // Result of layout query, used by stb_textedit to determine where 361 | // the text in each row is. 362 | 363 | // result of layout query 364 | typedef struct 365 | { 366 | float x0,x1; // starting x location, end x location (allows for align=right, etc) 367 | float baseline_y_delta; // position of baseline relative to previous row's baseline 368 | float ymin,ymax; // height of row above and below baseline 369 | int num_chars; 370 | } StbTexteditRow; 371 | #endif //INCLUDE_STB_TEXTEDIT_H 372 | 373 | 374 | //////////////////////////////////////////////////////////////////////////// 375 | //////////////////////////////////////////////////////////////////////////// 376 | //// 377 | //// Implementation mode 378 | //// 379 | //// 380 | 381 | 382 | // implementation isn't include-guarded, since it might have indirectly 383 | // included just the "header" portion 384 | #ifdef STB_TEXTEDIT_IMPLEMENTATION 385 | 386 | #ifndef STB_TEXTEDIT_memmove 387 | //#include 388 | #define STB_TEXTEDIT_memmove memmove 389 | #endif 390 | 391 | 392 | ///////////////////////////////////////////////////////////////////////////// 393 | // 394 | // Mouse input handling 395 | // 396 | 397 | // traverse the layout to locate the nearest character to a display position 398 | static int stb_text_locate_coord(STB_TEXTEDIT_STRING *str, float x, float y) 399 | { 400 | StbTexteditRow r; 401 | int n = STB_TEXTEDIT_STRINGLEN(str); 402 | float base_y = 0, prev_x; 403 | int i=0, k; 404 | 405 | r.x0 = r.x1 = 0; 406 | r.ymin = r.ymax = 0; 407 | r.num_chars = 0; 408 | 409 | // search rows to find one that straddles 'y' 410 | while (i < n) { 411 | STB_TEXTEDIT_LAYOUTROW(&r, str, i); 412 | if (r.num_chars <= 0) 413 | return n; 414 | 415 | if (i==0 && y < base_y + r.ymin) 416 | return 0; 417 | 418 | if (y < base_y + r.ymax) 419 | break; 420 | 421 | i += r.num_chars; 422 | base_y += r.baseline_y_delta; 423 | } 424 | 425 | // below all text, return 'after' last character 426 | if (i >= n) 427 | return n; 428 | 429 | // check if it's before the beginning of the line 430 | if (x < r.x0) 431 | return i; 432 | 433 | // check if it's before the end of the line 434 | if (x < r.x1) { 435 | // search characters in row for one that straddles 'x' 436 | prev_x = r.x0; 437 | for (k=0; k < r.num_chars; ++k) { 438 | float w = STB_TEXTEDIT_GETWIDTH(str, i, k); 439 | if (x < prev_x+w) { 440 | if (x < prev_x+w/2) 441 | return k+i; 442 | else 443 | return k+i+1; 444 | } 445 | prev_x += w; 446 | } 447 | // shouldn't happen, but if it does, fall through to end-of-line case 448 | } 449 | 450 | // if the last character is a newline, return that. otherwise return 'after' the last character 451 | if (STB_TEXTEDIT_GETCHAR(str, i+r.num_chars-1) == STB_TEXTEDIT_NEWLINE) 452 | return i+r.num_chars-1; 453 | else 454 | return i+r.num_chars; 455 | } 456 | 457 | // API click: on mouse down, move the cursor to the clicked location, and reset the selection 458 | static void stb_textedit_click(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y) 459 | { 460 | // In single-line mode, just always make y = 0. This lets the drag keep working if the mouse 461 | // goes off the top or bottom of the text 462 | if( state->single_line ) 463 | { 464 | StbTexteditRow r; 465 | STB_TEXTEDIT_LAYOUTROW(&r, str, 0); 466 | y = r.ymin; 467 | } 468 | 469 | state->cursor = stb_text_locate_coord(str, x, y); 470 | state->select_start = state->cursor; 471 | state->select_end = state->cursor; 472 | state->has_preferred_x = 0; 473 | } 474 | 475 | // API drag: on mouse drag, move the cursor and selection endpoint to the clicked location 476 | static void stb_textedit_drag(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y) 477 | { 478 | int p = 0; 479 | 480 | // In single-line mode, just always make y = 0. This lets the drag keep working if the mouse 481 | // goes off the top or bottom of the text 482 | if( state->single_line ) 483 | { 484 | StbTexteditRow r; 485 | STB_TEXTEDIT_LAYOUTROW(&r, str, 0); 486 | y = r.ymin; 487 | } 488 | 489 | if (state->select_start == state->select_end) 490 | state->select_start = state->cursor; 491 | 492 | p = stb_text_locate_coord(str, x, y); 493 | state->cursor = state->select_end = p; 494 | } 495 | 496 | ///////////////////////////////////////////////////////////////////////////// 497 | // 498 | // Keyboard input handling 499 | // 500 | 501 | // forward declarations 502 | static void stb_text_undo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state); 503 | static void stb_text_redo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state); 504 | static void stb_text_makeundo_delete(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int length); 505 | static void stb_text_makeundo_insert(STB_TexteditState *state, int where, int length); 506 | static void stb_text_makeundo_replace(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int old_length, int new_length); 507 | 508 | typedef struct 509 | { 510 | float x,y; // position of n'th character 511 | float height; // height of line 512 | int first_char, length; // first char of row, and length 513 | int prev_first; // first char of previous row 514 | } StbFindState; 515 | 516 | // find the x/y location of a character, and remember info about the previous row in 517 | // case we get a move-up event (for page up, we'll have to rescan) 518 | static void stb_textedit_find_charpos(StbFindState *find, STB_TEXTEDIT_STRING *str, int n, int single_line) 519 | { 520 | StbTexteditRow r; 521 | int prev_start = 0; 522 | int z = STB_TEXTEDIT_STRINGLEN(str); 523 | int i=0, first; 524 | 525 | if (n == z) { 526 | // if it's at the end, then find the last line -- simpler than trying to 527 | // explicitly handle this case in the regular code 528 | if (single_line) { 529 | STB_TEXTEDIT_LAYOUTROW(&r, str, 0); 530 | find->y = 0; 531 | find->first_char = 0; 532 | find->length = z; 533 | find->height = r.ymax - r.ymin; 534 | find->x = r.x1; 535 | } else { 536 | find->y = 0; 537 | find->x = 0; 538 | find->height = 1; 539 | while (i < z) { 540 | STB_TEXTEDIT_LAYOUTROW(&r, str, i); 541 | prev_start = i; 542 | i += r.num_chars; 543 | } 544 | find->first_char = i; 545 | find->length = 0; 546 | find->prev_first = prev_start; 547 | } 548 | return; 549 | } 550 | 551 | // search rows to find the one that straddles character n 552 | find->y = 0; 553 | 554 | for(;;) { 555 | STB_TEXTEDIT_LAYOUTROW(&r, str, i); 556 | if (n < i + r.num_chars) 557 | break; 558 | prev_start = i; 559 | i += r.num_chars; 560 | find->y += r.baseline_y_delta; 561 | } 562 | 563 | find->first_char = first = i; 564 | find->length = r.num_chars; 565 | find->height = r.ymax - r.ymin; 566 | find->prev_first = prev_start; 567 | 568 | // now scan to find xpos 569 | find->x = r.x0; 570 | for (i=0; first+i < n; ++i) 571 | find->x += STB_TEXTEDIT_GETWIDTH(str, first, i); 572 | } 573 | 574 | #define STB_TEXT_HAS_SELECTION(s) ((s)->select_start != (s)->select_end) 575 | 576 | // make the selection/cursor state valid if client altered the string 577 | static void stb_textedit_clamp(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) 578 | { 579 | int n = STB_TEXTEDIT_STRINGLEN(str); 580 | if (STB_TEXT_HAS_SELECTION(state)) { 581 | if (state->select_start > n) state->select_start = n; 582 | if (state->select_end > n) state->select_end = n; 583 | // if clamping forced them to be equal, move the cursor to match 584 | if (state->select_start == state->select_end) 585 | state->cursor = state->select_start; 586 | } 587 | if (state->cursor > n) state->cursor = n; 588 | } 589 | 590 | // delete characters while updating undo 591 | static void stb_textedit_delete(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int len) 592 | { 593 | stb_text_makeundo_delete(str, state, where, len); 594 | STB_TEXTEDIT_DELETECHARS(str, where, len); 595 | state->has_preferred_x = 0; 596 | } 597 | 598 | // delete the section 599 | static void stb_textedit_delete_selection(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) 600 | { 601 | stb_textedit_clamp(str, state); 602 | if (STB_TEXT_HAS_SELECTION(state)) { 603 | if (state->select_start < state->select_end) { 604 | stb_textedit_delete(str, state, state->select_start, state->select_end - state->select_start); 605 | state->select_end = state->cursor = state->select_start; 606 | } else { 607 | stb_textedit_delete(str, state, state->select_end, state->select_start - state->select_end); 608 | state->select_start = state->cursor = state->select_end; 609 | } 610 | state->has_preferred_x = 0; 611 | } 612 | } 613 | 614 | // canoncialize the selection so start <= end 615 | static void stb_textedit_sortselection(STB_TexteditState *state) 616 | { 617 | if (state->select_end < state->select_start) { 618 | int temp = state->select_end; 619 | state->select_end = state->select_start; 620 | state->select_start = temp; 621 | } 622 | } 623 | 624 | // move cursor to first character of selection 625 | static void stb_textedit_move_to_first(STB_TexteditState *state) 626 | { 627 | if (STB_TEXT_HAS_SELECTION(state)) { 628 | stb_textedit_sortselection(state); 629 | state->cursor = state->select_start; 630 | state->select_end = state->select_start; 631 | state->has_preferred_x = 0; 632 | } 633 | } 634 | 635 | // move cursor to last character of selection 636 | static void stb_textedit_move_to_last(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) 637 | { 638 | if (STB_TEXT_HAS_SELECTION(state)) { 639 | stb_textedit_sortselection(state); 640 | stb_textedit_clamp(str, state); 641 | state->cursor = state->select_end; 642 | state->select_start = state->select_end; 643 | state->has_preferred_x = 0; 644 | } 645 | } 646 | 647 | #ifdef STB_TEXTEDIT_IS_SPACE 648 | static int is_word_boundary( STB_TEXTEDIT_STRING *str, int idx ) 649 | { 650 | return idx > 0 ? (STB_TEXTEDIT_IS_SPACE( STB_TEXTEDIT_GETCHAR(str,idx-1) ) && !STB_TEXTEDIT_IS_SPACE( STB_TEXTEDIT_GETCHAR(str, idx) ) ) : 1; 651 | } 652 | 653 | #ifndef STB_TEXTEDIT_MOVEWORDLEFT 654 | static int stb_textedit_move_to_word_previous( STB_TEXTEDIT_STRING *str, int c ) 655 | { 656 | --c; // always move at least one character 657 | while( c >= 0 && !is_word_boundary( str, c ) ) 658 | --c; 659 | 660 | if( c < 0 ) 661 | c = 0; 662 | 663 | return c; 664 | } 665 | #define STB_TEXTEDIT_MOVEWORDLEFT stb_textedit_move_to_word_previous 666 | #endif 667 | 668 | #ifndef STB_TEXTEDIT_MOVEWORDRIGHT 669 | static int stb_textedit_move_to_word_next( STB_TEXTEDIT_STRING *str, int c ) 670 | { 671 | const int len = STB_TEXTEDIT_STRINGLEN(str); 672 | ++c; // always move at least one character 673 | while( c < len && !is_word_boundary( str, c ) ) 674 | ++c; 675 | 676 | if( c > len ) 677 | c = len; 678 | 679 | return c; 680 | } 681 | #define STB_TEXTEDIT_MOVEWORDRIGHT stb_textedit_move_to_word_next 682 | #endif 683 | 684 | #endif 685 | 686 | // update selection and cursor to match each other 687 | static void stb_textedit_prep_selection_at_cursor(STB_TexteditState *state) 688 | { 689 | if (!STB_TEXT_HAS_SELECTION(state)) 690 | state->select_start = state->select_end = state->cursor; 691 | else 692 | state->cursor = state->select_end; 693 | } 694 | 695 | // API cut: delete selection 696 | static int stb_textedit_cut(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) 697 | { 698 | if (STB_TEXT_HAS_SELECTION(state)) { 699 | stb_textedit_delete_selection(str,state); // implicitly clamps 700 | state->has_preferred_x = 0; 701 | return 1; 702 | } 703 | return 0; 704 | } 705 | 706 | // API paste: replace existing selection with passed-in text 707 | static int stb_textedit_paste_internal(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE *text, int len) 708 | { 709 | // if there's a selection, the paste should delete it 710 | stb_textedit_clamp(str, state); 711 | stb_textedit_delete_selection(str,state); 712 | // try to insert the characters 713 | if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, text, len)) { 714 | stb_text_makeundo_insert(state, state->cursor, len); 715 | state->cursor += len; 716 | state->has_preferred_x = 0; 717 | return 1; 718 | } 719 | // remove the undo since we didn't actually insert the characters 720 | if (state->undostate.undo_point) 721 | --state->undostate.undo_point; 722 | return 0; 723 | } 724 | 725 | #ifndef STB_TEXTEDIT_KEYTYPE 726 | #define STB_TEXTEDIT_KEYTYPE int 727 | #endif 728 | 729 | // API key: process a keyboard input 730 | static void stb_textedit_key(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_KEYTYPE key) 731 | { 732 | retry: 733 | switch (key) { 734 | default: { 735 | int c = STB_TEXTEDIT_KEYTOTEXT(key); 736 | if (c > 0) { 737 | STB_TEXTEDIT_CHARTYPE ch = (STB_TEXTEDIT_CHARTYPE) c; 738 | 739 | // can't add newline in single-line mode 740 | if (c == '\n' && state->single_line) 741 | break; 742 | 743 | if (state->insert_mode && !STB_TEXT_HAS_SELECTION(state) && state->cursor < STB_TEXTEDIT_STRINGLEN(str)) { 744 | stb_text_makeundo_replace(str, state, state->cursor, 1, 1); 745 | STB_TEXTEDIT_DELETECHARS(str, state->cursor, 1); 746 | if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, &ch, 1)) { 747 | ++state->cursor; 748 | state->has_preferred_x = 0; 749 | } 750 | } else { 751 | stb_textedit_delete_selection(str,state); // implicitly clamps 752 | if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, &ch, 1)) { 753 | stb_text_makeundo_insert(state, state->cursor, 1); 754 | ++state->cursor; 755 | state->has_preferred_x = 0; 756 | } 757 | } 758 | } 759 | break; 760 | } 761 | 762 | #ifdef STB_TEXTEDIT_K_INSERT 763 | case STB_TEXTEDIT_K_INSERT: 764 | state->insert_mode = !state->insert_mode; 765 | break; 766 | #endif 767 | 768 | case STB_TEXTEDIT_K_UNDO: 769 | stb_text_undo(str, state); 770 | state->has_preferred_x = 0; 771 | break; 772 | 773 | case STB_TEXTEDIT_K_REDO: 774 | stb_text_redo(str, state); 775 | state->has_preferred_x = 0; 776 | break; 777 | 778 | case STB_TEXTEDIT_K_LEFT: 779 | // if currently there's a selection, move cursor to start of selection 780 | if (STB_TEXT_HAS_SELECTION(state)) 781 | stb_textedit_move_to_first(state); 782 | else 783 | if (state->cursor > 0) 784 | --state->cursor; 785 | state->has_preferred_x = 0; 786 | break; 787 | 788 | case STB_TEXTEDIT_K_RIGHT: 789 | // if currently there's a selection, move cursor to end of selection 790 | if (STB_TEXT_HAS_SELECTION(state)) 791 | stb_textedit_move_to_last(str, state); 792 | else 793 | ++state->cursor; 794 | stb_textedit_clamp(str, state); 795 | state->has_preferred_x = 0; 796 | break; 797 | 798 | case STB_TEXTEDIT_K_LEFT | STB_TEXTEDIT_K_SHIFT: 799 | stb_textedit_clamp(str, state); 800 | stb_textedit_prep_selection_at_cursor(state); 801 | // move selection left 802 | if (state->select_end > 0) 803 | --state->select_end; 804 | state->cursor = state->select_end; 805 | state->has_preferred_x = 0; 806 | break; 807 | 808 | #ifdef STB_TEXTEDIT_MOVEWORDLEFT 809 | case STB_TEXTEDIT_K_WORDLEFT: 810 | if (STB_TEXT_HAS_SELECTION(state)) 811 | stb_textedit_move_to_first(state); 812 | else { 813 | state->cursor = STB_TEXTEDIT_MOVEWORDLEFT(str, state->cursor); 814 | stb_textedit_clamp( str, state ); 815 | } 816 | break; 817 | 818 | case STB_TEXTEDIT_K_WORDLEFT | STB_TEXTEDIT_K_SHIFT: 819 | if( !STB_TEXT_HAS_SELECTION( state ) ) 820 | stb_textedit_prep_selection_at_cursor(state); 821 | 822 | state->cursor = STB_TEXTEDIT_MOVEWORDLEFT(str, state->cursor); 823 | state->select_end = state->cursor; 824 | 825 | stb_textedit_clamp( str, state ); 826 | break; 827 | #endif 828 | 829 | #ifdef STB_TEXTEDIT_MOVEWORDRIGHT 830 | case STB_TEXTEDIT_K_WORDRIGHT: 831 | if (STB_TEXT_HAS_SELECTION(state)) 832 | stb_textedit_move_to_last(str, state); 833 | else { 834 | state->cursor = STB_TEXTEDIT_MOVEWORDRIGHT(str, state->cursor); 835 | stb_textedit_clamp( str, state ); 836 | } 837 | break; 838 | 839 | case STB_TEXTEDIT_K_WORDRIGHT | STB_TEXTEDIT_K_SHIFT: 840 | if( !STB_TEXT_HAS_SELECTION( state ) ) 841 | stb_textedit_prep_selection_at_cursor(state); 842 | 843 | state->cursor = STB_TEXTEDIT_MOVEWORDRIGHT(str, state->cursor); 844 | state->select_end = state->cursor; 845 | 846 | stb_textedit_clamp( str, state ); 847 | break; 848 | #endif 849 | 850 | case STB_TEXTEDIT_K_RIGHT | STB_TEXTEDIT_K_SHIFT: 851 | stb_textedit_prep_selection_at_cursor(state); 852 | // move selection right 853 | ++state->select_end; 854 | stb_textedit_clamp(str, state); 855 | state->cursor = state->select_end; 856 | state->has_preferred_x = 0; 857 | break; 858 | 859 | case STB_TEXTEDIT_K_DOWN: 860 | case STB_TEXTEDIT_K_DOWN | STB_TEXTEDIT_K_SHIFT: 861 | case STB_TEXTEDIT_K_PGDOWN: 862 | case STB_TEXTEDIT_K_PGDOWN | STB_TEXTEDIT_K_SHIFT: { 863 | StbFindState find; 864 | StbTexteditRow row; 865 | int i, j, sel = (key & STB_TEXTEDIT_K_SHIFT) != 0; 866 | int is_page = (key & ~STB_TEXTEDIT_K_SHIFT) == STB_TEXTEDIT_K_PGDOWN; 867 | int row_count = is_page ? state->row_count_per_page : 1; 868 | 869 | if (!is_page && state->single_line) { 870 | // on windows, up&down in single-line behave like left&right 871 | key = STB_TEXTEDIT_K_RIGHT | (key & STB_TEXTEDIT_K_SHIFT); 872 | goto retry; 873 | } 874 | 875 | if (sel) 876 | stb_textedit_prep_selection_at_cursor(state); 877 | else if (STB_TEXT_HAS_SELECTION(state)) 878 | stb_textedit_move_to_last(str, state); 879 | 880 | // compute current position of cursor point 881 | stb_textedit_clamp(str, state); 882 | stb_textedit_find_charpos(&find, str, state->cursor, state->single_line); 883 | 884 | for (j = 0; j < row_count; ++j) { 885 | float x, goal_x = state->has_preferred_x ? state->preferred_x : find.x; 886 | int start = find.first_char + find.length; 887 | 888 | if (find.length == 0) 889 | break; 890 | 891 | // [DEAR IMGUI] 892 | // going down while being on the last line shouldn't bring us to that line end 893 | if (STB_TEXTEDIT_GETCHAR(str, find.first_char + find.length - 1) != STB_TEXTEDIT_NEWLINE) 894 | break; 895 | 896 | // now find character position down a row 897 | state->cursor = start; 898 | STB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor); 899 | x = row.x0; 900 | for (i=0; i < row.num_chars; ++i) { 901 | float dx = STB_TEXTEDIT_GETWIDTH(str, start, i); 902 | #ifdef STB_TEXTEDIT_GETWIDTH_NEWLINE 903 | if (dx == STB_TEXTEDIT_GETWIDTH_NEWLINE) 904 | break; 905 | #endif 906 | x += dx; 907 | if (x > goal_x) 908 | break; 909 | ++state->cursor; 910 | } 911 | stb_textedit_clamp(str, state); 912 | 913 | state->has_preferred_x = 1; 914 | state->preferred_x = goal_x; 915 | 916 | if (sel) 917 | state->select_end = state->cursor; 918 | 919 | // go to next line 920 | find.first_char = find.first_char + find.length; 921 | find.length = row.num_chars; 922 | } 923 | break; 924 | } 925 | 926 | case STB_TEXTEDIT_K_UP: 927 | case STB_TEXTEDIT_K_UP | STB_TEXTEDIT_K_SHIFT: 928 | case STB_TEXTEDIT_K_PGUP: 929 | case STB_TEXTEDIT_K_PGUP | STB_TEXTEDIT_K_SHIFT: { 930 | StbFindState find; 931 | StbTexteditRow row; 932 | int i, j, prev_scan, sel = (key & STB_TEXTEDIT_K_SHIFT) != 0; 933 | int is_page = (key & ~STB_TEXTEDIT_K_SHIFT) == STB_TEXTEDIT_K_PGUP; 934 | int row_count = is_page ? state->row_count_per_page : 1; 935 | 936 | if (!is_page && state->single_line) { 937 | // on windows, up&down become left&right 938 | key = STB_TEXTEDIT_K_LEFT | (key & STB_TEXTEDIT_K_SHIFT); 939 | goto retry; 940 | } 941 | 942 | if (sel) 943 | stb_textedit_prep_selection_at_cursor(state); 944 | else if (STB_TEXT_HAS_SELECTION(state)) 945 | stb_textedit_move_to_first(state); 946 | 947 | // compute current position of cursor point 948 | stb_textedit_clamp(str, state); 949 | stb_textedit_find_charpos(&find, str, state->cursor, state->single_line); 950 | 951 | for (j = 0; j < row_count; ++j) { 952 | float x, goal_x = state->has_preferred_x ? state->preferred_x : find.x; 953 | 954 | // can only go up if there's a previous row 955 | if (find.prev_first == find.first_char) 956 | break; 957 | 958 | // now find character position up a row 959 | state->cursor = find.prev_first; 960 | STB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor); 961 | x = row.x0; 962 | for (i=0; i < row.num_chars; ++i) { 963 | float dx = STB_TEXTEDIT_GETWIDTH(str, find.prev_first, i); 964 | #ifdef STB_TEXTEDIT_GETWIDTH_NEWLINE 965 | if (dx == STB_TEXTEDIT_GETWIDTH_NEWLINE) 966 | break; 967 | #endif 968 | x += dx; 969 | if (x > goal_x) 970 | break; 971 | ++state->cursor; 972 | } 973 | stb_textedit_clamp(str, state); 974 | 975 | state->has_preferred_x = 1; 976 | state->preferred_x = goal_x; 977 | 978 | if (sel) 979 | state->select_end = state->cursor; 980 | 981 | // go to previous line 982 | // (we need to scan previous line the hard way. maybe we could expose this as a new API function?) 983 | prev_scan = find.prev_first > 0 ? find.prev_first - 1 : 0; 984 | while (prev_scan > 0 && STB_TEXTEDIT_GETCHAR(str, prev_scan - 1) != STB_TEXTEDIT_NEWLINE) 985 | --prev_scan; 986 | find.first_char = find.prev_first; 987 | find.prev_first = prev_scan; 988 | } 989 | break; 990 | } 991 | 992 | case STB_TEXTEDIT_K_DELETE: 993 | case STB_TEXTEDIT_K_DELETE | STB_TEXTEDIT_K_SHIFT: 994 | if (STB_TEXT_HAS_SELECTION(state)) 995 | stb_textedit_delete_selection(str, state); 996 | else { 997 | int n = STB_TEXTEDIT_STRINGLEN(str); 998 | if (state->cursor < n) 999 | stb_textedit_delete(str, state, state->cursor, 1); 1000 | } 1001 | state->has_preferred_x = 0; 1002 | break; 1003 | 1004 | case STB_TEXTEDIT_K_BACKSPACE: 1005 | case STB_TEXTEDIT_K_BACKSPACE | STB_TEXTEDIT_K_SHIFT: 1006 | if (STB_TEXT_HAS_SELECTION(state)) 1007 | stb_textedit_delete_selection(str, state); 1008 | else { 1009 | stb_textedit_clamp(str, state); 1010 | if (state->cursor > 0) { 1011 | stb_textedit_delete(str, state, state->cursor-1, 1); 1012 | --state->cursor; 1013 | } 1014 | } 1015 | state->has_preferred_x = 0; 1016 | break; 1017 | 1018 | #ifdef STB_TEXTEDIT_K_TEXTSTART2 1019 | case STB_TEXTEDIT_K_TEXTSTART2: 1020 | #endif 1021 | case STB_TEXTEDIT_K_TEXTSTART: 1022 | state->cursor = state->select_start = state->select_end = 0; 1023 | state->has_preferred_x = 0; 1024 | break; 1025 | 1026 | #ifdef STB_TEXTEDIT_K_TEXTEND2 1027 | case STB_TEXTEDIT_K_TEXTEND2: 1028 | #endif 1029 | case STB_TEXTEDIT_K_TEXTEND: 1030 | state->cursor = STB_TEXTEDIT_STRINGLEN(str); 1031 | state->select_start = state->select_end = 0; 1032 | state->has_preferred_x = 0; 1033 | break; 1034 | 1035 | #ifdef STB_TEXTEDIT_K_TEXTSTART2 1036 | case STB_TEXTEDIT_K_TEXTSTART2 | STB_TEXTEDIT_K_SHIFT: 1037 | #endif 1038 | case STB_TEXTEDIT_K_TEXTSTART | STB_TEXTEDIT_K_SHIFT: 1039 | stb_textedit_prep_selection_at_cursor(state); 1040 | state->cursor = state->select_end = 0; 1041 | state->has_preferred_x = 0; 1042 | break; 1043 | 1044 | #ifdef STB_TEXTEDIT_K_TEXTEND2 1045 | case STB_TEXTEDIT_K_TEXTEND2 | STB_TEXTEDIT_K_SHIFT: 1046 | #endif 1047 | case STB_TEXTEDIT_K_TEXTEND | STB_TEXTEDIT_K_SHIFT: 1048 | stb_textedit_prep_selection_at_cursor(state); 1049 | state->cursor = state->select_end = STB_TEXTEDIT_STRINGLEN(str); 1050 | state->has_preferred_x = 0; 1051 | break; 1052 | 1053 | 1054 | #ifdef STB_TEXTEDIT_K_LINESTART2 1055 | case STB_TEXTEDIT_K_LINESTART2: 1056 | #endif 1057 | case STB_TEXTEDIT_K_LINESTART: 1058 | stb_textedit_clamp(str, state); 1059 | stb_textedit_move_to_first(state); 1060 | if (state->single_line) 1061 | state->cursor = 0; 1062 | else while (state->cursor > 0 && STB_TEXTEDIT_GETCHAR(str, state->cursor-1) != STB_TEXTEDIT_NEWLINE) 1063 | --state->cursor; 1064 | state->has_preferred_x = 0; 1065 | break; 1066 | 1067 | #ifdef STB_TEXTEDIT_K_LINEEND2 1068 | case STB_TEXTEDIT_K_LINEEND2: 1069 | #endif 1070 | case STB_TEXTEDIT_K_LINEEND: { 1071 | int n = STB_TEXTEDIT_STRINGLEN(str); 1072 | stb_textedit_clamp(str, state); 1073 | stb_textedit_move_to_first(state); 1074 | if (state->single_line) 1075 | state->cursor = n; 1076 | else while (state->cursor < n && STB_TEXTEDIT_GETCHAR(str, state->cursor) != STB_TEXTEDIT_NEWLINE) 1077 | ++state->cursor; 1078 | state->has_preferred_x = 0; 1079 | break; 1080 | } 1081 | 1082 | #ifdef STB_TEXTEDIT_K_LINESTART2 1083 | case STB_TEXTEDIT_K_LINESTART2 | STB_TEXTEDIT_K_SHIFT: 1084 | #endif 1085 | case STB_TEXTEDIT_K_LINESTART | STB_TEXTEDIT_K_SHIFT: 1086 | stb_textedit_clamp(str, state); 1087 | stb_textedit_prep_selection_at_cursor(state); 1088 | if (state->single_line) 1089 | state->cursor = 0; 1090 | else while (state->cursor > 0 && STB_TEXTEDIT_GETCHAR(str, state->cursor-1) != STB_TEXTEDIT_NEWLINE) 1091 | --state->cursor; 1092 | state->select_end = state->cursor; 1093 | state->has_preferred_x = 0; 1094 | break; 1095 | 1096 | #ifdef STB_TEXTEDIT_K_LINEEND2 1097 | case STB_TEXTEDIT_K_LINEEND2 | STB_TEXTEDIT_K_SHIFT: 1098 | #endif 1099 | case STB_TEXTEDIT_K_LINEEND | STB_TEXTEDIT_K_SHIFT: { 1100 | int n = STB_TEXTEDIT_STRINGLEN(str); 1101 | stb_textedit_clamp(str, state); 1102 | stb_textedit_prep_selection_at_cursor(state); 1103 | if (state->single_line) 1104 | state->cursor = n; 1105 | else while (state->cursor < n && STB_TEXTEDIT_GETCHAR(str, state->cursor) != STB_TEXTEDIT_NEWLINE) 1106 | ++state->cursor; 1107 | state->select_end = state->cursor; 1108 | state->has_preferred_x = 0; 1109 | break; 1110 | } 1111 | } 1112 | } 1113 | 1114 | ///////////////////////////////////////////////////////////////////////////// 1115 | // 1116 | // Undo processing 1117 | // 1118 | // @OPTIMIZE: the undo/redo buffer should be circular 1119 | 1120 | static void stb_textedit_flush_redo(StbUndoState *state) 1121 | { 1122 | state->redo_point = STB_TEXTEDIT_UNDOSTATECOUNT; 1123 | state->redo_char_point = STB_TEXTEDIT_UNDOCHARCOUNT; 1124 | } 1125 | 1126 | // discard the oldest entry in the undo list 1127 | static void stb_textedit_discard_undo(StbUndoState *state) 1128 | { 1129 | if (state->undo_point > 0) { 1130 | // if the 0th undo state has characters, clean those up 1131 | if (state->undo_rec[0].char_storage >= 0) { 1132 | int n = state->undo_rec[0].insert_length, i; 1133 | // delete n characters from all other records 1134 | state->undo_char_point -= n; 1135 | STB_TEXTEDIT_memmove(state->undo_char, state->undo_char + n, (size_t) (state->undo_char_point*sizeof(STB_TEXTEDIT_CHARTYPE))); 1136 | for (i=0; i < state->undo_point; ++i) 1137 | if (state->undo_rec[i].char_storage >= 0) 1138 | state->undo_rec[i].char_storage -= n; // @OPTIMIZE: get rid of char_storage and infer it 1139 | } 1140 | --state->undo_point; 1141 | STB_TEXTEDIT_memmove(state->undo_rec, state->undo_rec+1, (size_t) (state->undo_point*sizeof(state->undo_rec[0]))); 1142 | } 1143 | } 1144 | 1145 | // discard the oldest entry in the redo list--it's bad if this 1146 | // ever happens, but because undo & redo have to store the actual 1147 | // characters in different cases, the redo character buffer can 1148 | // fill up even though the undo buffer didn't 1149 | static void stb_textedit_discard_redo(StbUndoState *state) 1150 | { 1151 | int k = STB_TEXTEDIT_UNDOSTATECOUNT-1; 1152 | 1153 | if (state->redo_point <= k) { 1154 | // if the k'th undo state has characters, clean those up 1155 | if (state->undo_rec[k].char_storage >= 0) { 1156 | int n = state->undo_rec[k].insert_length, i; 1157 | // move the remaining redo character data to the end of the buffer 1158 | state->redo_char_point += n; 1159 | STB_TEXTEDIT_memmove(state->undo_char + state->redo_char_point, state->undo_char + state->redo_char_point-n, (size_t) ((STB_TEXTEDIT_UNDOCHARCOUNT - state->redo_char_point)*sizeof(STB_TEXTEDIT_CHARTYPE))); 1160 | // adjust the position of all the other records to account for above memmove 1161 | for (i=state->redo_point; i < k; ++i) 1162 | if (state->undo_rec[i].char_storage >= 0) 1163 | state->undo_rec[i].char_storage += n; 1164 | } 1165 | // now move all the redo records towards the end of the buffer; the first one is at 'redo_point' 1166 | // [DEAR IMGUI] 1167 | size_t move_size = (size_t)((STB_TEXTEDIT_UNDOSTATECOUNT - state->redo_point - 1) * sizeof(state->undo_rec[0])); 1168 | const char* buf_begin = (char*)state->undo_rec; (void)buf_begin; 1169 | const char* buf_end = (char*)state->undo_rec + sizeof(state->undo_rec); (void)buf_end; 1170 | IM_ASSERT(((char*)(state->undo_rec + state->redo_point)) >= buf_begin); 1171 | IM_ASSERT(((char*)(state->undo_rec + state->redo_point + 1) + move_size) <= buf_end); 1172 | STB_TEXTEDIT_memmove(state->undo_rec + state->redo_point+1, state->undo_rec + state->redo_point, move_size); 1173 | 1174 | // now move redo_point to point to the new one 1175 | ++state->redo_point; 1176 | } 1177 | } 1178 | 1179 | static StbUndoRecord *stb_text_create_undo_record(StbUndoState *state, int numchars) 1180 | { 1181 | // any time we create a new undo record, we discard redo 1182 | stb_textedit_flush_redo(state); 1183 | 1184 | // if we have no free records, we have to make room, by sliding the 1185 | // existing records down 1186 | if (state->undo_point == STB_TEXTEDIT_UNDOSTATECOUNT) 1187 | stb_textedit_discard_undo(state); 1188 | 1189 | // if the characters to store won't possibly fit in the buffer, we can't undo 1190 | if (numchars > STB_TEXTEDIT_UNDOCHARCOUNT) { 1191 | state->undo_point = 0; 1192 | state->undo_char_point = 0; 1193 | return NULL; 1194 | } 1195 | 1196 | // if we don't have enough free characters in the buffer, we have to make room 1197 | while (state->undo_char_point + numchars > STB_TEXTEDIT_UNDOCHARCOUNT) 1198 | stb_textedit_discard_undo(state); 1199 | 1200 | return &state->undo_rec[state->undo_point++]; 1201 | } 1202 | 1203 | static STB_TEXTEDIT_CHARTYPE *stb_text_createundo(StbUndoState *state, int pos, int insert_len, int delete_len) 1204 | { 1205 | StbUndoRecord *r = stb_text_create_undo_record(state, insert_len); 1206 | if (r == NULL) 1207 | return NULL; 1208 | 1209 | r->where = pos; 1210 | r->insert_length = (STB_TEXTEDIT_POSITIONTYPE) insert_len; 1211 | r->delete_length = (STB_TEXTEDIT_POSITIONTYPE) delete_len; 1212 | 1213 | if (insert_len == 0) { 1214 | r->char_storage = -1; 1215 | return NULL; 1216 | } else { 1217 | r->char_storage = state->undo_char_point; 1218 | state->undo_char_point += insert_len; 1219 | return &state->undo_char[r->char_storage]; 1220 | } 1221 | } 1222 | 1223 | static void stb_text_undo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) 1224 | { 1225 | StbUndoState *s = &state->undostate; 1226 | StbUndoRecord u, *r; 1227 | if (s->undo_point == 0) 1228 | return; 1229 | 1230 | // we need to do two things: apply the undo record, and create a redo record 1231 | u = s->undo_rec[s->undo_point-1]; 1232 | r = &s->undo_rec[s->redo_point-1]; 1233 | r->char_storage = -1; 1234 | 1235 | r->insert_length = u.delete_length; 1236 | r->delete_length = u.insert_length; 1237 | r->where = u.where; 1238 | 1239 | if (u.delete_length) { 1240 | // if the undo record says to delete characters, then the redo record will 1241 | // need to re-insert the characters that get deleted, so we need to store 1242 | // them. 1243 | 1244 | // there are three cases: 1245 | // there's enough room to store the characters 1246 | // characters stored for *redoing* don't leave room for redo 1247 | // characters stored for *undoing* don't leave room for redo 1248 | // if the last is true, we have to bail 1249 | 1250 | if (s->undo_char_point + u.delete_length >= STB_TEXTEDIT_UNDOCHARCOUNT) { 1251 | // the undo records take up too much character space; there's no space to store the redo characters 1252 | r->insert_length = 0; 1253 | } else { 1254 | int i; 1255 | 1256 | // there's definitely room to store the characters eventually 1257 | while (s->undo_char_point + u.delete_length > s->redo_char_point) { 1258 | // should never happen: 1259 | if (s->redo_point == STB_TEXTEDIT_UNDOSTATECOUNT) 1260 | return; 1261 | // there's currently not enough room, so discard a redo record 1262 | stb_textedit_discard_redo(s); 1263 | } 1264 | r = &s->undo_rec[s->redo_point-1]; 1265 | 1266 | r->char_storage = s->redo_char_point - u.delete_length; 1267 | s->redo_char_point = s->redo_char_point - u.delete_length; 1268 | 1269 | // now save the characters 1270 | for (i=0; i < u.delete_length; ++i) 1271 | s->undo_char[r->char_storage + i] = STB_TEXTEDIT_GETCHAR(str, u.where + i); 1272 | } 1273 | 1274 | // now we can carry out the deletion 1275 | STB_TEXTEDIT_DELETECHARS(str, u.where, u.delete_length); 1276 | } 1277 | 1278 | // check type of recorded action: 1279 | if (u.insert_length) { 1280 | // easy case: was a deletion, so we need to insert n characters 1281 | STB_TEXTEDIT_INSERTCHARS(str, u.where, &s->undo_char[u.char_storage], u.insert_length); 1282 | s->undo_char_point -= u.insert_length; 1283 | } 1284 | 1285 | state->cursor = u.where + u.insert_length; 1286 | 1287 | s->undo_point--; 1288 | s->redo_point--; 1289 | } 1290 | 1291 | static void stb_text_redo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) 1292 | { 1293 | StbUndoState *s = &state->undostate; 1294 | StbUndoRecord *u, r; 1295 | if (s->redo_point == STB_TEXTEDIT_UNDOSTATECOUNT) 1296 | return; 1297 | 1298 | // we need to do two things: apply the redo record, and create an undo record 1299 | u = &s->undo_rec[s->undo_point]; 1300 | r = s->undo_rec[s->redo_point]; 1301 | 1302 | // we KNOW there must be room for the undo record, because the redo record 1303 | // was derived from an undo record 1304 | 1305 | u->delete_length = r.insert_length; 1306 | u->insert_length = r.delete_length; 1307 | u->where = r.where; 1308 | u->char_storage = -1; 1309 | 1310 | if (r.delete_length) { 1311 | // the redo record requires us to delete characters, so the undo record 1312 | // needs to store the characters 1313 | 1314 | if (s->undo_char_point + u->insert_length > s->redo_char_point) { 1315 | u->insert_length = 0; 1316 | u->delete_length = 0; 1317 | } else { 1318 | int i; 1319 | u->char_storage = s->undo_char_point; 1320 | s->undo_char_point = s->undo_char_point + u->insert_length; 1321 | 1322 | // now save the characters 1323 | for (i=0; i < u->insert_length; ++i) 1324 | s->undo_char[u->char_storage + i] = STB_TEXTEDIT_GETCHAR(str, u->where + i); 1325 | } 1326 | 1327 | STB_TEXTEDIT_DELETECHARS(str, r.where, r.delete_length); 1328 | } 1329 | 1330 | if (r.insert_length) { 1331 | // easy case: need to insert n characters 1332 | STB_TEXTEDIT_INSERTCHARS(str, r.where, &s->undo_char[r.char_storage], r.insert_length); 1333 | s->redo_char_point += r.insert_length; 1334 | } 1335 | 1336 | state->cursor = r.where + r.insert_length; 1337 | 1338 | s->undo_point++; 1339 | s->redo_point++; 1340 | } 1341 | 1342 | static void stb_text_makeundo_insert(STB_TexteditState *state, int where, int length) 1343 | { 1344 | stb_text_createundo(&state->undostate, where, 0, length); 1345 | } 1346 | 1347 | static void stb_text_makeundo_delete(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int length) 1348 | { 1349 | int i; 1350 | STB_TEXTEDIT_CHARTYPE *p = stb_text_createundo(&state->undostate, where, length, 0); 1351 | if (p) { 1352 | for (i=0; i < length; ++i) 1353 | p[i] = STB_TEXTEDIT_GETCHAR(str, where+i); 1354 | } 1355 | } 1356 | 1357 | static void stb_text_makeundo_replace(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int old_length, int new_length) 1358 | { 1359 | int i; 1360 | STB_TEXTEDIT_CHARTYPE *p = stb_text_createundo(&state->undostate, where, old_length, new_length); 1361 | if (p) { 1362 | for (i=0; i < old_length; ++i) 1363 | p[i] = STB_TEXTEDIT_GETCHAR(str, where+i); 1364 | } 1365 | } 1366 | 1367 | // reset the state to default 1368 | static void stb_textedit_clear_state(STB_TexteditState *state, int is_single_line) 1369 | { 1370 | state->undostate.undo_point = 0; 1371 | state->undostate.undo_char_point = 0; 1372 | state->undostate.redo_point = STB_TEXTEDIT_UNDOSTATECOUNT; 1373 | state->undostate.redo_char_point = STB_TEXTEDIT_UNDOCHARCOUNT; 1374 | state->select_end = state->select_start = 0; 1375 | state->cursor = 0; 1376 | state->has_preferred_x = 0; 1377 | state->preferred_x = 0; 1378 | state->cursor_at_end_of_line = 0; 1379 | state->initialized = 1; 1380 | state->single_line = (unsigned char) is_single_line; 1381 | state->insert_mode = 0; 1382 | state->row_count_per_page = 0; 1383 | } 1384 | 1385 | // API initialize 1386 | static void stb_textedit_initialize_state(STB_TexteditState *state, int is_single_line) 1387 | { 1388 | stb_textedit_clear_state(state, is_single_line); 1389 | } 1390 | 1391 | #if defined(__GNUC__) || defined(__clang__) 1392 | #pragma GCC diagnostic push 1393 | #pragma GCC diagnostic ignored "-Wcast-qual" 1394 | #endif 1395 | 1396 | static int stb_textedit_paste(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE const *ctext, int len) 1397 | { 1398 | return stb_textedit_paste_internal(str, state, (STB_TEXTEDIT_CHARTYPE *) ctext, len); 1399 | } 1400 | 1401 | #if defined(__GNUC__) || defined(__clang__) 1402 | #pragma GCC diagnostic pop 1403 | #endif 1404 | 1405 | #endif//STB_TEXTEDIT_IMPLEMENTATION 1406 | 1407 | /* 1408 | ------------------------------------------------------------------------------ 1409 | This software is available under 2 licenses -- choose whichever you prefer. 1410 | ------------------------------------------------------------------------------ 1411 | ALTERNATIVE A - MIT License 1412 | Copyright (c) 2017 Sean Barrett 1413 | Permission is hereby granted, free of charge, to any person obtaining a copy of 1414 | this software and associated documentation files (the "Software"), to deal in 1415 | the Software without restriction, including without limitation the rights to 1416 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 1417 | of the Software, and to permit persons to whom the Software is furnished to do 1418 | so, subject to the following conditions: 1419 | The above copyright notice and this permission notice shall be included in all 1420 | copies or substantial portions of the Software. 1421 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1422 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1423 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 1424 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 1425 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 1426 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 1427 | SOFTWARE. 1428 | ------------------------------------------------------------------------------ 1429 | ALTERNATIVE B - Public Domain (www.unlicense.org) 1430 | This is free and unencumbered software released into the public domain. 1431 | Anyone is free to copy, modify, publish, use, compile, sell, or distribute this 1432 | software, either in source code form or as a compiled binary, for any purpose, 1433 | commercial or non-commercial, and by any means. 1434 | In jurisdictions that recognize copyright laws, the author or authors of this 1435 | software dedicate any and all copyright interest in the software to the public 1436 | domain. We make this dedication for the benefit of the public at large and to 1437 | the detriment of our heirs and successors. We intend this dedication to be an 1438 | overt act of relinquishment in perpetuity of all present and future rights to 1439 | this software under copyright law. 1440 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1441 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1442 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 1443 | AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 1444 | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 1445 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 1446 | ------------------------------------------------------------------------------ 1447 | */ 1448 | -------------------------------------------------------------------------------- /workingMenu16.4/KittyMemory/initializer_list: -------------------------------------------------------------------------------- 1 | // std::initializer_list support -*- C++ -*- 2 | // Copyright (C) 2008-2017 Free Software Foundation, Inc. 3 | // 4 | // This file is part of GCC. 5 | // 6 | // GCC is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3, or (at your option) 9 | // any later version. 10 | // 11 | // GCC is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // Under Section 7 of GPL version 3, you are granted additional 17 | // permissions described in the GCC Runtime Library Exception, version 18 | // 3.1, as published by the Free Software Foundation. 19 | // You should have received a copy of the GNU General Public License and 20 | // a copy of the GCC Runtime Library Exception along with this program; 21 | // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 22 | // . 23 | /** @file initializer_list 24 | * This is a Standard C++ Library header. 25 | */ 26 | #ifndef _INITIALIZER_LIST 27 | #define _INITIALIZER_LIST 28 | #pragma GCC system_header 29 | #if __cplusplus < 201103L 30 | # include 31 | #else // C++0x 32 | #pragma GCC visibility push(default) 33 | #include 34 | namespace std 35 | { 36 | /// initializer_list 37 | template 38 | class initializer_list 39 | { 40 | public: 41 | typedef _E value_type; 42 | typedef const _E& reference; 43 | typedef const _E& const_reference; 44 | typedef size_t size_type; 45 | typedef const _E* iterator; 46 | typedef const _E* const_iterator; 47 | private: 48 | iterator _M_array; 49 | size_type _M_len; 50 | // The compiler can call a private constructor. 51 | constexpr initializer_list(const_iterator __a, size_type __l) 52 | : _M_array(__a), _M_len(__l) { } 53 | public: 54 | constexpr initializer_list() noexcept 55 | : _M_array(0), _M_len(0) { } 56 | // Number of elements. 57 | constexpr size_type 58 | size() const noexcept { return _M_len; } 59 | // First element. 60 | constexpr const_iterator 61 | begin() const noexcept { return _M_array; } 62 | // One past the last element. 63 | constexpr const_iterator 64 | end() const noexcept { return begin() + size(); } 65 | }; 66 | /** 67 | * @brief Return an iterator pointing to the first element of 68 | * the initializer_list. 69 | * @param __ils Initializer list. 70 | */ 71 | template 72 | constexpr const _Tp* 73 | begin(initializer_list<_Tp> __ils) noexcept 74 | { return __ils.begin(); } 75 | /** 76 | * @brief Return an iterator pointing to one past the last element 77 | * of the initializer_list. 78 | * @param __ils Initializer list. 79 | */ 80 | template 81 | constexpr const _Tp* 82 | end(initializer_list<_Tp> __ils) noexcept 83 | { return __ils.end(); } 84 | } 85 | #pragma GCC visibility pop 86 | #endif // C++11 87 | #endif // _INITIALIZER_LIST -------------------------------------------------------------------------------- /workingMenu16.4/KittyMemory/writeData.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // writeData.cpp 3 | // 4 | // 5 | // Created by MJ (Ruit) on 4/13/19. 6 | // 7 | 8 | 9 | /* 10 | This is an alternative for the old writeData that was made by HackJack & Razzile 11 | */ 12 | 13 | #include "writeData.hpp" 14 | 15 | 16 | 17 | bool writeData8(uint64_t offset, uint8_t data) 18 | { 19 | const size_t sz = sizeof(uint8_t); 20 | 21 | // pass NULL as fileName for base executable 22 | return MemoryPatch(NULL, /* relative address */ offset, /* patch bytes */ &data, /* patch bytes length */ sz).Modify(); 23 | } 24 | 25 | bool writeData16(uint64_t offset, uint16_t data) 26 | { 27 | const size_t sz = sizeof(uint16_t); 28 | SwapData(data); 29 | 30 | // pass NULL as fileName for base executable 31 | return MemoryPatch(NULL, /* relative address */ offset, /* patch bytes */ &data, /* patch bytes length */ sz).Modify(); 32 | } 33 | 34 | bool writeData32(uint64_t offset, uint32_t data) 35 | { 36 | const size_t sz = sizeof(uint32_t); 37 | SwapData(data); 38 | 39 | // pass NULL as fileName for base executable 40 | return MemoryPatch(NULL, /* relative address */ offset, /* patch bytes */ &data, /* patch bytes length */ sz).Modify(); 41 | } 42 | 43 | 44 | bool writeData64(uint64_t offset, uint64_t data) 45 | { 46 | const size_t sz = sizeof(uint64_t); 47 | SwapData(data); 48 | 49 | // pass NULL as fileName for base executable 50 | return MemoryPatch(NULL, /* relative address */ offset, /* patch bytes */ &data, /* patch bytes length */ sz).Modify(); 51 | } 52 | -------------------------------------------------------------------------------- /workingMenu16.4/KittyMemory/writeData.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // writeData.h 3 | // 4 | // 5 | // Created by MJ (Ruit) on 4/13/19. 6 | // 7 | 8 | 9 | /* 10 | This is an alternative for the old writeData that was made by HackJack & Razzile 11 | */ 12 | 13 | 14 | #ifndef writeData_h 15 | #define writeData_h 16 | 17 | #include 18 | #include "MemoryPatch.hpp" 19 | 20 | 21 | #define BITS_IN_BYTE 8 22 | 23 | 24 | // https://www.exploringbinary.com/number-of-bits-in-a-decimal-integer/ 25 | // returns bits size of an integer 26 | inline int findBits(uint64_t n) 27 | { 28 | if(n > 0) 29 | { 30 | return floor(log(n)/log(2))+1; 31 | } 32 | return 0; 33 | } 34 | 35 | 36 | // returns bytes size of an integer 37 | inline size_t findBytes(uint64_t data) 38 | { 39 | int bits = findBits(data); 40 | if(bits > 0) 41 | { 42 | return (size_t)(bits / BITS_IN_BYTE); 43 | } 44 | return 0; 45 | } 46 | 47 | 48 | template 49 | void SwapData(T& data) 50 | { 51 | const size_t sz = sizeof(T); 52 | switch (sz) 53 | { 54 | case sizeof(int16_t): 55 | data = _OSSwapInt16(data); 56 | break; 57 | case sizeof(int32_t): 58 | data = _OSSwapInt32(data); 59 | break; 60 | case sizeof(int64_t): 61 | data = _OSSwapInt64(data); 62 | break; 63 | default: 64 | break; 65 | } 66 | } 67 | 68 | bool writeData8 (uint64_t offset, uint8_t data); 69 | bool writeData16(uint64_t offset, uint16_t data); 70 | bool writeData32(uint64_t offset, uint32_t data); 71 | bool writeData64(uint64_t offset, uint64_t data); 72 | 73 | #endif /* writeData.h */ -------------------------------------------------------------------------------- /workingMenu16.4/Makefile: -------------------------------------------------------------------------------- 1 | 2 | THEOS_DEVICE_IP = 192.168.1.36 3 | THEOS_DEVICE_PORT=22 4 | 5 | ARCHS = arm64 arm64e 6 | 7 | DEBUG = 0 8 | FINALPACKAGE = 1 9 | FOR_RELEASE = 1 10 | 11 | TARGET = iphone:clang:latest:latest 12 | CFLAGS = -fobjc-arc 13 | 14 | include $(THEOS)/makefiles/common.mk 15 | 16 | TWEAK_NAME = ModMenu 17 | 18 | 19 | 20 | ModMenu_FRAMEWORKS = UIKit Foundation Security QuartzCore CoreGraphics CoreText AVFoundation Accelerate GLKit SystemConfiguration GameController 21 | 22 | 23 | ModMenu_CFLAGS = -fobjc-arc -Wall -Wno-deprecated-declarations -Wno-unused-variable -Wno-unused-value -Wno-unused-function 24 | ModMenu_CCFLAGS = -std=c++11 -fno-rtti -fno-exceptions -DNDEBUG -Wall -Wno-deprecated-declarations -Wno-unused-variable -Wno-unused-value -Wno-unused-function 25 | 26 | ModMenu_FILES = UserMenu.mm Menu.mm MenuLoad/ImGuiDrawView.xm $(wildcard MenuLoad/*.mm) $(wildcard MenuLoad/*.m) $(wildcard KittyMemory/*.cpp) $(wildcard KittyMemory/*.mm) $(wildcard img/*.m) 27 | 28 | 29 | 30 | #LQMNemOS_LIBRARIES += substrate 31 | # GO_EASY_ON_ME = 1 32 | 33 | include $(THEOS_MAKE_PATH)/tweak.mk 34 | include $(THEOS)/makefiles/aggregate.mk 35 | after-install:: 36 | install.exec "killall -9 kgvn || :" 37 | 38 | 39 | -------------------------------------------------------------------------------- /workingMenu16.4/Menu.h: -------------------------------------------------------------------------------- 1 | // 2 | // Menu.h 3 | // BaseMenu 4 | // 5 | // Created by Carson Mobile on 9/1/23. 6 | // 7 | 8 | #ifndef Menu_h 9 | #define Menu_h 10 | #include 11 | #include 12 | #include 13 | #include "KittyMemory/imgui.h" 14 | #include "KittyMemory/imgui_internal.h" 15 | #include "KittyMemory/imgui_impl_metal.h" 16 | 17 | using namespace std; 18 | class MenuIcon{ 19 | public: 20 | static MenuIcon& getInstance() { 21 | static MenuIcon instance; // The single instance 22 | return instance; 23 | } 24 | void DrawIcon(); 25 | void SetIconURL(string imageURL); 26 | void SetLinkURL(string newURL); 27 | void SetIconSize(float x, float y); 28 | private: 29 | ImVec2 IconSize; 30 | ImTextureID LogoTexture; 31 | string URL; 32 | }; 33 | 34 | 35 | class TabBar { 36 | public: 37 | TabBar(); 38 | void DrawTabs(); 39 | void AddTab(string TabName); 40 | int GetSelectedTab() const; 41 | int GetSelectedTab(string TabName) const; 42 | bool isTabSelected(string TabName) const; 43 | ImVec2 GetTabBarStartLocation(); 44 | void BeginWindowChild(); 45 | private: 46 | vector Tabs; 47 | int SelectedTab; 48 | }; 49 | 50 | class MenuTab { 51 | public: 52 | MenuTab() : isSelected(false) {} 53 | MenuTab(std::string TabName, std::function TabDrawFunction) {isSelected = false; Name = TabName; DrawFunction = TabDrawFunction;} 54 | void InitializeWithName(std::string TabName, std::function TabDrawFunction) { 55 | Name = TabName; 56 | DrawFunction = TabDrawFunction; 57 | } 58 | void TabDraw(ImVec2 ButtonSize); 59 | void Unselect(); 60 | void Select(); 61 | bool CheckSelected() const; 62 | void ExecuteDrawMenu() const; 63 | 64 | private: 65 | std::string Name; 66 | std::function DrawFunction; 67 | bool isSelected; 68 | }; 69 | 70 | class MainMenu{ 71 | public: 72 | MainMenu(); 73 | void DrawMainMenu(); 74 | void TabSelected(string TabName); 75 | void InitializeTab(MenuTab newTab); 76 | void HandleTabs(MenuTab& sender); 77 | static MainMenu& getInstance() { 78 | static MainMenu instance; // The single instance 79 | return instance; 80 | } 81 | ImVec2 GetMenuSize() const; 82 | ImVec2 GetMenuPos() const; 83 | ImVec2 GetLogoSize() const; 84 | float GetLogoToTabSpacing() const; 85 | float GetTabToPagesSpacing() const; 86 | ImVec2 CursorStart; 87 | string MenuName; 88 | private: 89 | ImVec2 MenuSize; 90 | ImVec2 MenuPos; 91 | ImVec2 LogoSize; 92 | float LogoToTabSpacing; 93 | float TabsToPagesSpacing; 94 | std::vector Tabs; 95 | }; 96 | 97 | #endif /* Menu_h */ 98 | -------------------------------------------------------------------------------- /workingMenu16.4/Menu.mm: -------------------------------------------------------------------------------- 1 | // 2 | // Menu.m 3 | // BaseMenu 4 | // 5 | // Created by Carson Mobile on 9/1/23. 6 | // 7 | 8 | #import 9 | #include "MenuLoad/Includes.h" 10 | void MenuIcon::DrawIcon(){ 11 | ImGui::PushStyleColor(ImGuiCol_Button, ImGuiCol_WindowBg); 12 | ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImGuiCol_WindowBg); 13 | ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImGuiCol_WindowBg); 14 | /* float ButtonSize = IconSize.x < IconSize.y ? IconSize.x : IconSize.y; 15 | if(IconSize.x > IconSize.y){ 16 | float DeltaWidth = IconSize.x - ButtonSize; 17 | float ButtonStartWidth = DeltaWidth/2; 18 | ImGui::SetCursorPos(ImVec2(ImGui::GetCursorPosX() + ButtonStartWidth, ImGui::GetCursorPosY())); 19 | } 20 | if(ImGui::ImageButton(LogoTexture, ImVec2(ButtonSize, ButtonSize))) */ 21 | if(ImGui::ImageButton(LogoTexture, IconSize)) 22 | { 23 | NSString* urlString = [NSString stringWithCString:URL.c_str() encoding:NSUTF8StringEncoding]; 24 | NSURL *url = [NSURL URLWithString:urlString]; 25 | if ([[UIApplication sharedApplication] canOpenURL:url]) { 26 | [[UIApplication sharedApplication] openURL:url options:@{} completionHandler:nil]; 27 | } 28 | } 29 | ImGui::PopStyleColor(3); 30 | } 31 | void MenuIcon::SetIconURL(string imageURL){ 32 | NSString *imageUrlString = [NSString stringWithCString:imageURL.c_str() encoding:NSUTF8StringEncoding]; 33 | NSURL *imageUrl = [NSURL URLWithString:imageUrlString]; 34 | 35 | NSURLSession *session = [NSURLSession sharedSession]; 36 | NSURLSessionDataTask *dataTask = [session dataTaskWithURL:imageUrl completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { 37 | if (!error) { 38 | if (data) { 39 | UIImage *image = [UIImage imageWithData:data]; 40 | id < MTLTexture > GlobalCTex = [[[MTKTextureLoader alloc] initWithDevice:MTLCreateSystemDefaultDevice()] newTextureWithCGImage:image.CGImage options:nil error:nil]; 41 | LogoTexture = (ImTextureID)CFBridgingRetain(GlobalCTex); 42 | } 43 | } 44 | }]; 45 | [dataTask resume]; 46 | } 47 | void MenuIcon::SetLinkURL(string newURL){ 48 | URL = newURL; 49 | } 50 | void MenuIcon::SetIconSize(float x, float y){ 51 | IconSize = ImVec2(x,y); 52 | } 53 | 54 | 55 | 56 | TabBar::TabBar(){ 57 | SelectedTab = 0; 58 | } 59 | ImVec2 TabBar::GetTabBarStartLocation(){ 60 | MainMenu& menu = MainMenu::getInstance(); 61 | return ImVec2(menu.GetLogoSize().x + menu.GetTabToPagesSpacing() + menu.CursorStart.x + ImGui::GetWindowPos().x, menu.CursorStart.y + ImGui::GetWindowPos().y); 62 | } 63 | 64 | void TabBar::AddTab(string TabName){ 65 | Tabs.push_back(TabName); 66 | } 67 | int TabBar::GetSelectedTab() const{ 68 | return SelectedTab; 69 | } 70 | int TabBar::GetSelectedTab(string TabName) const{ 71 | for(int i = 0; iAddRectFilled(GetTabBarStartLocation(), ImVec2(GetTabBarStartLocation().x + PageWidth, GetTabBarStartLocation().y + MainMenu::getInstance().GetLogoSize().y), ImGui::ColorConvertFloat4ToU32(ImGui::GetStyleColorVec4(ImGuiCol_Button)), 10); 86 | 87 | float ButtonWidth = PageWidth/Tabs.size(); 88 | ImVec2 TabDrawPosition = ImVec2(menu.GetLogoSize().x + menu.GetTabToPagesSpacing() + menu.CursorStart.x, menu.CursorStart.y); 89 | for(int i = 0; iAddRectFilled(FunctionBackgroundStartLocation, ImVec2(FunctionBackgroundStartLocation.x + PageWidth , ImGui::GetWindowWidth() + ImGui::GetWindowPos().y - 40), ImGui::ColorConvertFloat4ToU32(ImGui::GetStyleColorVec4(ImGuiCol_Button)), 10); 115 | ImGui::SetCursorPos(FunctionDrawStartLocation); 116 | ImGui::BeginChild("CHILD", ImVec2(ImGui::GetWindowWidth() - (menu.GetTabToPagesSpacing() + menu.GetLogoSize().x), ImGui::GetWindowHeight() - (menu.GetLogoSize().y + menu.GetLogoToTabSpacing() + menu.CursorStart.y + 40)), false, ImGuiWindowFlags_None); 117 | } 118 | 119 | 120 | MainMenu::MainMenu(){ 121 | float ScreenWidth = [UIScreen mainScreen].bounds.size.width; 122 | float ScreenHeight = [UIScreen mainScreen].bounds.size.height; 123 | float MenuHeight = ScreenHeight < 400 ? ScreenHeight : 400; 124 | MenuSize = ImVec2(400, MenuHeight); 125 | 126 | MenuPos = ImVec2(ScreenWidth/2 - 400/2, ScreenHeight/2 - MenuHeight/2); 127 | LogoSize = ImVec2(MenuSize.x / 4, MenuHeight / 13); 128 | LogoToTabSpacing = 10; 129 | TabsToPagesSpacing = 10; 130 | MenuName = "Testing Menu"; 131 | MenuIcon::getInstance().SetIconURL("https://carsontoolcsvr.online/tedimage.png"); 132 | MenuIcon::getInstance().SetLinkURL("https://github.com/CarsonARK/AdvancedModMenuTemplate"); 133 | //https://github.com/CarsonARK/TheosModMenuTemplate 134 | } 135 | void MainMenu::InitializeTab(MenuTab newTab){ 136 | Tabs.push_back(newTab); 137 | } 138 | ImVec2 MainMenu::GetMenuSize() const{ 139 | return MenuSize; 140 | } 141 | ImVec2 MainMenu::GetMenuPos() const{ 142 | return MenuPos; 143 | } 144 | ImVec2 MainMenu::GetLogoSize() const{ 145 | return LogoSize; 146 | } 147 | float MainMenu::GetLogoToTabSpacing() const{ 148 | return LogoToTabSpacing; 149 | } 150 | float MainMenu::GetTabToPagesSpacing() const{ 151 | return TabsToPagesSpacing; 152 | } 153 | 154 | void MenuTab::Unselect(){ 155 | isSelected = false; 156 | } 157 | void MenuTab::Select(){ 158 | isSelected = true; 159 | } 160 | bool MenuTab::CheckSelected() const{ 161 | return isSelected; 162 | } 163 | void MenuTab::TabDraw(ImVec2 ButtonSize){ 164 | if(isSelected){ 165 | ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1,0,0,0.7)); 166 | ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(1,0,0,0.7)); 167 | ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(1,0,0,0.7)); 168 | 169 | if(ImGui::Button(Name.c_str(), ButtonSize)){ 170 | MainMenu::getInstance().HandleTabs(*this); 171 | } 172 | 173 | ImGui::PopStyleColor(3); 174 | } 175 | else { 176 | ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1,0,0,0)); 177 | ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(1,0,0,0)); 178 | ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(1,0,0,0)); 179 | 180 | if(ImGui::Button(Name.c_str(), ButtonSize)){ 181 | MainMenu::getInstance().HandleTabs(*this); 182 | } 183 | ImGui::PopStyleColor(3); 184 | } 185 | } 186 | void MenuTab::ExecuteDrawMenu() const{ 187 | DrawFunction(); 188 | } 189 | void MainMenu::HandleTabs(MenuTab& sender){ 190 | for(MenuTab& currentTab : Tabs){ 191 | currentTab.Unselect(); 192 | } 193 | sender.Select(); 194 | } 195 | void MainMenu::DrawMainMenu(){ 196 | 197 | static dispatch_once_t DpWindow; 198 | dispatch_once(&DpWindow, ^{ 199 | ImGui::SetNextWindowPos(MenuPos); 200 | ImGui::SetNextWindowSize(MenuSize); 201 | }); 202 | 203 | ImGuiWindowFlags MenuFlags = MoveMenu ? ImGuiWindowFlags_NoCollapse : ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove; 204 | ImGui::Begin(MenuName.c_str(), NULL, MenuFlags); 205 | 206 | 207 | ImVec2 StartingCursorPosition = ImGui::GetCursorPos(); 208 | CursorStart = ImGui::GetCursorPos(); 209 | MenuIcon::getInstance().SetIconSize(LogoSize.x, LogoSize.y); 210 | MenuIcon::getInstance().DrawIcon(); 211 | 212 | MenuOrigin = ImGui::GetWindowPos(); 213 | MenuSize = ImGui::GetWindowSize(); 214 | 215 | ImVec2 TabStartPosition = ImVec2(StartingCursorPosition.x + 5, StartingCursorPosition.y + LogoSize.y + LogoToTabSpacing); 216 | 217 | float RemainingHeight = ImGui::GetWindowHeight() - TabStartPosition.y; 218 | float ButtonHeight = 40 < (RemainingHeight/Tabs.size()) + 5 ? 40 : (RemainingHeight/Tabs.size()) + 5; 219 | 220 | ImVec2 ButtonBackgroundRect = ImVec2(ImGui::GetWindowPos().x + StartingCursorPosition.x + 5, ImGui::GetWindowPos().y + StartingCursorPosition.y + LogoSize.y + LogoToTabSpacing); 221 | ImGui::GetWindowDrawList()->AddRectFilled(ButtonBackgroundRect, ImVec2(ButtonBackgroundRect.x + LogoSize.x - 5, ButtonBackgroundRect.y + ButtonHeight * Tabs.size()), ImGui::ColorConvertFloat4ToU32(ImGui::GetStyleColorVec4(ImGuiCol_Button)), 10); 222 | 223 | ImGui::SetCursorPos(TabStartPosition); 224 | ImGui::SetWindowFontScale(1.3); 225 | 226 | ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0, 0.5)); 227 | 228 | for(MenuTab& CurrentTab : Tabs) 229 | { 230 | CurrentTab.TabDraw(ImVec2(LogoSize.x-5, ButtonHeight)); 231 | TabStartPosition.y += ButtonHeight; 232 | ImGui::SetCursorPos(TabStartPosition); 233 | } 234 | 235 | ImGui::PopStyleVar(); 236 | 237 | for(MenuTab& CurrentTab : Tabs){ 238 | if(CurrentTab.CheckSelected()){ 239 | CurrentTab.ExecuteDrawMenu(); 240 | break; 241 | } 242 | } 243 | ImGui::SetWindowFontScale(1); 244 | ImGui::End(); 245 | } 246 | -------------------------------------------------------------------------------- /workingMenu16.4/MenuLoad/ImGuiDrawView.h: -------------------------------------------------------------------------------- 1 | // 2 | // ImGuiDrawView.h 3 | // ImGuiTest 4 | // 5 | // Created by yiming on 2021/6/2. 6 | // 7 | 8 | #import 9 | NS_ASSUME_NONNULL_BEGIN 10 | 11 | 12 | @interface ImGuiDrawView : UIViewController 13 | 14 | + (void)showChange:(BOOL)open; 15 | + (BOOL)isMenuShowing; 16 | - (void)updateIOWithTouchEvent:(UIEvent *)event; 17 | 18 | 19 | @end 20 | 21 | NS_ASSUME_NONNULL_END 22 | -------------------------------------------------------------------------------- /workingMenu16.4/MenuLoad/ImGuiDrawView.xm: -------------------------------------------------------------------------------- 1 | #include "Includes.h" 2 | 3 | 4 | #define kWidth [UIScreen mainScreen].bounds.size.width 5 | #define kHeight [UIScreen mainScreen].bounds.size.height 6 | #define kScale [UIScreen mainScreen].scale 7 | 8 | 9 | 10 | 11 | 12 | 13 | @interface ImGuiDrawView () 14 | @property (nonatomic, strong) id device; 15 | @property (nonatomic, strong) id commandQueue; 16 | 17 | @end 18 | @implementation ImGuiDrawView 19 | 20 | static bool MenDeal = true; 21 | 22 | - (instancetype)initWithNibName:(nullable NSString *)nibNameOrNil bundle:(nullable NSBundle *)nibBundleOrNil 23 | { 24 | self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; 25 | 26 | _device = MTLCreateSystemDefaultDevice(); 27 | _commandQueue = [_device newCommandQueue]; 28 | 29 | if (!self.device) abort(); 30 | 31 | IMGUI_CHECKVERSION(); 32 | ImGui::CreateContext(); 33 | ImGuiIO& io = ImGui::GetIO(); (void)io; 34 | 35 | ImGui::StyleColorsDark(); 36 | 37 | /*NSString *FontPath = @"/System/Library/Fonts/AppFonts/Charter.ttc"; 38 | io.Fonts->AddFontFromFileTTF(FontPath.UTF8String, 40.f,NULL,io.Fonts->GetGlyphRangesChineseSimplifiedCommon()); */ 39 | 40 | ImFontConfig config; 41 | config.FontDataOwnedByAtlas = false; 42 | 43 | io.Fonts->Clear(); // clear fonts if you loaded some before (even if only default one was loaded) 44 | 45 | ImFontConfig font_cfg; 46 | font_cfg.FontDataOwnedByAtlas = false; // if true it will try to free memory and fail 47 | io.Fonts->AddFontFromMemoryTTF((void*)poppinsFont, sizeof(poppinsFont), 18, &font_cfg); 48 | 49 | static const ImWchar icons_ranges[] = { ICON_MIN_FA, ICON_MAX_FA, 0 }; 50 | ImFontConfig icons_config; 51 | icons_config.MergeMode = true; 52 | icons_config.PixelSnapH = true; 53 | icons_config.FontDataOwnedByAtlas = false; 54 | io.Fonts->AddFontFromMemoryTTF((void*)fontAwesome, sizeof(fontAwesome), 18, &icons_config, icons_ranges); 55 | 56 | ImGui_ImplMetal_Init(_device); 57 | 58 | return self; 59 | } 60 | 61 | + (void)showChange:(BOOL)open 62 | { 63 | MenDeal = open; 64 | } 65 | + (BOOL)isMenuShowing { 66 | return MenDeal; 67 | } 68 | 69 | 70 | - (MTKView *)mtkView 71 | { 72 | return (MTKView *)self.view; 73 | } 74 | 75 | 76 | 77 | - (void)loadView 78 | { 79 | CGFloat w = [UIApplication sharedApplication].windows[0].rootViewController.view.frame.size.width; 80 | CGFloat h = [UIApplication sharedApplication].windows[0].rootViewController.view.frame.size.height; 81 | self.view = [[MTKView alloc] initWithFrame:CGRectMake(0, 0, w, h)]; 82 | } 83 | 84 | - (void)viewDidLoad { 85 | [super viewDidLoad]; 86 | 87 | self.mtkView.device = self.device; 88 | self.mtkView.delegate = self; 89 | self.mtkView.clearColor = MTLClearColorMake(0, 0, 0, 0); 90 | self.mtkView.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0]; 91 | self.mtkView.clipsToBounds = YES; 92 | 93 | } 94 | 95 | 96 | #pragma mark - Interaction 97 | 98 | 99 | 100 | - (void)updateIOWithTouchEvent:(UIEvent *)event 101 | { 102 | UITouch *anyTouch = event.allTouches.anyObject; 103 | CGPoint touchLocation = [anyTouch locationInView:self.view]; 104 | ImGuiIO &io = ImGui::GetIO(); 105 | io.MousePos = ImVec2(touchLocation.x, touchLocation.y); 106 | 107 | BOOL hasActiveTouch = NO; 108 | for (UITouch *touch in event.allTouches) 109 | { 110 | if (touch.phase != UITouchPhaseEnded && touch.phase != UITouchPhaseCancelled) 111 | { 112 | hasActiveTouch = YES; 113 | break; 114 | } 115 | } 116 | io.MouseDown[0] = hasActiveTouch; 117 | 118 | 119 | 120 | 121 | } 122 | 123 | 124 | 125 | - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 126 | { 127 | [self updateIOWithTouchEvent:event]; 128 | } 129 | 130 | - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event 131 | { 132 | [self updateIOWithTouchEvent:event]; 133 | } 134 | 135 | - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event 136 | { 137 | [self updateIOWithTouchEvent:event]; 138 | } 139 | 140 | - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event 141 | { 142 | [self updateIOWithTouchEvent:event]; 143 | } 144 | 145 | - (void)drawInMTKView:(MTKView*)view 146 | { 147 | 148 | 149 | hideRecordTextfield.secureTextEntry = StreamerMode; 150 | 151 | 152 | ImGuiIO& io = ImGui::GetIO(); 153 | io.DisplaySize.x = view.bounds.size.width; 154 | io.DisplaySize.y = view.bounds.size.height; 155 | 156 | 157 | CGFloat framebufferScale = view.window.screen.nativeScale ?: UIScreen.mainScreen.nativeScale; 158 | io.DisplayFramebufferScale = ImVec2(framebufferScale, framebufferScale); 159 | io.DeltaTime = 1 / float(view.preferredFramesPerSecond ?: 60); 160 | 161 | id commandBuffer = [self.commandQueue commandBuffer]; 162 | 163 | 164 | 165 | 166 | static bool show_line = false; 167 | if (MenDeal == true) 168 | { 169 | [self.view setUserInteractionEnabled:YES]; 170 | [self.view.superview setUserInteractionEnabled:YES]; 171 | [menuTouchView setUserInteractionEnabled:YES]; 172 | } 173 | else if (MenDeal == false) 174 | { 175 | 176 | [self.view setUserInteractionEnabled:NO]; 177 | [self.view.superview setUserInteractionEnabled:NO]; 178 | [menuTouchView setUserInteractionEnabled:NO]; 179 | 180 | } 181 | 182 | 183 | 184 | MTLRenderPassDescriptor* renderPassDescriptor = view.currentRenderPassDescriptor; 185 | if (renderPassDescriptor != nil) 186 | { 187 | id renderEncoder = [commandBuffer renderCommandEncoderWithDescriptor:renderPassDescriptor]; 188 | [renderEncoder pushDebugGroup:@"ImGui Jane"]; 189 | 190 | ImGui_ImplMetal_NewFrame(renderPassDescriptor); 191 | ImGui::NewFrame(); 192 | 193 | ImFont* font = ImGui::GetFont(); 194 | font->Scale = 10.f / font->FontSize; 195 | 196 | if (MenDeal == true) 197 | { 198 | 199 | UserMenu::getInstance().DrawMenu(); 200 | //static MenuDraw& menu = MenuDraw::getInstance(); 201 | //menu.HandleDrawMenu(&MenDeal); 202 | 203 | 204 | 205 | } 206 | 207 | ImDrawList* draw_list = ImGui::GetForegroundDrawList(); 208 | 209 | 210 | ImGui::Render(); 211 | ImDrawData* draw_data = ImGui::GetDrawData(); 212 | ImGui_ImplMetal_RenderDrawData(draw_data, commandBuffer, renderEncoder); 213 | 214 | [renderEncoder popDebugGroup]; 215 | [renderEncoder endEncoding]; 216 | 217 | [commandBuffer presentDrawable:view.currentDrawable]; 218 | 219 | } 220 | 221 | 222 | [commandBuffer commit]; 223 | 224 | } 225 | 226 | 227 | 228 | 229 | 230 | 231 | - (void)mtkView:(MTKView*)view drawableSizeWillChange:(CGSize)size 232 | { 233 | 234 | } 235 | 236 | @end 237 | 238 | 239 | 240 | 241 | 242 | 243 | %ctor 244 | { 245 | 246 | } 247 | -------------------------------------------------------------------------------- /workingMenu16.4/MenuLoad/Includes.h: -------------------------------------------------------------------------------- 1 | #include "ImGuiDrawView.h" 2 | #include "MenuLoad.h" 3 | #include "../Menu.h" 4 | #include "../UserMenu.h" 5 | #include "../Fonts.hpp" 6 | 7 | #include "../KittyMemory/imgui.h" 8 | #include "../KittyMemory/imgui_internal.h" 9 | #include "../KittyMemory/imgui_impl_metal.h" 10 | 11 | #import 12 | #import 13 | #import 14 | #import 15 | #import 16 | #import 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #define RadiansToDegree 180 /3.141592654f; 29 | #define SCREEN_WIDTH [UIScreen mainScreen].bounds.size.width 30 | #define SCREEN_HEIGHT [UIScreen mainScreen].bounds.size.height 31 | #define SCREEN_SCALE [UIScreen mainScreen].scale 32 | #define timer(sec) dispatch_after(dispatch_time(DISPATCH_TIME_NOW, sec * NSEC_PER_SEC), dispatch_get_main_queue(), ^ 33 | #define PI 3.14159265 34 | 35 | extern MenuInteraction* menuTouchView; 36 | extern ImVec2 MenuOrigin; 37 | extern ImVec2 MenuSize; 38 | extern UIButton* InvisibleMenuButton; 39 | extern UIButton* VisibleMenuButton; 40 | extern UITextField* hideRecordTextfield; 41 | extern UIView* hideRecordView; 42 | extern bool StreamerMode; 43 | extern bool MoveMenu; 44 | -------------------------------------------------------------------------------- /workingMenu16.4/MenuLoad/MenuLoad.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | NS_ASSUME_NONNULL_BEGIN 4 | 5 | @interface MenuLoad : NSObject 6 | @end 7 | @interface MenuInteraction : UIView 8 | @end 9 | 10 | NS_ASSUME_NONNULL_END 11 | -------------------------------------------------------------------------------- /workingMenu16.4/ModMenu.plist: -------------------------------------------------------------------------------- 1 | { Filter = { Bundles = ( "com.yourgame.developer.game" ); }; } -------------------------------------------------------------------------------- /workingMenu16.4/UserMenu.h: -------------------------------------------------------------------------------- 1 | // 2 | // UserMenu.h 3 | // BaseMenu 4 | // 5 | // Created by Carson Mobile on 9/1/23. 6 | // 7 | 8 | #ifndef UserMenu_h 9 | #define UserMenu_h 10 | 11 | class UserMenu{ 12 | public: 13 | void Initialize(); 14 | void DrawMenu(); 15 | static UserMenu& getInstance() { 16 | static UserMenu instance; // The single instance 17 | return instance; 18 | } 19 | }; 20 | 21 | #endif /* UserMenu_h */ 22 | -------------------------------------------------------------------------------- /workingMenu16.4/UserMenu.mm: -------------------------------------------------------------------------------- 1 | // 2 | // UserMenu.m 3 | // BaseMenu 4 | // 5 | // Created by Carson Mobile on 9/1/23. 6 | // 7 | 8 | #import 9 | #include "MenuLoad/Includes.h" 10 | static void BasicTab(){ 11 | static TabBar MenuTwoTB; 12 | static dispatch_once_t once; 13 | dispatch_once(&once, ^{ 14 | MenuTwoTB.AddTab("Basic"); 15 | }); 16 | MenuTwoTB.DrawTabs(); 17 | MenuTwoTB.BeginWindowChild(); 18 | if(MenuTwoTB.isTabSelected("Basic")){ 19 | ImGui::Text("Basic"); 20 | ImGui::Checkbox("Move Menu", &MoveMenu); 21 | ImGui::Checkbox("Streamer Mode", &StreamerMode); 22 | } 23 | ImGui::EndChild(); 24 | } 25 | static void AimbotTab(){ 26 | static TabBar MenuTwoTB; 27 | static dispatch_once_t once; 28 | dispatch_once(&once, ^{ 29 | MenuTwoTB.AddTab("Legit"); 30 | MenuTwoTB.AddTab("Blatant"); 31 | MenuTwoTB.AddTab("Silent"); 32 | }); 33 | MenuTwoTB.DrawTabs(); 34 | MenuTwoTB.BeginWindowChild(); 35 | if(MenuTwoTB.isTabSelected("Legit")){ 36 | ImGui::Text("Legit"); 37 | } 38 | if(MenuTwoTB.isTabSelected("Blatant")){ 39 | ImGui::Text("Blatant"); 40 | } 41 | if(MenuTwoTB.isTabSelected("Silent")){ 42 | ImGui::Text("Silent"); 43 | } 44 | ImGui::EndChild(); 45 | } 46 | static void ESPTab(){ 47 | static TabBar MenuTwoTB; 48 | static dispatch_once_t once; 49 | dispatch_once(&once, ^{ 50 | MenuTwoTB.AddTab("Players"); 51 | MenuTwoTB.AddTab("Entities"); 52 | MenuTwoTB.AddTab("CHAMS"); 53 | }); 54 | MenuTwoTB.DrawTabs(); 55 | MenuTwoTB.BeginWindowChild(); 56 | if(MenuTwoTB.isTabSelected("Players")){ 57 | ImGui::Text("Players"); 58 | } 59 | if(MenuTwoTB.isTabSelected("Entities")){ 60 | ImGui::Text("Entities"); 61 | } 62 | if(MenuTwoTB.isTabSelected("CHAMS")){ 63 | ImGui::Text("CHAMS"); 64 | } 65 | ImGui::EndChild(); 66 | 67 | } 68 | static void CustomizeTab(){ 69 | static TabBar MenuTwoTB; 70 | static dispatch_once_t once; 71 | dispatch_once(&once, ^{ 72 | MenuTwoTB.AddTab("ESP Colors"); 73 | MenuTwoTB.AddTab("Menu Colors"); 74 | }); 75 | MenuTwoTB.DrawTabs(); 76 | MenuTwoTB.BeginWindowChild(); 77 | if(MenuTwoTB.isTabSelected("ESP Colors")){ 78 | ImGui::Text("ESP Colors"); 79 | } 80 | if(MenuTwoTB.isTabSelected("Menu Colors")){ 81 | ImGui::Text("Menu Colors"); 82 | } 83 | ImGui::EndChild(); 84 | } 85 | void UserMenu::Initialize(){ 86 | ImGui::StyleColorsClassic(); 87 | ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 8); //ScrollbarSize 88 | ImGui::PushStyleVar(ImGuiStyleVar_ScrollbarSize, 25); 89 | ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0,0,0,1)); 90 | ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0.5, 0.5)); 91 | ImGui::PushStyleVar(ImGuiStyleVar_WindowTitleAlign, ImVec2(0.5, 0.5)); 92 | 93 | MainMenu::getInstance() = MainMenu(); 94 | MainMenu::getInstance().MenuName = "A Mod Menu"; 95 | //ICON_FA_PLUS_CIRCLE " Create New Profile" 96 | 97 | 98 | MainMenu::getInstance().InitializeTab(MenuTab(ICON_FA_WIND " Basic", BasicTab)); 99 | MainMenu::getInstance().InitializeTab(MenuTab(ICON_FA_BULLSEYE " Aimbot", AimbotTab)); 100 | MainMenu::getInstance().InitializeTab(MenuTab(ICON_FA_EYE " ESP", ESPTab)); 101 | MainMenu::getInstance().InitializeTab(MenuTab(ICON_FA_STAR " Customize", CustomizeTab)); 102 | } 103 | void UserMenu::DrawMenu(){ 104 | MainMenu::getInstance().DrawMainMenu(); 105 | } 106 | -------------------------------------------------------------------------------- /workingMenu16.4/control: -------------------------------------------------------------------------------- 1 | Package: com.newimgui.ark 2 | Name: CarsontoolTest 3 | Depends: mobilesubstrate 4 | Version: 1 5 | Architecture: iphoneos-arm 6 | Description: Testing Making Ark Cheat 7 | Maintainer: Carsontool 8 | Author: Carson 9 | -------------------------------------------------------------------------------- /workingMenu16.4/packages/com.newimgui.ark_1_iphoneos-arm.deb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CarsonARK/AdvancedModMenuTemplate/ea2c8c1704bc1fb5b274fb6b9c219d6b24e1eede/workingMenu16.4/packages/com.newimgui.ark_1_iphoneos-arm.deb --------------------------------------------------------------------------------