├── .DS_Store ├── ImGui ├── CustomWidgets.h ├── CustomWidgets.mm ├── ImGuiDrawViewX.h ├── ImGuiDrawViewX.mm ├── MenuUtils.h ├── MenuUtils.mm ├── imconfig.h ├── imgui.cpp ├── imgui.h ├── imgui_demo.cpp ├── imgui_draw.cpp ├── imgui_impl_metal.h ├── imgui_impl_metal.mm ├── imgui_internal.h ├── imgui_tables.cpp ├── imgui_widgets.cpp ├── imstb_rectpack.h ├── imstb_textedit.h └── imstb_truetype.h ├── Includes ├── .DS_Store ├── Fonts │ └── Fonts.hpp ├── Hooking │ ├── JailedHook.h │ └── JailedHook.mm ├── Libs │ ├── dobby_defines.h │ ├── libdobby_fixed.a │ └── libstdc++.6.0.9.dylib ├── Obfuscate.h ├── SCLAlertView │ ├── SCLAlertView.h │ ├── SCLAlertView.m │ ├── SCLAlertViewResponder.h │ ├── SCLAlertViewResponder.m │ ├── SCLAlertViewStyleKit.h │ ├── SCLAlertViewStyleKit.m │ ├── SCLButton.h │ ├── SCLButton.m │ ├── SCLMacros.h │ ├── SCLSwitchView.h │ ├── SCLSwitchView.m │ ├── SCLTextView.h │ ├── SCLTextView.m │ ├── SCLTimerDisplay.h │ ├── SCLTimerDisplay.m │ ├── UIImage+ImageEffects.h │ └── UIImage+ImageEffects.m └── Unity │ ├── Quaternion.h │ ├── Unity.h │ └── Vector3.h ├── Makefile ├── Menu.h ├── Menu.mm ├── Mods.h ├── Mods.mm ├── README.md ├── control ├── iOSImGui.plist └── menupic ├── .DS_Store └── screenshot.png /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Duende510/iOS-ImGui-ModMenu-Jailed/c91916012c5b78bda036cfdd65276f498f35d365/.DS_Store -------------------------------------------------------------------------------- /ImGui/CustomWidgets.h: -------------------------------------------------------------------------------- 1 | #ifndef CustomWidgets_h 2 | #define CustomWidgets_h 3 | #include 4 | #include 5 | #include 6 | #include "imgui.h" 7 | #include "imgui_internal.h" 8 | #include "imgui_impl_metal.h" 9 | #include "Includes/Fonts/Fonts.hpp" 10 | #import 11 | #import 12 | #import 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | using namespace std; 22 | 23 | void LightTheme(); 24 | void saveSettings(const char* label, bool value); 25 | bool loadSettings(const char* label, bool defaultValue); 26 | bool ToggleButton(const char* label, bool* v); 27 | bool ToggleWidget(const char* icon, const char* widgetName, bool* v, bool* newChildVisible); 28 | bool ToggleButtonMini(const char* label, bool* v); 29 | void SliderFloatMini(const char* label, float* v, float v_min, float v_max); 30 | void SliderIntMini(const char* label, int* v, int v_min, int v_max); 31 | void IntInputMini(const char* label, int* v, int v_min, int v_max); 32 | bool TextInputMini(const char* label, std::string& text, bool integerOnly); 33 | void CopyToClipboard(const char* text); 34 | 35 | extern int ChildColor[4]; 36 | extern int BGColor[4]; 37 | extern int IconChildColor[4]; 38 | extern int InactiveTextColor[4]; 39 | extern int ActiveTextColor[4]; 40 | extern int GrabColor[4]; 41 | extern int animation_text; 42 | extern int speed; 43 | extern bool ToggleAnimations; 44 | extern bool lightTheme; 45 | extern bool newChildVisible; 46 | extern bool saveToggleStates; 47 | extern std::map childVisibilityMap; 48 | 49 | #pragma once 50 | 51 | struct Output { 52 | std::string text, time; 53 | bool drawTime; 54 | int type; 55 | 56 | Output(std::string text_, bool drawTime_, int type_) { 57 | text = text_; 58 | drawTime = drawTime_; 59 | type = type_; 60 | } 61 | }; 62 | 63 | class Console { 64 | static Console* instance; 65 | 66 | Console() = default; 67 | 68 | void logInternal(const std::string& text, bool printTime, int type); 69 | 70 | void renderLog(Output& output); 71 | void renderLogError(Output& output); 72 | void renderLogInfo(Output& output); 73 | void renderLogSuccess(Output& output); 74 | void renderLogWarning(Output& output); 75 | std::string getCurrentTime(); 76 | 77 | public: 78 | int selectedTypeTab; 79 | char inputBuf[256]; 80 | std::vector outputArr; 81 | bool DRAW_CONSOLE = true; 82 | 83 | static Console& getInstance() { 84 | if (!instance) { 85 | instance = new Console(); 86 | } 87 | return *instance; 88 | } 89 | 90 | static void addLog(const std::string& text, bool printTime = true) { 91 | getInstance().logInternal(text, printTime, 0); 92 | } 93 | 94 | static void logError(const std::string& text, bool printTime = true) { 95 | getInstance().logInternal(text, printTime, 1); 96 | } 97 | 98 | static void logInfo(const std::string& text, bool printTime = true) { 99 | getInstance().logInternal(text, printTime, 2); 100 | } 101 | 102 | static void logWarning(const std::string& text, bool printTime = true) { 103 | getInstance().logInternal(text, printTime, 4); 104 | } 105 | 106 | static void logSuccess(const std::string& text, bool printTime = true) { 107 | getInstance().logInternal(text, printTime, 3); 108 | } 109 | 110 | static void render() { 111 | getInstance().renderInternal(); 112 | } 113 | 114 | private: 115 | void renderInternal(); 116 | }; 117 | 118 | #endif 119 | -------------------------------------------------------------------------------- /ImGui/CustomWidgets.mm: -------------------------------------------------------------------------------- 1 | #include "CustomWidgets.h" 2 | #import "../Includes/SCLAlertView/SCLAlertView.h" 3 | #import "../Includes/Obfuscate.h" 4 | #define UIColorFromHex(hexColor) [UIColor colorWithRed:((float)((hexColor & 0xFF0000) >> 16))/255.0 green:((float)((hexColor & 0xFF00) >> 8))/255.0 blue:((float)(hexColor & 0xFF))/255.0 alpha:1.0] 5 | #define UIColorFromRGBA(r, g, b, a) [UIColor colorWithRed:(r)/255.0 green:(g)/255.0 blue:(b)/255.0 alpha:(a)] 6 | 7 | 8 | void LightTheme() 9 | { 10 | int lightBG[3] = { 214, 219, 226 }; 11 | int lightChild[3] = { 230, 234, 238 }; 12 | int lightIconChild[3] = { 248, 252, 255 }; 13 | int lightInactiveText[3] = { 123, 133, 146 }; 14 | int lightActiveText[3] = { 85, 85, 85 }; 15 | int lightGrabColor[3] = { 210, 210, 210 }; 16 | 17 | int darkBG[3] = { 17, 17, 19 }; 18 | int darkChild[3] = { 22, 21, 26 }; 19 | int darkIconChild[3] = { 25, 26, 31 }; 20 | int darkInactiveText[3] = { 84, 82, 89 }; 21 | int darkActiveText[3] = { 255, 255, 255 }; 22 | int darkGrabColor[3] = { 72, 71, 78 }; 23 | 24 | if (lightTheme) 25 | { 26 | for (int i = 0; i < 3; i++) { 27 | BGColor[i] = std::min(BGColor[i] + speed, lightBG[i]); 28 | ChildColor[i] = std::min(ChildColor[i] + speed, lightChild[i]); 29 | IconChildColor[i] = std::min(IconChildColor[i] + speed, lightIconChild[i]); 30 | InactiveTextColor[i] = std::min(InactiveTextColor[i] + speed, lightInactiveText[i]); 31 | ActiveTextColor[i] = std::min(ActiveTextColor[i] + speed, lightActiveText[i]); 32 | GrabColor[i] = std::min(GrabColor[i] + speed, lightGrabColor[i]); 33 | } 34 | } 35 | else { 36 | for (int i = 0; i < 3; i++) { 37 | BGColor[i] = std::max(BGColor[i] - speed, darkBG[i]); 38 | ChildColor[i] = std::max(ChildColor[i] - speed, darkChild[i]); 39 | IconChildColor[i] = std::max(IconChildColor[i] - speed, darkIconChild[i]); 40 | InactiveTextColor[i] = std::max(InactiveTextColor[i] - speed, darkInactiveText[i]); 41 | ActiveTextColor[i] = std::max(ActiveTextColor[i] - speed, darkActiveText[i]); 42 | GrabColor[i] = std::min(GrabColor[i] + speed, darkGrabColor[i]); 43 | } 44 | } 45 | } 46 | 47 | void CopyToClipboard(const char* text) 48 | { 49 | UIPasteboard* pasteboard = [UIPasteboard generalPasteboard]; 50 | [pasteboard setString:[NSString stringWithUTF8String:text]]; 51 | } 52 | 53 | void saveSettings(const char* label, bool value) { 54 | NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; 55 | [defaults setBool:value forKey:[NSString stringWithUTF8String:label]]; 56 | [defaults synchronize]; 57 | } 58 | 59 | bool loadSettings(const char* label, bool defaultValue) { 60 | NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; 61 | if ([defaults objectForKey:[NSString stringWithUTF8String:label]] != nil) { 62 | return [defaults boolForKey:[NSString stringWithUTF8String:label]]; 63 | } 64 | return defaultValue; 65 | } 66 | 67 | bool ToggleWidget(const char* icon, const char* widgetName, bool* v, bool* newChildVisible) 68 | { 69 | static std::map previousStates; 70 | std::string tabNameID = "##tabName_" + std::string(widgetName); 71 | std::string iconChildID = "##iconChild_" + std::string(widgetName); 72 | std::string toggleButtonID = "##toggle_" + std::string(widgetName); 73 | std::string settingsButtonID = "##settingsButton_" + std::string(widgetName); 74 | 75 | static std::map settingsButtonStates; 76 | if (settingsButtonStates.find(widgetName) == settingsButtonStates.end()) { 77 | settingsButtonStates[widgetName] = false; 78 | } 79 | bool stateChanged = false; 80 | 81 | ImGui::PushStyleColor(ImGuiCol_ChildBg, IM_COL32(ChildColor[0], ChildColor[1], ChildColor[2], animation_text)); 82 | ImGui::BeginChild(tabNameID.c_str(), ImVec2(ImGui::GetContentRegionAvail().x, 55), false, ImGuiWindowFlags_NoScrollbar); 83 | { 84 | ImVec2 currentPos = ImGui::GetCursorPos(); 85 | ImGui::SetCursorPos(ImVec2(currentPos.x + 5, currentPos.y + 5)); 86 | ImGui::PushStyleColor(ImGuiCol_ChildBg, IM_COL32(IconChildColor[0], IconChildColor[1], IconChildColor[2], animation_text)); 87 | ImGui::BeginChild(iconChildID.c_str(), ImVec2(45, 45), false); 88 | { 89 | ImGui::SetWindowFontScale(0.6f); 90 | ImVec2 iconSize = ImGui::CalcTextSize(icon); 91 | ImVec2 iconPosition = ImVec2((45 - iconSize.x) * 0.5f, (45 - iconSize.y) * 0.5f); 92 | ImU32 iconColor = *v ? IM_COL32(ActiveTextColor[0], ActiveTextColor[1], ActiveTextColor[2], animation_text) : IM_COL32(InactiveTextColor[0], InactiveTextColor[1], InactiveTextColor[2], animation_text); 93 | ImGui::PushStyleColor(ImGuiCol_Text, iconColor); 94 | ImGui::SetCursorPos(iconPosition); 95 | ImGui::Text("%s", icon); 96 | ImGui::SetWindowFontScale(1.0f); 97 | ImGui::PopStyleColor(1); 98 | } 99 | ImGui::EndChild(); 100 | ImGui::PopStyleColor(1); 101 | 102 | ImU32 textColor = *v ? IM_COL32(ActiveTextColor[0], ActiveTextColor[1], ActiveTextColor[2], animation_text) : IM_COL32(InactiveTextColor[0], InactiveTextColor[1], InactiveTextColor[2], animation_text); 103 | ImGui::PushStyleColor(ImGuiCol_Text, textColor); 104 | ImGui::SameLine(); 105 | ImGui::SetCursorPosY(currentPos.y + 16); 106 | ImGui::Text("%s", widgetName); 107 | ImGui::PopStyleColor(1); 108 | 109 | ImGui::SameLine(ImGui::GetContentRegionAvail().x - 75); 110 | if (ToggleButton(toggleButtonID.c_str(), v)) { 111 | stateChanged = true; 112 | } 113 | 114 | if (previousStates[widgetName] != *v) { 115 | previousStates[widgetName] = *v; 116 | stateChanged = true; 117 | *newChildVisible = *v; 118 | } 119 | 120 | ImGui::SameLine(ImGui::GetContentRegionAvail().x - 20); 121 | 122 | float buttonOffsetY = -0.0f; 123 | ImGui::SetCursorPosY(currentPos.y + buttonOffsetY); 124 | const char* settingsIcon = settingsButtonStates[widgetName] ? ICON_FA_MINUS : ICON_FA_PLUS; 125 | 126 | ImGui::PushStyleColor(ImGuiCol_Button, IM_COL32(IconChildColor[0], IconChildColor[1], IconChildColor[2], animation_text)); 127 | ImGui::PushStyleColor(ImGuiCol_ButtonHovered, IM_COL32(IconChildColor[0], IconChildColor[1], IconChildColor[2], animation_text)); 128 | ImGui::PushStyleColor(ImGuiCol_ButtonActive, IM_COL32(IconChildColor[0], IconChildColor[1], IconChildColor[2], animation_text)); 129 | 130 | if (ImGui::Button(settingsButtonID.c_str(), ImVec2(20, 55))) { 131 | settingsButtonStates[widgetName] = !settingsButtonStates[widgetName]; 132 | 133 | for (auto& pair : settingsButtonStates) { 134 | if (pair.first != widgetName) { 135 | pair.second = false; 136 | childVisibilityMap[pair.first] = false; 137 | } else { 138 | childVisibilityMap[widgetName] = settingsButtonStates[widgetName]; 139 | } 140 | } 141 | 142 | *newChildVisible = settingsButtonStates[widgetName]; 143 | if (!settingsButtonStates[widgetName]) { 144 | childVisibilityMap[widgetName] = false; 145 | } else { 146 | childVisibilityMap[widgetName] = true; 147 | } 148 | ToggleAnimations = settingsButtonStates[widgetName]; 149 | } 150 | 151 | ImGui::SetWindowFontScale(0.6f); 152 | ImVec2 buttonSize = ImGui::CalcTextSize(settingsIcon); 153 | ImVec2 buttonPos = ImVec2(ImGui::GetContentRegionAvail().x - 15, (55 - buttonSize.y) * 0.5f); 154 | ImGui::SetCursorPos(buttonPos); 155 | 156 | ImU32 settingsColor = settingsButtonStates[widgetName] ? 157 | IM_COL32(ActiveTextColor[0], ActiveTextColor[1], ActiveTextColor[2], animation_text) : 158 | IM_COL32(InactiveTextColor[0], InactiveTextColor[1], InactiveTextColor[2], animation_text); 159 | 160 | ImGui::PushStyleColor(ImGuiCol_Text, settingsColor); 161 | ImGui::Text("%s", settingsIcon); 162 | ImGui::PopStyleColor(1); 163 | 164 | ImGui::SetWindowFontScale(1.0f); 165 | 166 | ImGui::PopStyleColor(3); 167 | } 168 | ImGui::EndChild(); 169 | ImGui::PopStyleColor(1); 170 | 171 | return stateChanged; 172 | } 173 | 174 | bool ToggleButton(const char* label, bool* v) 175 | { 176 | ImVec2 p = ImGui::GetCursorScreenPos(); 177 | ImDrawList* draw_list = ImGui::GetWindowDrawList(); 178 | 179 | const float toggleWidth = 50.0f; 180 | const float toggleHeight = 25.0f; 181 | const float circleRadius = toggleHeight * 0.45f; 182 | 183 | int id = ImGui::GetID(label); 184 | 185 | static std::map toggleStates; 186 | static std::map bounceProgress; 187 | static std::map animationProgress; 188 | 189 | if (toggleStates.find(id) == toggleStates.end()) { 190 | toggleStates[id] = *v; 191 | animationProgress[id] = toggleStates[id] ? 1.0f : 0.0f; 192 | } 193 | 194 | float circlePosX = p.x + (toggleStates[id] ? toggleWidth - circleRadius : circleRadius); 195 | 196 | if (toggleStates[id]) { 197 | animationProgress[id] = ImMin(animationProgress[id] + 0.05f, 1.0f); 198 | } else { 199 | animationProgress[id] = ImMax(animationProgress[id] - 0.05f, 0.0f); 200 | } 201 | 202 | circlePosX = ImLerp(p.x + circleRadius, p.x + toggleWidth - circleRadius, animationProgress[id]); 203 | 204 | if (animationProgress[id] == 1.0f || animationProgress[id] == 0.0f) { 205 | bounceProgress[id] = ImMin(bounceProgress[id] + 0.1f, 1.0f); 206 | } else { 207 | bounceProgress[id] = ImMax(bounceProgress[id] - 0.1f, 0.0f); 208 | } 209 | 210 | float bounceOffsetX = bounceProgress[id] * 3.0f; 211 | circlePosX += (toggleStates[id] ? -bounceOffsetX : bounceOffsetX); 212 | 213 | ImU32 backgroundColor = (toggleStates[id]) ? IM_COL32(IconChildColor[0], IconChildColor[1], IconChildColor[2], animation_text) : IM_COL32(IconChildColor[0], IconChildColor[1], IconChildColor[2], animation_text); 214 | draw_list->AddRectFilled(ImVec2(p.x, p.y), ImVec2(p.x + toggleWidth, p.y + toggleHeight), backgroundColor, toggleHeight * 0.5f); 215 | 216 | ImU32 circleColor = (toggleStates[id]) ? IM_COL32(ActiveTextColor[0], ActiveTextColor[1], ActiveTextColor[2], animation_text) : IM_COL32(InactiveTextColor[0], InactiveTextColor[1], InactiveTextColor[2], animation_text); 217 | draw_list->AddCircleFilled(ImVec2(circlePosX, p.y + circleRadius + 1), circleRadius - 2.0f, circleColor, 32); 218 | 219 | bool clicked = ImGui::InvisibleButton(label, ImVec2(toggleWidth, toggleHeight)); 220 | 221 | if (clicked) { 222 | toggleStates[id] = !toggleStates[id]; 223 | *v = toggleStates[id]; 224 | } 225 | 226 | return clicked; 227 | } 228 | 229 | 230 | bool ToggleButtonMini(const char* label, bool* v) 231 | { 232 | const float toggleWidth = 36.0f; 233 | const float toggleHeight = 18.0f; 234 | const float circleRadius = toggleHeight * 0.45f; 235 | const float gap = 5.0f; 236 | const float moveUpOffset = 0.0f; 237 | 238 | int id = ImGui::GetID(label); 239 | static std::map toggleStates; 240 | static std::map bounceProgress; 241 | static std::map animationProgress; 242 | 243 | if (toggleStates.find(id) == toggleStates.end()) { 244 | toggleStates[id] = *v; 245 | animationProgress[id] = toggleStates[id] ? 1.0f : 0.0f; 246 | } 247 | 248 | ImU32 textColor = toggleStates[id] ? IM_COL32(ActiveTextColor[0], ActiveTextColor[1], ActiveTextColor[2], animation_text) : IM_COL32(InactiveTextColor[0], InactiveTextColor[1], InactiveTextColor[2], animation_text); 249 | 250 | ImGui::PushStyleColor(ImGuiCol_Text, textColor); 251 | ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 5); 252 | ImGui::TextUnformatted(label); 253 | ImGui::PopStyleColor(); 254 | ImGui::SameLine(); 255 | 256 | ImVec2 windowPos = ImGui::GetWindowPos(); 257 | ImVec2 windowSize = ImGui::GetWindowSize(); 258 | 259 | float toggleBackgroundX = windowPos.x + windowSize.x - toggleWidth - gap; 260 | float toggleBackgroundY = ImGui::GetCursorScreenPos().y - moveUpOffset; 261 | 262 | ImGui::SetCursorScreenPos(ImVec2(toggleBackgroundX, toggleBackgroundY)); 263 | 264 | bool toggled = false; 265 | if (ImGui::InvisibleButton(label, ImVec2(toggleWidth, toggleHeight))) { 266 | toggleStates[id] = !toggleStates[id]; 267 | *v = toggleStates[id]; 268 | toggled = true; 269 | } 270 | 271 | if (toggleStates[id]) { 272 | animationProgress[id] = ImMin(animationProgress[id] + 0.04f, 1.0f); 273 | } else { 274 | animationProgress[id] = ImMax(animationProgress[id] - 0.04f, 0.0f); 275 | } 276 | 277 | float circlePosX = toggleBackgroundX + 6 + animationProgress[id] * (toggleWidth - circleRadius); 278 | if (toggleStates[id]) { 279 | circlePosX -= 4.0f; 280 | } 281 | 282 | if (animationProgress[id] == 1.0f || animationProgress[id] == 0.0f) { 283 | bounceProgress[id] = ImMin(bounceProgress[id] + 0.1f, 1.0f); 284 | } else { 285 | bounceProgress[id] = ImMax(bounceProgress[id] - 0.1f, 0.0f); 286 | } 287 | 288 | float bounceOffsetX = bounceProgress[id] * 3.0f; 289 | circlePosX += (toggleStates[id] ? -bounceOffsetX : bounceOffsetX); 290 | 291 | ImU32 backgroundColor = toggleStates[id] ? IM_COL32(IconChildColor[0], IconChildColor[1], IconChildColor[2], animation_text) : IM_COL32(IconChildColor[0], IconChildColor[1], IconChildColor[2], animation_text); 292 | ImDrawList* draw_list = ImGui::GetWindowDrawList(); 293 | draw_list->AddRectFilled(ImVec2(toggleBackgroundX, toggleBackgroundY), ImVec2(toggleBackgroundX + toggleWidth, toggleBackgroundY + toggleHeight), backgroundColor, toggleHeight * 0.5f); 294 | 295 | ImU32 circleColor = toggleStates[id] ? IM_COL32(ActiveTextColor[0], ActiveTextColor[1], ActiveTextColor[2], animation_text) : IM_COL32(InactiveTextColor[0], InactiveTextColor[1], InactiveTextColor[2], animation_text); 296 | draw_list->AddCircleFilled(ImVec2(circlePosX, toggleBackgroundY + circleRadius + 1), circleRadius - 2.0f, circleColor, 32); 297 | 298 | return toggled; 299 | } 300 | 301 | 302 | void SliderFloatMini(const char* label, float* v, float v_min, float v_max) 303 | { 304 | const float sliderWidth = 100.0f; 305 | const float sliderHeight = 10.0f; 306 | const float gap = 5.0f; 307 | const float moveUpOffset = 0.0f; 308 | std::string sliderID = "##sliderID_" + std::string(label); 309 | 310 | int id = ImGui::GetID(label); 311 | 312 | ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 5); 313 | 314 | ImU32 textColor = IM_COL32(InactiveTextColor[0], InactiveTextColor[1], InactiveTextColor[2], 255); 315 | ImGui::PushStyleColor(ImGuiCol_Text, textColor); 316 | 317 | ImGui::TextUnformatted(label); 318 | 319 | ImGui::PopStyleColor(); 320 | ImGui::SameLine(); 321 | 322 | ImVec2 windowPos = ImGui::GetWindowPos(); 323 | ImVec2 windowSize = ImGui::GetWindowSize(); 324 | 325 | float sliderPosX = windowPos.x + windowSize.x - sliderWidth - gap; 326 | float sliderPosY = ImGui::GetCursorScreenPos().y - moveUpOffset; 327 | 328 | ImGui::SetCursorScreenPos(ImVec2(sliderPosX, sliderPosY)); 329 | 330 | ImGui::SetNextItemWidth(sliderWidth); 331 | ImGui::SliderFloat(sliderID.c_str(), v, v_min, v_max); 332 | } 333 | 334 | void SliderIntMini(const char* label, int* v, int v_min, int v_max) 335 | { 336 | const float sliderWidth = 100.0f; 337 | const float sliderHeight = 10.0f; 338 | const float gap = 5.0f; 339 | const float moveUpOffset = 0.0f; 340 | std::string sliderID = "##intSliderID_" + std::string(label); 341 | 342 | int id = ImGui::GetID(label); 343 | 344 | ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 5); 345 | 346 | ImU32 textColor = IM_COL32(InactiveTextColor[0], InactiveTextColor[1], InactiveTextColor[2], 255); 347 | ImGui::PushStyleColor(ImGuiCol_Text, textColor); 348 | 349 | ImGui::TextUnformatted(label); 350 | 351 | ImGui::PopStyleColor(); 352 | ImGui::SameLine(); 353 | 354 | ImVec2 windowPos = ImGui::GetWindowPos(); 355 | ImVec2 windowSize = ImGui::GetWindowSize(); 356 | 357 | float sliderPosX = windowPos.x + windowSize.x - sliderWidth - gap; 358 | float sliderPosY = ImGui::GetCursorScreenPos().y - moveUpOffset; 359 | 360 | ImGui::SetCursorScreenPos(ImVec2(sliderPosX, sliderPosY)); 361 | 362 | ImGui::SetNextItemWidth(sliderWidth); 363 | ImGui::SliderInt(sliderID.c_str(), v, v_min, v_max); 364 | } 365 | 366 | void IntInputMini(const char* label, int* v, int v_min, int v_max) 367 | { 368 | const float inputWidth = 100.0f; 369 | const float gap = 5.0f; 370 | const float labelOffset = 10.0f; 371 | const float verticalOffset = -18.0f; 372 | 373 | std::string intInputID = "##intInputID_" + std::string(label); 374 | 375 | ImGui::SetCursorPosX(ImGui::GetCursorPosX() + gap); 376 | 377 | ImU32 textColor = IM_COL32(InactiveTextColor[0], InactiveTextColor[1], InactiveTextColor[2], 255); 378 | ImGui::PushStyleColor(ImGuiCol_Text, textColor); 379 | 380 | ImGui::TextUnformatted(label); 381 | 382 | ImGui::PopStyleColor(); 383 | 384 | float contentWidth = ImGui::GetContentRegionAvail().x; 385 | 386 | ImGui::SetCursorPosX(contentWidth - inputWidth - 5); 387 | 388 | ImGui::SetCursorPosY(ImGui::GetCursorPosY() + verticalOffset); 389 | 390 | ImGui::SetNextItemWidth(inputWidth); 391 | 392 | ImGui::InputInt(intInputID.c_str(), v, 1, 100, ImGuiInputTextFlags_CharsDecimal); 393 | 394 | if (*v < v_min) *v = v_min; 395 | if (*v > v_max) *v = v_max; 396 | } 397 | 398 | bool TextInputMini(const char* label, std::string& text, bool integerOnly) 399 | { 400 | const float inputWidth = 100.0f; 401 | const float gap = 5.0f; 402 | const float verticalOffset = -18.0f; 403 | 404 | // Create a unique ID using both the label and the memory address of the text string 405 | std::string textInputID = "##textInput_" + std::string(label) + "_" + std::to_string((uintptr_t)&text); 406 | 407 | ImGui::SetCursorPosX(ImGui::GetCursorPosX() + gap); 408 | 409 | ImU32 textColor = IM_COL32(InactiveTextColor[0], InactiveTextColor[1], InactiveTextColor[2], 255); 410 | ImGui::PushStyleColor(ImGuiCol_Text, textColor); 411 | 412 | ImGui::TextUnformatted(label); 413 | ImGui::PopStyleColor(); 414 | 415 | float contentWidth = ImGui::GetContentRegionAvail().x; 416 | ImGui::SetCursorPosX(contentWidth - inputWidth - gap); 417 | ImGui::SetCursorPosY(ImGui::GetCursorPosY() + verticalOffset); 418 | 419 | ImGui::SetNextItemWidth(inputWidth); 420 | 421 | // Create a buffer for the input text 422 | static std::unordered_map buffers; 423 | if (buffers.find(textInputID) == buffers.end()) { 424 | strcpy(buffers[textInputID], text.c_str()); 425 | } 426 | 427 | ImGuiInputTextFlags flags = ImGuiInputTextFlags_None; 428 | if (integerOnly) 429 | flags |= ImGuiInputTextFlags_CharsDecimal; 430 | 431 | bool changed = ImGui::InputText(textInputID.c_str(), buffers[textInputID], 256, flags); 432 | 433 | if (changed) 434 | text = buffers[textInputID]; 435 | 436 | return changed; 437 | } 438 | 439 | Console* Console::instance = nullptr; 440 | 441 | std::string Console::getCurrentTime() { 442 | auto now = std::chrono::system_clock::now(); 443 | std::time_t now_time = std::chrono::system_clock::to_time_t(now); 444 | std::tm* tm = std::localtime(&now_time); 445 | 446 | std::ostringstream oss; 447 | oss << std::put_time(tm, "%H:%M:%S"); 448 | return oss.str(); 449 | } 450 | 451 | void Console::logInternal(const std::string& text, bool printTime, int type) { 452 | Output output{text, printTime, type}; 453 | if (printTime) { 454 | output.time = getCurrentTime(); 455 | } 456 | outputArr.push_back(output); 457 | } 458 | 459 | void Console::renderLog(Output& output) { 460 | if (output.type != 0) return; 461 | std::string print = output.text; 462 | if (output.drawTime) print = "[" + output.time + "] " + print; 463 | ImGui::TextUnformatted(print.c_str()); 464 | } 465 | 466 | void Console::renderLogError(Output& output) { 467 | if (output.type != 1) return; 468 | std::string print = output.text; 469 | if (output.drawTime) print = "[" + output.time + "] " ICON_FA_TIMES_CIRCLE " " + print; 470 | ImVec4 color = ImVec4(1.0f, 0.6f, 0.67f, 1.0f); 471 | 472 | ImGui::PushStyleColor(ImGuiCol_Text, color); 473 | ImGui::TextUnformatted(print.c_str()); 474 | ImGui::PopStyleColor(); 475 | } 476 | 477 | void Console::renderLogInfo(Output& output) { 478 | if (output.type != 2) return; 479 | std::string print = output.text; 480 | if (output.drawTime) print = "[" + output.time + "] " ICON_FA_INFO_CIRCLE " " + print; 481 | ImVec4 color = ImVec4(0.48f, 0.79f, 0.95f, 1.0f); 482 | 483 | ImGui::PushStyleColor(ImGuiCol_Text, color); 484 | ImGui::TextUnformatted(print.c_str()); 485 | ImGui::PopStyleColor(); 486 | } 487 | 488 | void Console::renderLogSuccess(Output& output) { 489 | if (output.type != 3) return; 490 | std::string print = output.text; 491 | if (output.drawTime) print = "[" + output.time + "] " ICON_FA_CHECK_CIRCLE " " + print; 492 | ImVec4 color = ImVec4(80.0f / 255.0f, 200.0f / 255.0f, 120.0f / 255.0f, 1.0f); 493 | 494 | ImGui::PushStyleColor(ImGuiCol_Text, color); 495 | ImGui::TextUnformatted(print.c_str()); 496 | ImGui::PopStyleColor(); 497 | } 498 | 499 | void Console::renderLogWarning(Output& output) { 500 | if (output.type != 4) return; 501 | std::string print = output.text; 502 | if (output.drawTime) print = "[" + output.time + "] " ICON_FA_EXCLAMATION_TRIANGLE " " + print; 503 | ImVec4 color = ImVec4(255.0f / 255.0f, 234.0f / 255.0f, 0.0f / 255.0f, 1.0f); 504 | 505 | ImGui::PushStyleColor(ImGuiCol_Text, color); 506 | ImGui::TextUnformatted(print.c_str()); 507 | ImGui::PopStyleColor(); 508 | } 509 | 510 | void Console::renderInternal() { 511 | if (!DRAW_CONSOLE) return; 512 | ImGui::PushStyleColor(ImGuiCol_ChildBg, IM_COL32(ChildColor[0], ChildColor[1], ChildColor[2], animation_text)); 513 | 514 | ImGui::BeginChild("Console", ImVec2(0, 200), true); 515 | 516 | ImVec2 titleBarSize = ImVec2(ImGui::GetContentRegionAvail().x, 25); 517 | ImVec2 titleBarPos = ImGui::GetCursorScreenPos(); 518 | 519 | float rounding = 5.0f; 520 | ImGui::GetWindowDrawList() -> AddRectFilled( 521 | titleBarPos, 522 | ImVec2(titleBarPos.x + titleBarSize.x, titleBarPos.y + titleBarSize.y), 523 | IM_COL32(IconChildColor[0], IconChildColor[1], IconChildColor[2], animation_text), 524 | rounding, 525 | ImDrawFlags_RoundCornersTop 526 | ); 527 | 528 | std::string titleText = "Menu Logs"; 529 | 530 | ImVec2 textSize = ImGui::CalcTextSize(titleText.c_str()); 531 | 532 | float textX = titleBarPos.x + (titleBarSize.x - textSize.x) / 2.0f; 533 | ImGui::SetCursorScreenPos(ImVec2(textX, titleBarPos.y + (titleBarSize.y - textSize.y) / 2.0f)); 534 | 535 | ImGui::TextUnformatted(titleText.c_str()); 536 | ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 5); 537 | ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 5); 538 | 539 | const float footer_height_to_reserve = ImGui::GetStyle().ItemSpacing.y + ImGui::GetFrameHeightWithSpacing(); 540 | ImGui::BeginChild("ScrollingRegion", ImVec2(0, -footer_height_to_reserve), true); 541 | ImGui::SetWindowFontScale(0.9f); 542 | 543 | for (auto& output : outputArr) { 544 | if (selectedTypeTab == 0) { 545 | renderLog(output); 546 | renderLogError(output); 547 | renderLogInfo(output); 548 | renderLogSuccess(output); 549 | renderLogWarning(output); 550 | } else if (selectedTypeTab == 1) { 551 | renderLogError(output); 552 | } else if (selectedTypeTab == 2) { 553 | renderLogInfo(output); 554 | } else if (selectedTypeTab == 3) { 555 | renderLogSuccess(output); 556 | } else if (selectedTypeTab == 4) { 557 | renderLogWarning(output); 558 | } 559 | } 560 | 561 | if (ImGui::GetScrollY() >= ImGui::GetScrollMaxY()) ImGui::SetScrollHereY(1.0f); 562 | ImGui::SetWindowFontScale(1.0f); 563 | ImGui::EndChild(); 564 | ImGui::Separator(); 565 | 566 | bool reclaim_focus = false; 567 | ImGuiInputTextFlags input_text_flags = ImGuiInputTextFlags_EnterReturnsTrue; 568 | if (reclaim_focus) ImGui::SetKeyboardFocusHere(-1); 569 | 570 | ImGui::EndChild(); 571 | ImGui::PopStyleColor(); 572 | } 573 | -------------------------------------------------------------------------------- /ImGui/ImGuiDrawViewX.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #include "../ImGui/imgui.h" 4 | #include "../ImGui/imgui_internal.h" 5 | #include "../ImGui/imgui_impl_metal.h" 6 | 7 | @interface ImGuiDrawViewX : UIViewController 8 | 9 | + (void)showChange:(BOOL)open; 10 | + (BOOL)isMenuShowing; 11 | - (void)updateIOWithTouchEvent:(UIEvent *)event; 12 | 13 | @property (nonatomic, assign) BOOL isKeyboardVisible; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /ImGui/ImGuiDrawViewX.mm: -------------------------------------------------------------------------------- 1 | #import "ImGuiDrawViewX.h" 2 | #include "../Includes/Fonts/Fonts.hpp" 3 | #include "../Menu.h" 4 | #include "MenuUtils.h" 5 | 6 | @interface ImGuiDrawViewX () 7 | @property (nonatomic, strong) id device; 8 | @property (nonatomic, strong) id commandQueue; 9 | 10 | @end 11 | 12 | @implementation ImGuiDrawViewX 13 | 14 | static BOOL menuVisible = YES; 15 | extern MenuInteraction* menuTouchView; 16 | 17 | - (instancetype)initWithNibName:(nullable NSString *)nibNameOrNil bundle:(nullable NSBundle *)nibBundleOrNil { 18 | self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; 19 | 20 | if (self) { 21 | _device = MTLCreateSystemDefaultDevice(); 22 | _commandQueue = [_device newCommandQueue]; 23 | 24 | if (!_device) { 25 | abort(); 26 | } 27 | 28 | [self setupImGuiContext]; 29 | } 30 | 31 | return self; 32 | } 33 | 34 | - (void)setupImGuiContext { 35 | IMGUI_CHECKVERSION(); 36 | ImGui::CreateContext(); 37 | ImGui::StyleColorsDark(); 38 | 39 | ImGuiIO& io = ImGui::GetIO(); 40 | io.KeyMap[ImGuiKey_Backspace] = 8; 41 | 42 | [self addFontsToImGui:io]; 43 | ImGui_ImplMetal_Init(_device); 44 | } 45 | 46 | - (void)addFontsToImGui:(ImGuiIO&)io { 47 | io.Fonts->Clear(); 48 | 49 | ImFontConfig poppinsConfig; 50 | poppinsConfig.FontDataOwnedByAtlas = NO; 51 | io.Fonts->AddFontFromMemoryTTF((void*)poppinsFont, sizeof(poppinsFont), 18, &poppinsConfig); 52 | 53 | static const ImWchar iconsRanges[] = { ICON_MIN_FA, ICON_MAX_FA, 0 }; 54 | ImFontConfig iconsConfig; 55 | iconsConfig.MergeMode = YES; 56 | iconsConfig.PixelSnapH = YES; 57 | iconsConfig.FontDataOwnedByAtlas = NO; 58 | io.Fonts->AddFontFromMemoryTTF((void*)fontAwesome, sizeof(fontAwesome), 18, &iconsConfig, iconsRanges); 59 | } 60 | 61 | + (void)showChange:(BOOL)open { 62 | menuVisible = open; 63 | } 64 | 65 | + (BOOL)isMenuShowing { 66 | return menuVisible; 67 | } 68 | 69 | - (MTKView *)mtkView { 70 | return (MTKView *)self.view; 71 | } 72 | 73 | - (void)loadView { 74 | CGRect frame = [UIScreen mainScreen].bounds; 75 | self.view = [[MTKView alloc] initWithFrame:frame]; 76 | } 77 | 78 | - (void)viewDidLoad { 79 | [super viewDidLoad]; 80 | 81 | self.mtkView.device = self.device; 82 | self.mtkView.delegate = self; 83 | self.mtkView.clearColor = MTLClearColorMake(0, 0, 0, 0); 84 | self.mtkView.backgroundColor = [UIColor clearColor]; 85 | self.mtkView.clipsToBounds = YES; 86 | 87 | // Add keyboard notifications 88 | [[NSNotificationCenter defaultCenter] addObserver:self 89 | selector:@selector(keyboardWillShow:) 90 | name:UIKeyboardWillShowNotification 91 | object:nil]; 92 | [[NSNotificationCenter defaultCenter] addObserver:self 93 | selector:@selector(keyboardWillHide:) 94 | name:UIKeyboardWillHideNotification 95 | object:nil]; 96 | } 97 | 98 | #pragma mark - Interaction 99 | 100 | - (void)updateIOWithTouchEvent:(UIEvent *)event { 101 | UITouch *touch = event.allTouches.anyObject; 102 | CGPoint touchLocation = [touch locationInView:self.view]; 103 | 104 | ImGuiIO &io = ImGui::GetIO(); 105 | io.MousePos = ImVec2(touchLocation.x, touchLocation.y); 106 | io.MouseDown[0] = (touch.phase != UITouchPhaseEnded && touch.phase != UITouchPhaseCancelled); 107 | 108 | if (touch.phase == UITouchPhaseBegan && self.isKeyboardVisible) { 109 | if (!io.WantTextInput) { 110 | [self resignFirstResponder]; 111 | self.isKeyboardVisible = NO; 112 | } 113 | } 114 | 115 | if (io.WantTextInput && !self.isKeyboardVisible) { 116 | [self becomeFirstResponder]; 117 | } 118 | } 119 | 120 | - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { 121 | [self updateIOWithTouchEvent:event]; 122 | } 123 | 124 | - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { 125 | [self updateIOWithTouchEvent:event]; 126 | } 127 | 128 | - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { 129 | [self updateIOWithTouchEvent:event]; 130 | } 131 | 132 | - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { 133 | [self updateIOWithTouchEvent:event]; 134 | } 135 | 136 | - (void)drawInMTKView:(MTKView *)view { 137 | hideRecordTextfield.secureTextEntry = StreamerMode; 138 | 139 | ImGuiIO &io = ImGui::GetIO(); 140 | io.DisplaySize = ImVec2(view.bounds.size.width, view.bounds.size.height); 141 | 142 | CGFloat framebufferScale = view.window.screen.nativeScale ?: UIScreen.mainScreen.nativeScale; 143 | io.DisplayFramebufferScale = ImVec2(framebufferScale, framebufferScale); 144 | io.DeltaTime = 1.0f / (float)(view.preferredFramesPerSecond ?: 60); 145 | 146 | id commandBuffer = [self.commandQueue commandBuffer]; 147 | 148 | [self updateUserInteractionEnabled]; 149 | 150 | MTLRenderPassDescriptor *renderPassDescriptor = view.currentRenderPassDescriptor; 151 | if (renderPassDescriptor) { 152 | id renderEncoder = [commandBuffer renderCommandEncoderWithDescriptor:renderPassDescriptor]; 153 | [renderEncoder pushDebugGroup:@"iOSImGui"]; 154 | 155 | ImGui_ImplMetal_NewFrame(renderPassDescriptor); 156 | ImGui::NewFrame(); 157 | SetStyles(); 158 | 159 | if (menuVisible) { 160 | 161 | ImGui::Begin("##Noname", NULL, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoCollapse); 162 | MenuOrigin = ImGui::GetWindowPos(); 163 | MenuSize = ImGui::GetWindowSize(); 164 | LoadMenu(); 165 | ImGui::End(); 166 | //ImGui::ShowDemoWindow(); 167 | } 168 | ImGui::EndFrame(); 169 | ImGui::Render(); 170 | ImDrawData *drawData = ImGui::GetDrawData(); 171 | ImGui_ImplMetal_RenderDrawData(drawData, commandBuffer, renderEncoder); 172 | 173 | [renderEncoder popDebugGroup]; 174 | [renderEncoder endEncoding]; 175 | [commandBuffer presentDrawable:view.currentDrawable]; 176 | } 177 | 178 | [commandBuffer commit]; 179 | } 180 | 181 | - (void)updateUserInteractionEnabled { 182 | BOOL isEnabled = menuVisible; 183 | [self.view setUserInteractionEnabled:isEnabled]; 184 | [self.view.superview setUserInteractionEnabled:isEnabled]; 185 | [menuTouchView setUserInteractionEnabled:isEnabled]; 186 | } 187 | 188 | - (void)mtkView:(MTKView *)view drawableSizeWillChange:(CGSize)size { 189 | 190 | } 191 | 192 | - (BOOL)hasText { 193 | return YES; 194 | } 195 | 196 | - (void)insertText:(NSString *)text { 197 | if ([text isEqualToString:@"\n"]) { 198 | [self resignFirstResponder]; 199 | self.isKeyboardVisible = NO; 200 | 201 | ImGui::SetWindowFocus(NULL); 202 | return; 203 | } 204 | 205 | ImGuiIO &io = ImGui::GetIO(); 206 | NSData *data = [text dataUsingEncoding:NSUTF8StringEncoding]; 207 | io.AddInputCharactersUTF8((const char*)[data bytes]); 208 | } 209 | 210 | - (void)deleteBackward { 211 | ImGuiIO& io = ImGui::GetIO(); 212 | 213 | io.KeysDown[io.KeyMap[ImGuiKey_Backspace]] = true; 214 | io.KeysDown[8] = true; 215 | 216 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.016 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 217 | io.KeysDown[io.KeyMap[ImGuiKey_Backspace]] = false; 218 | io.KeysDown[8] = false; 219 | }); 220 | } 221 | 222 | - (BOOL)canBecomeFirstResponder { 223 | return YES; 224 | } 225 | 226 | - (void)keyboardWillShow:(NSNotification *)notification { 227 | self.isKeyboardVisible = YES; 228 | } 229 | 230 | - (void)keyboardWillHide:(NSNotification *)notification { 231 | self.isKeyboardVisible = NO; 232 | } 233 | 234 | - (void)dealloc { 235 | [[NSNotificationCenter defaultCenter] removeObserver:self]; 236 | } 237 | 238 | - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string { 239 | if ([string isEqualToString:@"\n"]) { 240 | [self resignFirstResponder]; 241 | self.isKeyboardVisible = NO; 242 | return NO; 243 | } 244 | return YES; 245 | } 246 | 247 | @end 248 | -------------------------------------------------------------------------------- /ImGui/MenuUtils.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface MenuUtils : NSObject 4 | 5 | @end 6 | 7 | @interface MenuInteraction : UIView 8 | 9 | @end -------------------------------------------------------------------------------- /ImGui/MenuUtils.mm: -------------------------------------------------------------------------------- 1 | #include "ImGuiDrawViewX.h" 2 | #include "MenuUtils.h" 3 | #define SCREEN_WIDTH [UIScreen mainScreen].bounds.size.width 4 | #define timer(sec) dispatch_after(dispatch_time(DISPATCH_TIME_NOW, sec * NSEC_PER_SEC), dispatch_get_main_queue(), ^ 5 | 6 | @interface MenuUtils() 7 | @property (nonatomic, strong) ImGuiDrawViewX *vna; 8 | - (ImGuiDrawViewX*) GetImGuiView; 9 | @end 10 | 11 | static MenuUtils *extraInfo; 12 | ImVec2 MenuOrigin = {(float)SCREEN_WIDTH - 400, 0}; 13 | ImVec2 MenuSize = {400, 260}; 14 | 15 | UIButton* InvisibleMenuButton; 16 | UIButton* VisibleMenuButton; 17 | MenuInteraction* menuTouchView; 18 | UITextField* hideRecordTextfield; 19 | UIView* hideRecordView; 20 | bool StreamerMode = false; 21 | bool MoveMenu = true; 22 | 23 | extern NSString* baseimage; 24 | 25 | @interface MenuInteraction() 26 | @end 27 | @implementation MenuInteraction 28 | - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event { 29 | CGRect touchableArea = CGRectMake(MenuOrigin.x, MenuOrigin.y, MenuSize.x, MenuSize.y); 30 | if (CGRectContainsPoint(touchableArea, point)) { 31 | return [super pointInside:point withEvent:event]; 32 | } 33 | return NO; 34 | } 35 | - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { 36 | [[extraInfo GetImGuiView] updateIOWithTouchEvent:event]; 37 | } 38 | - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { 39 | [[extraInfo GetImGuiView] updateIOWithTouchEvent:event]; 40 | } 41 | - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { 42 | [[extraInfo GetImGuiView] updateIOWithTouchEvent:event]; 43 | } 44 | - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { 45 | [[extraInfo GetImGuiView] updateIOWithTouchEvent:event]; 46 | } 47 | @end 48 | 49 | 50 | @implementation MenuUtils 51 | bool isOpened = false; 52 | 53 | - (ImGuiDrawViewX*) GetImGuiView 54 | { 55 | return _vna; 56 | } 57 | + (void)load 58 | { 59 | [super load]; 60 | timer(3){ 61 | extraInfo = [MenuUtils new]; 62 | [extraInfo initTapGes]; 63 | }); 64 | } 65 | -(void)initTapGes 66 | { 67 | UIView* mainView = [UIApplication sharedApplication].windows[0].rootViewController.view; 68 | 69 | hideRecordTextfield = [[UITextField alloc] init]; 70 | hideRecordView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, UIScreen.mainScreen.bounds.size.width, UIScreen.mainScreen.bounds.size.height)]; 71 | [hideRecordView setBackgroundColor:[UIColor clearColor]]; 72 | [hideRecordView setUserInteractionEnabled:YES]; 73 | hideRecordTextfield.secureTextEntry = true; 74 | [hideRecordView addSubview:hideRecordTextfield]; 75 | CALayer *layer = hideRecordTextfield.layer; 76 | if ([layer.sublayers.firstObject.delegate isKindOfClass:[UIView class]]) { 77 | hideRecordView = (UIView *)layer.sublayers.firstObject.delegate; 78 | } else { 79 | hideRecordView = nil; 80 | } 81 | 82 | [[UIApplication sharedApplication].keyWindow addSubview:hideRecordView]; 83 | 84 | if (!_vna) { 85 | ImGuiDrawViewX *vc = [[ImGuiDrawViewX alloc] init]; 86 | _vna = vc; 87 | } 88 | 89 | [ImGuiDrawViewX showChange:false]; 90 | [hideRecordView addSubview:_vna.view]; 91 | 92 | menuTouchView = [[MenuInteraction alloc] initWithFrame:mainView.frame]; 93 | [[UIApplication sharedApplication].windows[0].rootViewController.view addSubview:menuTouchView]; 94 | 95 | NSData* data = [[NSData alloc] initWithBase64EncodedString:baseimage options:0]; 96 | UIImage* menuIconImage = [UIImage imageWithData:data]; 97 | 98 | InvisibleMenuButton = [UIButton buttonWithType:UIButtonTypeRoundedRect]; 99 | InvisibleMenuButton.frame = CGRectMake(mainView.frame.size.width / 2, mainView.frame.size.height / 2, 50, 50); 100 | InvisibleMenuButton.backgroundColor = [UIColor clearColor]; 101 | [InvisibleMenuButton addTarget:self action:@selector(buttonDragged:withEvent:) forControlEvents:UIControlEventTouchDragInside]; 102 | [InvisibleMenuButton addTarget:self action:@selector(buttonDragEnded:) forControlEvents:UIControlEventTouchUpInside]; 103 | [InvisibleMenuButton addTarget:self action:@selector(buttonDragEnded:) forControlEvents:UIControlEventTouchUpOutside]; 104 | [InvisibleMenuButton addTarget:self action:@selector(buttonDragStarted:) forControlEvents:UIControlEventTouchDown]; 105 | UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(showMenu:)]; 106 | [InvisibleMenuButton addGestureRecognizer:tapGestureRecognizer]; 107 | [[UIApplication sharedApplication].windows[0].rootViewController.view addSubview:InvisibleMenuButton]; 108 | 109 | VisibleMenuButton = [UIButton buttonWithType:UIButtonTypeRoundedRect]; 110 | VisibleMenuButton.frame = CGRectMake(mainView.frame.size.width / 2, mainView.frame.size.height / 2, 50, 50); 111 | VisibleMenuButton.backgroundColor = [UIColor clearColor]; 112 | VisibleMenuButton.layer.cornerRadius = VisibleMenuButton.frame.size.width * 0.5f; 113 | [VisibleMenuButton setBackgroundImage:menuIconImage forState:UIControlStateNormal]; 114 | VisibleMenuButton.layer.opacity = 0.7; 115 | [hideRecordView addSubview:VisibleMenuButton]; 116 | } 117 | 118 | -(void)showMenu:(UITapGestureRecognizer *)tapGestureRecognizer { 119 | if(tapGestureRecognizer.state == UIGestureRecognizerStateEnded) { 120 | [UIView animateWithDuration:0.2 animations:^{ 121 | VisibleMenuButton.transform = CGAffineTransformMakeScale(1.2, 1.2); 122 | }]; 123 | 124 | [UIView animateWithDuration:0.2 delay:0.2 options:UIViewAnimationOptionCurveEaseInOut animations:^{ 125 | VisibleMenuButton.transform = CGAffineTransformIdentity; 126 | } completion:nil]; 127 | 128 | [ImGuiDrawViewX showChange:![ImGuiDrawViewX isMenuShowing]]; 129 | } 130 | } 131 | 132 | - (void)buttonDragged:(UIButton *)button withEvent:(UIEvent *)event { 133 | UITouch *touch = [[event touchesForView:button] anyObject]; 134 | 135 | CGPoint previousLocation = [touch previousLocationInView:button]; 136 | CGPoint location = [touch locationInView:button]; 137 | CGFloat delta_x = location.x - previousLocation.x; 138 | CGFloat delta_y = location.y - previousLocation.y; 139 | 140 | button.center = CGPointMake(button.center.x + delta_x, button.center.y + delta_y); 141 | 142 | CGRect mainFrame = [UIApplication sharedApplication].windows[0].rootViewController.view.bounds; 143 | if (button.center.x < 0) button.center = CGPointMake(0, button.center.y); 144 | if (button.center.y < 0) button.center = CGPointMake(button.center.x, 0); 145 | if (button.center.y > mainFrame.size.height) button.center = CGPointMake(button.center.x, mainFrame.size.height); 146 | if (button.center.x > mainFrame.size.width) button.center = CGPointMake(mainFrame.size.width, button.center.y); 147 | 148 | VisibleMenuButton.center = button.center; 149 | VisibleMenuButton.frame = button.frame; 150 | VisibleMenuButton.layer.opacity = 1.0; 151 | } 152 | 153 | - (void)buttonDragStarted:(UIButton *)button { 154 | [UIView animateWithDuration:0.2 animations:^{ 155 | button.transform = CGAffineTransformMakeScale(1.2, 1.2); 156 | VisibleMenuButton.transform = button.transform; 157 | }]; 158 | } 159 | 160 | - (void)buttonDragEnded:(UIButton *)button { 161 | [UIView animateWithDuration:0.2 animations:^{ 162 | button.transform = CGAffineTransformIdentity; 163 | VisibleMenuButton.transform = button.transform; 164 | VisibleMenuButton.layer.opacity = 0.7; 165 | }]; 166 | } 167 | 168 | @end 169 | -------------------------------------------------------------------------------- /ImGui/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 | -------------------------------------------------------------------------------- /ImGui/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 | -------------------------------------------------------------------------------- /ImGui/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 | textureDescriptor.usage = MTLTextureUsageShaderRead; 243 | #if TARGET_OS_OSX || TARGET_OS_MACCATALYST 244 | textureDescriptor.storageMode = MTLStorageModeManaged; 245 | #else 246 | textureDescriptor.storageMode = MTLStorageModeShared; 247 | #endif 248 | id texture = [device newTextureWithDescriptor:textureDescriptor]; 249 | [texture replaceRegion:MTLRegionMake2D(0, 0, (NSUInteger)width, (NSUInteger)height) mipmapLevel:0 withBytes:pixels bytesPerRow:(NSUInteger)width * 4]; 250 | self.fontTexture = texture; 251 | } 252 | 253 | - (MetalBuffer *)dequeueReusableBufferOfLength:(NSUInteger)length device:(id)device 254 | { 255 | NSTimeInterval now = [NSDate date].timeIntervalSince1970; 256 | 257 | // Purge old buffers that haven't been useful for a while 258 | if (now - self.lastBufferCachePurge > 1.0) 259 | { 260 | NSMutableArray *survivors = [NSMutableArray array]; 261 | for (MetalBuffer *candidate in self.bufferCache) 262 | { 263 | if (candidate.lastReuseTime > self.lastBufferCachePurge) 264 | { 265 | [survivors addObject:candidate]; 266 | } 267 | } 268 | self.bufferCache = [survivors mutableCopy]; 269 | self.lastBufferCachePurge = now; 270 | } 271 | 272 | // See if we have a buffer we can reuse 273 | MetalBuffer *bestCandidate = nil; 274 | for (MetalBuffer *candidate in self.bufferCache) 275 | if (candidate.buffer.length >= length && (bestCandidate == nil || bestCandidate.lastReuseTime > candidate.lastReuseTime)) 276 | bestCandidate = candidate; 277 | 278 | if (bestCandidate != nil) 279 | { 280 | [self.bufferCache removeObject:bestCandidate]; 281 | bestCandidate.lastReuseTime = now; 282 | return bestCandidate; 283 | } 284 | 285 | // No luck; make a new buffer 286 | id backing = [device newBufferWithLength:length options:MTLResourceStorageModeShared]; 287 | return [[MetalBuffer alloc] initWithBuffer:backing]; 288 | } 289 | 290 | - (void)enqueueReusableBuffer:(MetalBuffer *)buffer 291 | { 292 | [self.bufferCache addObject:buffer]; 293 | } 294 | 295 | - (_Nullable id)renderPipelineStateForFrameAndDevice:(id)device 296 | { 297 | // Try to retrieve a render pipeline state that is compatible with the framebuffer config for this frame 298 | // The hit rate for this cache should be very near 100%. 299 | id renderPipelineState = self.renderPipelineStateCache[self.framebufferDescriptor]; 300 | 301 | if (renderPipelineState == nil) 302 | { 303 | // No luck; make a new render pipeline state 304 | renderPipelineState = [self _renderPipelineStateForFramebufferDescriptor:self.framebufferDescriptor device:device]; 305 | // Cache render pipeline state for later reuse 306 | self.renderPipelineStateCache[self.framebufferDescriptor] = renderPipelineState; 307 | } 308 | 309 | return renderPipelineState; 310 | } 311 | 312 | - (id)_renderPipelineStateForFramebufferDescriptor:(FramebufferDescriptor *)descriptor device:(id)device 313 | { 314 | NSError *error = nil; 315 | 316 | NSString *shaderSource = @"" 317 | "#include \n" 318 | "using namespace metal;\n" 319 | "\n" 320 | "struct Uniforms {\n" 321 | " float4x4 projectionMatrix;\n" 322 | "};\n" 323 | "\n" 324 | "struct VertexIn {\n" 325 | " float2 position [[attribute(0)]];\n" 326 | " float2 texCoords [[attribute(1)]];\n" 327 | " uchar4 color [[attribute(2)]];\n" 328 | "};\n" 329 | "\n" 330 | "struct VertexOut {\n" 331 | " float4 position [[position]];\n" 332 | " float2 texCoords;\n" 333 | " float4 color;\n" 334 | "};\n" 335 | "\n" 336 | "vertex VertexOut vertex_main(VertexIn in [[stage_in]],\n" 337 | " constant Uniforms &uniforms [[buffer(1)]]) {\n" 338 | " VertexOut out;\n" 339 | " out.position = uniforms.projectionMatrix * float4(in.position, 0, 1);\n" 340 | " out.texCoords = in.texCoords;\n" 341 | " out.color = float4(in.color) / float4(255.0);\n" 342 | " return out;\n" 343 | "}\n" 344 | "\n" 345 | "fragment half4 fragment_main(VertexOut in [[stage_in]],\n" 346 | " texture2d texture [[texture(0)]]) {\n" 347 | " constexpr sampler linearSampler(coord::normalized, min_filter::linear, mag_filter::linear, mip_filter::linear);\n" 348 | " half4 texColor = texture.sample(linearSampler, in.texCoords);\n" 349 | " return half4(in.color) * texColor;\n" 350 | "}\n"; 351 | 352 | id library = [device newLibraryWithSource:shaderSource options:nil error:&error]; 353 | if (library == nil) 354 | { 355 | NSLog(@"Error: failed to create Metal library: %@", error); 356 | return nil; 357 | } 358 | 359 | id vertexFunction = [library newFunctionWithName:@"vertex_main"]; 360 | id fragmentFunction = [library newFunctionWithName:@"fragment_main"]; 361 | 362 | if (vertexFunction == nil || fragmentFunction == nil) 363 | { 364 | NSLog(@"Error: failed to find Metal shader functions in library: %@", error); 365 | return nil; 366 | } 367 | 368 | MTLVertexDescriptor *vertexDescriptor = [MTLVertexDescriptor vertexDescriptor]; 369 | vertexDescriptor.attributes[0].offset = IM_OFFSETOF(ImDrawVert, pos); 370 | vertexDescriptor.attributes[0].format = MTLVertexFormatFloat2; // position 371 | vertexDescriptor.attributes[0].bufferIndex = 0; 372 | vertexDescriptor.attributes[1].offset = IM_OFFSETOF(ImDrawVert, uv); 373 | vertexDescriptor.attributes[1].format = MTLVertexFormatFloat2; // texCoords 374 | vertexDescriptor.attributes[1].bufferIndex = 0; 375 | vertexDescriptor.attributes[2].offset = IM_OFFSETOF(ImDrawVert, col); 376 | vertexDescriptor.attributes[2].format = MTLVertexFormatUChar4; // color 377 | vertexDescriptor.attributes[2].bufferIndex = 0; 378 | vertexDescriptor.layouts[0].stepRate = 1; 379 | vertexDescriptor.layouts[0].stepFunction = MTLVertexStepFunctionPerVertex; 380 | vertexDescriptor.layouts[0].stride = sizeof(ImDrawVert); 381 | 382 | MTLRenderPipelineDescriptor *pipelineDescriptor = [[MTLRenderPipelineDescriptor alloc] init]; 383 | pipelineDescriptor.vertexFunction = vertexFunction; 384 | pipelineDescriptor.fragmentFunction = fragmentFunction; 385 | pipelineDescriptor.vertexDescriptor = vertexDescriptor; 386 | pipelineDescriptor.sampleCount = self.framebufferDescriptor.sampleCount; 387 | pipelineDescriptor.colorAttachments[0].pixelFormat = self.framebufferDescriptor.colorPixelFormat; 388 | pipelineDescriptor.colorAttachments[0].blendingEnabled = YES; 389 | pipelineDescriptor.colorAttachments[0].rgbBlendOperation = MTLBlendOperationAdd; 390 | pipelineDescriptor.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactorSourceAlpha; 391 | pipelineDescriptor.colorAttachments[0].destinationRGBBlendFactor = MTLBlendFactorOneMinusSourceAlpha; 392 | pipelineDescriptor.colorAttachments[0].alphaBlendOperation = MTLBlendOperationAdd; 393 | pipelineDescriptor.colorAttachments[0].sourceAlphaBlendFactor = MTLBlendFactorOne; 394 | pipelineDescriptor.colorAttachments[0].destinationAlphaBlendFactor = MTLBlendFactorOneMinusSourceAlpha; 395 | pipelineDescriptor.depthAttachmentPixelFormat = self.framebufferDescriptor.depthPixelFormat; 396 | pipelineDescriptor.stencilAttachmentPixelFormat = self.framebufferDescriptor.stencilPixelFormat; 397 | 398 | id renderPipelineState = [device newRenderPipelineStateWithDescriptor:pipelineDescriptor error:&error]; 399 | if (error != nil) 400 | { 401 | NSLog(@"Error: failed to create Metal pipeline state: %@", error); 402 | } 403 | 404 | return renderPipelineState; 405 | } 406 | 407 | - (void)emptyRenderPipelineStateCache 408 | { 409 | [self.renderPipelineStateCache removeAllObjects]; 410 | } 411 | 412 | - (void)setupRenderState:(ImDrawData *)drawData 413 | commandBuffer:(id)commandBuffer 414 | commandEncoder:(id)commandEncoder 415 | renderPipelineState:(id)renderPipelineState 416 | vertexBuffer:(MetalBuffer *)vertexBuffer 417 | vertexBufferOffset:(size_t)vertexBufferOffset 418 | { 419 | [commandEncoder setCullMode:MTLCullModeNone]; 420 | [commandEncoder setDepthStencilState:g_sharedMetalContext.depthStencilState]; 421 | 422 | // Setup viewport, orthographic projection matrix 423 | // Our visible imgui space lies from draw_data->DisplayPos (top left) to 424 | // draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayMin is typically (0,0) for single viewport apps. 425 | MTLViewport viewport = 426 | { 427 | .originX = 0.0, 428 | .originY = 0.0, 429 | .width = (double)(drawData->DisplaySize.x * drawData->FramebufferScale.x), 430 | .height = (double)(drawData->DisplaySize.y * drawData->FramebufferScale.y), 431 | .znear = 0.0, 432 | .zfar = 1.0 433 | }; 434 | [commandEncoder setViewport:viewport]; 435 | 436 | float L = drawData->DisplayPos.x; 437 | float R = drawData->DisplayPos.x + drawData->DisplaySize.x; 438 | float T = drawData->DisplayPos.y; 439 | float B = drawData->DisplayPos.y + drawData->DisplaySize.y; 440 | float N = (float)viewport.znear; 441 | float F = (float)viewport.zfar; 442 | const float ortho_projection[4][4] = 443 | { 444 | { 2.0f/(R-L), 0.0f, 0.0f, 0.0f }, 445 | { 0.0f, 2.0f/(T-B), 0.0f, 0.0f }, 446 | { 0.0f, 0.0f, 1/(F-N), 0.0f }, 447 | { (R+L)/(L-R), (T+B)/(B-T), N/(F-N), 1.0f }, 448 | }; 449 | [commandEncoder setVertexBytes:&ortho_projection length:sizeof(ortho_projection) atIndex:1]; 450 | 451 | [commandEncoder setRenderPipelineState:renderPipelineState]; 452 | 453 | [commandEncoder setVertexBuffer:vertexBuffer.buffer offset:0 atIndex:0]; 454 | [commandEncoder setVertexBufferOffset:vertexBufferOffset atIndex:0]; 455 | } 456 | 457 | - (void)renderDrawData:(ImDrawData *)drawData 458 | commandBuffer:(id)commandBuffer 459 | commandEncoder:(id)commandEncoder 460 | { 461 | // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) 462 | int fb_width = (int)(drawData->DisplaySize.x * drawData->FramebufferScale.x); 463 | int fb_height = (int)(drawData->DisplaySize.y * drawData->FramebufferScale.y); 464 | if (fb_width <= 0 || fb_height <= 0 || drawData->CmdListsCount == 0) 465 | return; 466 | 467 | id renderPipelineState = [self renderPipelineStateForFrameAndDevice:commandBuffer.device]; 468 | 469 | size_t vertexBufferLength = (size_t)drawData->TotalVtxCount * sizeof(ImDrawVert); 470 | size_t indexBufferLength = (size_t)drawData->TotalIdxCount * sizeof(ImDrawIdx); 471 | MetalBuffer* vertexBuffer = [self dequeueReusableBufferOfLength:vertexBufferLength device:commandBuffer.device]; 472 | MetalBuffer* indexBuffer = [self dequeueReusableBufferOfLength:indexBufferLength device:commandBuffer.device]; 473 | 474 | [self setupRenderState:drawData commandBuffer:commandBuffer commandEncoder:commandEncoder renderPipelineState:renderPipelineState vertexBuffer:vertexBuffer vertexBufferOffset:0]; 475 | 476 | // Will project scissor/clipping rectangles into framebuffer space 477 | ImVec2 clip_off = drawData->DisplayPos; // (0,0) unless using multi-viewports 478 | ImVec2 clip_scale = drawData->FramebufferScale; // (1,1) unless using retina display which are often (2,2) 479 | 480 | // Render command lists 481 | size_t vertexBufferOffset = 0; 482 | size_t indexBufferOffset = 0; 483 | for (int n = 0; n < drawData->CmdListsCount; n++) 484 | { 485 | const ImDrawList* cmd_list = drawData->CmdLists[n]; 486 | 487 | memcpy((char *)vertexBuffer.buffer.contents + vertexBufferOffset, cmd_list->VtxBuffer.Data, (size_t)cmd_list->VtxBuffer.Size * sizeof(ImDrawVert)); 488 | memcpy((char *)indexBuffer.buffer.contents + indexBufferOffset, cmd_list->IdxBuffer.Data, (size_t)cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx)); 489 | 490 | for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) 491 | { 492 | const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; 493 | if (pcmd->UserCallback) 494 | { 495 | // User callback, registered via ImDrawList::AddCallback() 496 | // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.) 497 | if (pcmd->UserCallback == ImDrawCallback_ResetRenderState) 498 | [self setupRenderState:drawData commandBuffer:commandBuffer commandEncoder:commandEncoder renderPipelineState:renderPipelineState vertexBuffer:vertexBuffer vertexBufferOffset:vertexBufferOffset]; 499 | else 500 | pcmd->UserCallback(cmd_list, pcmd); 501 | } 502 | else 503 | { 504 | // Project scissor/clipping rectangles into framebuffer space 505 | ImVec4 clip_rect; 506 | clip_rect.x = (pcmd->ClipRect.x - clip_off.x) * clip_scale.x; 507 | clip_rect.y = (pcmd->ClipRect.y - clip_off.y) * clip_scale.y; 508 | clip_rect.z = (pcmd->ClipRect.z - clip_off.x) * clip_scale.x; 509 | clip_rect.w = (pcmd->ClipRect.w - clip_off.y) * clip_scale.y; 510 | 511 | if (clip_rect.x < fb_width && clip_rect.y < fb_height && clip_rect.z >= 0.0f && clip_rect.w >= 0.0f) 512 | { 513 | // Apply scissor/clipping rectangle 514 | MTLScissorRect scissorRect = 515 | { 516 | .x = NSUInteger(clip_rect.x), 517 | .y = NSUInteger(clip_rect.y), 518 | .width = NSUInteger(clip_rect.z - clip_rect.x), 519 | .height = NSUInteger(clip_rect.w - clip_rect.y) 520 | }; 521 | [commandEncoder setScissorRect:scissorRect]; 522 | 523 | 524 | // Bind texture, Draw 525 | if (pcmd->TextureId != NULL) 526 | [commandEncoder setFragmentTexture:(__bridge id)(pcmd->TextureId) atIndex:0]; 527 | 528 | [commandEncoder setVertexBufferOffset:(vertexBufferOffset + pcmd->VtxOffset * sizeof(ImDrawVert)) atIndex:0]; 529 | [commandEncoder drawIndexedPrimitives:MTLPrimitiveTypeTriangle 530 | indexCount:pcmd->ElemCount 531 | indexType:sizeof(ImDrawIdx) == 2 ? MTLIndexTypeUInt16 : MTLIndexTypeUInt32 532 | indexBuffer:indexBuffer.buffer 533 | indexBufferOffset:indexBufferOffset + pcmd->IdxOffset * sizeof(ImDrawIdx)]; 534 | } 535 | } 536 | } 537 | 538 | vertexBufferOffset += (size_t)cmd_list->VtxBuffer.Size * sizeof(ImDrawVert); 539 | indexBufferOffset += (size_t)cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx); 540 | } 541 | 542 | __weak id weakSelf = self; 543 | [commandBuffer addCompletedHandler:^(id) 544 | { 545 | dispatch_async(dispatch_get_main_queue(), ^{ 546 | [weakSelf enqueueReusableBuffer:vertexBuffer]; 547 | [weakSelf enqueueReusableBuffer:indexBuffer]; 548 | }); 549 | }]; 550 | } 551 | 552 | @end 553 | -------------------------------------------------------------------------------- /ImGui/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 | -------------------------------------------------------------------------------- /Includes/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Duende510/iOS-ImGui-ModMenu-Jailed/c91916012c5b78bda036cfdd65276f498f35d365/Includes/.DS_Store -------------------------------------------------------------------------------- /Includes/Hooking/JailedHook.h: -------------------------------------------------------------------------------- 1 | #include "../Libs/dobby_defines.h" 2 | #include "../SCLAlertView/SCLAlertView.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #define DEBUG 16 | 17 | #ifdef DEBUG 18 | #define log(...) NSLog(__VA_ARGS__) 19 | #else 20 | #define log(...) 21 | #endif 22 | 23 | #ifdef __cplusplus 24 | extern "C" 25 | { 26 | #endif 27 | 28 | NSString *StaticInlineHookPatch(char *machoPath, uint64_t vaddr, char *patch); 29 | void *StaticInlineHookFunction(char *machoPath, uint64_t vaddr, void *replacement); 30 | void *find_module_by_path(char *machoPath); 31 | BOOL DeactiveCodePatch(char *machoPath, uint64_t vaddr, char *patch); 32 | BOOL ActiveCodePatch(char *machoPath, uint64_t vaddr, char *patch); 33 | extern char *BinaryName; 34 | 35 | #define UIColorFromHex(hexColor) [UIColor colorWithRed:((float)((hexColor & 0xFF0000) >> 16)) / 255.0 green:((float)((hexColor & 0xFF00) >> 8)) / 255.0 blue:((float)(hexColor & 0xFF)) / 255.0 alpha:1.0] 36 | 37 | #define HOOK(x, y, z) \ 38 | NSString *result_##y = StaticInlineHookPatch(BinaryName, x, nullptr); \ 39 | if (result_##y) \ 40 | { \ 41 | log(@"Hook result: %s", result_##y.UTF8String); \ 42 | void *result = StaticInlineHookFunction(BinaryName, x, (void *)y); \ 43 | log(@"Hook result %p", result); \ 44 | *(void **)(&z) = (void *)result; \ 45 | } 46 | 47 | #define HOOKPTR(x, z) \ 48 | NSString *result_##z = StaticInlineHookPatch(BinaryName, x, nullptr); \ 49 | if (result_##z) \ 50 | { \ 51 | log(@"Hook result: %s", result_##z.UTF8String); \ 52 | void *result = StaticInlineHookFunction(BinaryName, x, nullptr); \ 53 | log(@"Retrieved function pointer %p", result); \ 54 | *(void **)(&z) = (void *)result; \ 55 | } 56 | 57 | #define PATCHOFFSET(x, z, active) \ 58 | { \ 59 | log(@"Attempting patch #%llx", x); \ 60 | NSString *result_patch_##x = StaticInlineHookPatch(BinaryName, x, z); \ 61 | if (result_patch_##x) \ 62 | { \ 63 | log(@"Hook result for %llx: %s", x, [result_patch_##x UTF8String]); \ 64 | BOOL success = active ? ActiveCodePatch(BinaryName, x, z) : DeactiveCodePatch(BinaryName, x, z); \ 65 | log(@"Patch %s result for %llx: %d", active ? "activation" : "deactivation", x, success); \ 66 | } \ 67 | } 68 | 69 | #ifdef __cplusplus 70 | } 71 | #endif 72 | -------------------------------------------------------------------------------- /Includes/Libs/dobby_defines.h: -------------------------------------------------------------------------------- 1 | // C++ version made by Lavochka 2 | 3 | #ifndef dobby_h 4 | #define dobby_h 5 | 6 | // obfuscated interface 7 | #if 0 8 | #define DobbyBuildVersion c343f74888dffad84d9ad08d9c433456 9 | #define DobbyHook c8dc3ffa44f22dbd10ccae213dd8b1f8 10 | #define DobbyInstrument b71e27bca2c362de90c1034f19d839f9 11 | #endif 12 | 13 | #ifdef __cplusplus 14 | extern "C" { 15 | #endif 16 | 17 | #include 18 | #include 19 | 20 | void log_set_level(int level); 21 | void log_switch_to_syslog(); 22 | void log_switch_to_file(const char *path); 23 | 24 | typedef enum { 25 | kMemoryOperationSuccess, 26 | kMemoryOperationError, 27 | kNotSupportAllocateExecutableMemory, 28 | kNotEnough, 29 | kNone 30 | } MemoryOperationError; 31 | 32 | #define PLATFORM_INTERFACE_CODE_PATCH_TOOL_H 33 | MemoryOperationError CodePatch(void *address, uint8_t *buffer, uint32_t buffer_size); 34 | 35 | typedef uintptr_t addr_t; 36 | typedef uint32_t addr32_t; 37 | typedef uint64_t addr64_t; 38 | 39 | #if defined(__arm64__) || defined(__aarch64__) 40 | 41 | #define ARM64_TMP_REG_NDX_0 17 42 | 43 | // float register 44 | typedef union _FPReg { 45 | __int128_t q; 46 | struct { 47 | double d1; 48 | double d2; 49 | } d; 50 | struct { 51 | float f1; 52 | float f2; 53 | float f3; 54 | float f4; 55 | } f; 56 | } FPReg; 57 | 58 | // register context 59 | typedef struct _RegisterContext { 60 | uint64_t dmmpy_0; // dummy placeholder 61 | uint64_t sp; 62 | 63 | uint64_t dmmpy_1; // dummy placeholder 64 | union { 65 | uint64_t x[29]; 66 | struct { 67 | uint64_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19, x20, x21, x22, 68 | x23, x24, x25, x26, x27, x28; 69 | } regs; 70 | } general; 71 | 72 | uint64_t fp; 73 | uint64_t lr; 74 | 75 | union { 76 | FPReg q[32]; 77 | struct { 78 | FPReg q0, q1, q2, q3, q4, q5, q6, q7; 79 | // [!!! READ ME !!!] 80 | // for Arm64, can't access q8 - q31, unless you enable full floating-point register pack 81 | FPReg q8, q9, q10, q11, q12, q13, q14, q15, q16, q17, q18, q19, q20, q21, q22, q23, q24, q25, q26, q27, q28, q29, 82 | q30, q31; 83 | } regs; 84 | } floating; 85 | } RegisterContext; 86 | #elif defined(__arm__) 87 | typedef struct _RegisterContext { 88 | uint32_t dummy_0; 89 | uint32_t dummy_1; 90 | 91 | uint32_t dummy_2; 92 | uint32_t sp; 93 | 94 | union { 95 | uint32_t r[13]; 96 | struct { 97 | uint32_t r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12; 98 | } regs; 99 | } general; 100 | 101 | uint32_t lr; 102 | } RegisterContext; 103 | #elif defined(_M_IX86) || defined(__i386__) 104 | typedef struct _RegisterContext { 105 | uint32_t dummy_0; 106 | uint32_t esp; 107 | 108 | uint32_t dummy_1; 109 | uint32_t flags; 110 | 111 | union { 112 | struct { 113 | uint32_t eax, ebx, ecx, edx, ebp, esp, edi, esi; 114 | } regs; 115 | } general; 116 | 117 | } RegisterContext; 118 | #elif defined(_M_X64) || defined(__x86_64__) 119 | typedef struct _RegisterContext { 120 | uint64_t dummy_0; 121 | uint64_t rsp; 122 | 123 | union { 124 | struct { 125 | uint64_t rax, rbx, rcx, rdx, rbp, rsp, rdi, rsi, r8, r9, r10, r11, r12, r13, r14, r15; 126 | } regs; 127 | } general; 128 | 129 | uint64_t dummy_1; 130 | uint64_t flags; 131 | } RegisterContext; 132 | #endif 133 | 134 | #define RT_FAILED -1 135 | #define RT_SUCCESS 0 136 | typedef enum _RetStatus { RS_FAILED = -1, RS_SUCCESS = 0 } RetStatus; 137 | 138 | typedef struct _HookEntryInfo { 139 | int hook_id; 140 | union { 141 | void *target_address; 142 | void *function_address; 143 | void *instruction_address; 144 | }; 145 | } HookEntryInfo; 146 | 147 | // DobbyWrap <==> DobbyInstrument, so use DobbyInstrument instead of DobbyWrap 148 | #if 0 149 | // wrap function with pre_call and post_call 150 | typedef void (*PreCallTy)(RegisterContext *ctx, const HookEntryInfo *info); 151 | typedef void (*PostCallTy)(RegisterContext *ctx, const HookEntryInfo *info); 152 | int DobbyWrap(void *function_address, PreCallTy pre_call, PostCallTy post_call); 153 | #endif 154 | 155 | // return dobby build date 156 | const char *DobbyBuildVersion(); 157 | 158 | // replace function 159 | int DobbyHook(void *address, void *replace_call, void **origin_call); 160 | 161 | // dynamic binary instrument for instruction 162 | // [!!! READ ME !!!] 163 | // for Arm64, can't access q8 - q31, unless you enable full floating-point register pack 164 | typedef void (*DBICallTy)(RegisterContext *ctx, const HookEntryInfo *info); 165 | int DobbyInstrument(void *address, DBICallTy dbi_call); 166 | 167 | // destory and restore hook 168 | int DobbyDestroy(void *address); 169 | 170 | // iterate symbol table and find symbol 171 | void *DobbySymbolResolver(const char *image_name, const char *symbol_name); 172 | 173 | // global offset table 174 | int DobbyGlobalOffsetTableReplace(char *image_name, char *symbol_name, void *fake_func, void **orig_func); 175 | 176 | // [!!! READ ME !!!] 177 | // for arm, Arm64, dobby will use b xxx instead of ldr absolute indirect branch 178 | // for x64, dobby always use absolute indirect jump 179 | #if defined(__arm__) || defined(__arm64__) || defined(__aarch64__) || defined(_M_X64) || defined(__x86_64__) 180 | void dobby_enable_near_branch_trampoline(); 181 | void dobby_disable_near_branch_trampoline(); 182 | #endif 183 | 184 | // register linker load image callback 185 | typedef void (*linker_load_callback_t)(const char *image_name, void *handle); 186 | void dobby_register_image_load_callback(linker_load_callback_t func); 187 | 188 | #ifdef __cplusplus 189 | } 190 | #endif 191 | 192 | typedef struct { 193 | uint64_t hook_vaddr; 194 | uint64_t hook_size; 195 | uint64_t code_vaddr; 196 | uint64_t code_size; 197 | 198 | uint64_t patched_vaddr; 199 | uint64_t original_vaddr; 200 | uint64_t instrument_vaddr; 201 | 202 | uint64_t patch_size; 203 | uint64_t patch_hash; 204 | 205 | void *target_replace; 206 | void *instrument_handler; 207 | } StaticInlineHookBlock; 208 | 209 | int dobby_create_instrument_bridge(void *targetData); 210 | 211 | bool dobby_static_inline_hook(StaticInlineHookBlock *hookBlock, StaticInlineHookBlock *hookBlockRVA, uint64_t funcRVA, 212 | void *funcData, uint64_t targetRVA, void *targetData, uint64_t InstrumentBridgeRVA, 213 | void *patchBytes, int patchSize); 214 | 215 | #endif 216 | 217 | // C++ version made by Lavochka -------------------------------------------------------------------------------- /Includes/Libs/libdobby_fixed.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Duende510/iOS-ImGui-ModMenu-Jailed/c91916012c5b78bda036cfdd65276f498f35d365/Includes/Libs/libdobby_fixed.a -------------------------------------------------------------------------------- /Includes/Libs/libstdc++.6.0.9.dylib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Duende510/iOS-ImGui-ModMenu-Jailed/c91916012c5b78bda036cfdd65276f498f35d365/Includes/Libs/libstdc++.6.0.9.dylib -------------------------------------------------------------------------------- /Includes/Obfuscate.h: -------------------------------------------------------------------------------- 1 | // http://www.rohitab.com/discuss/topic/39611-malware-related-compile-time-hacks-with-c11/ 2 | // https://github.com/Rednick16/cpp11-compile-time-string-obfuscation 3 | 4 | #include 5 | #include 6 | 7 | //-------------------------------------------------------------// 8 | // "Malware related compile-time hacks with C++11" by LeFF // 9 | // You can use this code however you like, I just don't really // 10 | // give a shit, but if you feel some respect for me, please // 11 | // don't cut off this comment when copy-pasting... ;-) // 12 | //-------------------------------------------------------------// 13 | 14 | #if defined(_MSC_VER) 15 | #define ALWAYS_INLINE __forceinline 16 | #else 17 | #define ALWAYS_INLINE __attribute__((always_inline)) 18 | #endif 19 | 20 | // Usage examples: 21 | void setup() __attribute__((noinline)); 22 | void startAuthentication() __attribute__((noinline)); 23 | 24 | #ifndef seed 25 | // I use current (compile time) as a seed 26 | // Convert time string (hh:mm:ss) into a number 27 | constexpr int seedToInt(char c) { return c - '0'; } 28 | const int seed = seedToInt(__TIME__[7]) + 29 | seedToInt(__TIME__[6]) * 10 + 30 | seedToInt(__TIME__[4]) * 60 + 31 | seedToInt(__TIME__[3]) * 600 + 32 | seedToInt(__TIME__[1]) * 3600 + 33 | seedToInt(__TIME__[0]) * 36000; 34 | #endif 35 | 36 | // The constantify template is used to make sure that the result of constexpr 37 | // function will be computed at compile-time instead of run-time 38 | template struct 39 | vxCplConstantify { enum { Value = Const }; }; 40 | 41 | // Compile-time mod of a linear congruential pseudorandom number generator, 42 | // the actual algorithm was taken from "Numerical Recipes" book 43 | constexpr uintptr_t vxCplRandom(uintptr_t Id) 44 | { return (1013904223 + 1664525 * ((Id > 0) ? (vxCplRandom(Id - 1)) : (/*vxCPLSEED*/seed))) & 0xFFFFFFFF; } 45 | 46 | // Compile-time random macros, can be used to randomize execution 47 | // path for separate builds, or compile-time trash code generation 48 | #define vxRANDOM(Min, Max) (Min + (vxRAND() % (Max - Min + 1))) 49 | #define vxRAND() (vxCplConstantify::Value) 50 | 51 | // Compile-time recursive mod of string hashing algorithm, 52 | // the actual algorithm was taken from Qt library (this 53 | // function isn't case sensitive due to vxCplTolower) 54 | constexpr char vxCplTolower(char Ch) { return (Ch >= 'A' && Ch <= 'Z') ? (Ch - 'A' + 'a') : (Ch); } 55 | constexpr uintptr_t vxCplHashPart3(char Ch, uintptr_t Hash) { return ((Hash << 4) + vxCplTolower(Ch)); } 56 | constexpr uintptr_t vxCplHashPart2(char Ch, uintptr_t Hash) { return (vxCplHashPart3(Ch, Hash) ^ ((vxCplHashPart3(Ch, Hash) & 0xF0000000) >> 23)); } 57 | constexpr uintptr_t vxCplHashPart1(char Ch, uintptr_t Hash) { return (vxCplHashPart2(Ch, Hash) & 0x0FFFFFFF); } 58 | constexpr uintptr_t vxCplHash(const char* Str) { return (*Str) ? (vxCplHashPart1(*Str, vxCplHash(Str + 1))) : (0); } 59 | 60 | // Compile-time hashing macro, hash values changes using the first pseudorandom number in sequence 61 | #define HASH(Str) (uintptr_t)(vxCplConstantify::Value ^ vxCplConstantify::Value) 62 | 63 | // Compile-time generator for list of indexes (0, 1, 2, ...) 64 | template struct vxCplIndexList {}; 65 | template struct vxCplAppend; 66 | template struct vxCplAppend, Right> { typedef vxCplIndexList Result; }; 67 | template struct vxCplIndexes { typedef typename vxCplAppend::Result, N - 1>::Result Result; }; 68 | template <> struct vxCplIndexes<0> { typedef vxCplIndexList<> Result; }; 69 | 70 | // Compile-time string encryption of a single character 71 | const char vxCplEncryptCharKey = (const char)vxRANDOM(0, 0xFF); 72 | constexpr char ALWAYS_INLINE vxCplEncryptChar(const char Ch, uintptr_t Idx) { return Ch ^ (vxCplEncryptCharKey + Idx); } 73 | 74 | // Compile-time string encryption class 75 | template struct vxCplEncryptedString; 76 | template struct vxCplEncryptedString > 77 | { 78 | char Value[sizeof...(Idx) + 1]; // Buffer for a string 79 | 80 | // Compile-time constructor 81 | constexpr ALWAYS_INLINE vxCplEncryptedString(const char* const Str) 82 | : Value{ vxCplEncryptChar(Str[Idx], Idx)... } {} 83 | 84 | // Run-time decryption 85 | inline const char* decrypt() 86 | { 87 | for(uintptr_t t = 0; t < sizeof...(Idx); t++) 88 | { this->Value[t] = this->Value[t] ^ (vxCplEncryptCharKey + t); } 89 | this->Value[sizeof...(Idx)] = '\0'; return this->Value; 90 | } 91 | }; 92 | 93 | // Compile-time string encryption macro 94 | #define ENCRYPT(Str) (vxCplEncryptedString::Result>(Str).decrypt()) 95 | 96 | #ifdef __APPLE__ 97 | // Compile-time Objective-c string encryption macro 98 | #define NSSENCRYPT(Str) @(ENCRYPT(Str)) 99 | #endif 100 | 101 | // Compile-time offset string encryption macro, converts back to uint64_t. 102 | #define ENCRYPTOFFSET(Str) strtoull(ENCRYPT(Str), NULL, 0) 103 | 104 | // Compile-time hex string encryption macro, does same as ENCRYPT, but the naming is just more clear. 105 | #define ENCRYPTHEX(Str) ENCRYPT(Str) 106 | -------------------------------------------------------------------------------- /Includes/SCLAlertView/SCLAlertViewResponder.h: -------------------------------------------------------------------------------- 1 | // 2 | // SCLAlertViewResponder.h 3 | // SCLAlertView 4 | // 5 | // Created by Diogo Autilio on 9/26/14. 6 | // Copyright (c) 2014-2017 AnyKey Entertainment. All rights reserved. 7 | // 8 | 9 | #if defined(__has_feature) && __has_feature(modules) 10 | @import Foundation; 11 | #else 12 | #import 13 | #endif 14 | #import "SCLAlertView.h" 15 | 16 | @interface SCLAlertViewResponder : NSObject 17 | 18 | /** TODO 19 | * 20 | * TODO 21 | */ 22 | - (instancetype)init:(SCLAlertView *)alertview; 23 | 24 | /** TODO 25 | * 26 | * TODO 27 | */ 28 | - (void)close; 29 | 30 | @end 31 | -------------------------------------------------------------------------------- /Includes/SCLAlertView/SCLAlertViewResponder.m: -------------------------------------------------------------------------------- 1 | // 2 | // SCLAlertViewResponder.m 3 | // SCLAlertView 4 | // 5 | // Created by Diogo Autilio on 9/26/14. 6 | // Copyright (c) 2014-2017 AnyKey Entertainment. All rights reserved. 7 | // 8 | 9 | #import "SCLAlertViewResponder.h" 10 | 11 | @interface SCLAlertViewResponder () 12 | 13 | @property SCLAlertView *alertview; 14 | 15 | @end 16 | 17 | @implementation SCLAlertViewResponder 18 | 19 | // 20 | //// Allow alerts to be closed/renamed in a chainable manner 21 | //// Example: SCLAlertView().showSuccess(self, title: "Test", subTitle: "Value").close() 22 | 23 | // Initialisation and Title/Subtitle/Close functions 24 | - (instancetype)init:(SCLAlertView *)alertview 25 | { 26 | self.alertview = alertview; 27 | return self; 28 | } 29 | 30 | - (void)setTitletitle:(NSString *)title 31 | { 32 | self.alertview.labelTitle.text = title; 33 | } 34 | 35 | - (void)setSubTitle:(NSString *)subTitle 36 | { 37 | self.alertview.viewText.text = subTitle; 38 | } 39 | 40 | - (void)close 41 | { 42 | [self.alertview hideView]; 43 | } 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /Includes/SCLAlertView/SCLAlertViewStyleKit.h: -------------------------------------------------------------------------------- 1 | // 2 | // SCLAlertViewStyleKit.h 3 | // SCLAlertView 4 | // 5 | // Created by Diogo Autilio on 9/26/14. 6 | // Copyright (c) 2014-2017 AnyKey Entertainment. All rights reserved. 7 | // 8 | 9 | #if defined(__has_feature) && __has_feature(modules) 10 | @import Foundation; 11 | @import UIKit; 12 | #else 13 | #import 14 | #import 15 | #endif 16 | #import "SCLButton.h" 17 | 18 | @interface SCLAlertViewStyleKit : NSObject 19 | 20 | // Images 21 | /** TODO 22 | * 23 | * TODO 24 | */ 25 | + (UIImage *)imageOfCheckmark; 26 | 27 | /** TODO 28 | * 29 | * TODO 30 | */ 31 | + (UIImage *)imageOfCross; 32 | 33 | /** TODO 34 | * 35 | * TODO 36 | */ 37 | + (UIImage *)imageOfNotice; 38 | 39 | /** TODO 40 | * 41 | * TODO 42 | */ 43 | + (UIImage *)imageOfWarning; 44 | 45 | /** TODO 46 | * 47 | * TODO 48 | */ 49 | + (UIImage *)imageOfInfo; 50 | 51 | /** TODO 52 | * 53 | * TODO 54 | */ 55 | + (UIImage *)imageOfEdit; 56 | 57 | /** TODO 58 | * 59 | * TODO 60 | */ 61 | + (UIImage *)imageOfQuestion; 62 | 63 | /** TODO 64 | * 65 | * TODO 66 | */ 67 | + (void)drawCheckmark; 68 | 69 | /** TODO 70 | * 71 | * TODO 72 | */ 73 | + (void)drawCross; 74 | 75 | /** TODO 76 | * 77 | * TODO 78 | */ 79 | + (void)drawNotice; 80 | 81 | /** TODO 82 | * 83 | * TODO 84 | */ 85 | + (void)drawWarning; 86 | 87 | /** TODO 88 | * 89 | * TODO 90 | */ 91 | + (void)drawInfo; 92 | 93 | /** TODO 94 | * 95 | * TODO 96 | */ 97 | + (void)drawEdit; 98 | 99 | /** TODO 100 | * 101 | * TODO 102 | */ 103 | + (void)drawQuestion; 104 | 105 | @end 106 | -------------------------------------------------------------------------------- /Includes/SCLAlertView/SCLAlertViewStyleKit.m: -------------------------------------------------------------------------------- 1 | // 2 | // SCLAlertViewStyleKit.m 3 | // SCLAlertView 4 | // 5 | // Created by Diogo Autilio on 9/26/14. 6 | // Copyright (c) 2014-2017 AnyKey Entertainment. All rights reserved. 7 | // 8 | 9 | #import "SCLAlertViewStyleKit.h" 10 | 11 | // ------------------------------------ 12 | // Icon drawing 13 | // Code generated by PaintCode 14 | // ------------------------------------ 15 | @implementation SCLAlertViewStyleKit 16 | 17 | #pragma mark - Cache 18 | 19 | static UIImage *imageOfCheckmark = nil; 20 | static UIImage *imageOfCross = nil; 21 | static UIImage *imageOfNotice = nil; 22 | static UIImage *imageOfWarning = nil; 23 | static UIImage *imageOfInfo = nil; 24 | static UIImage *imageOfEdit = nil; 25 | static UIImage *imageOfQuestion = nil; 26 | 27 | #pragma mark - Initialization 28 | 29 | + (void)initialize 30 | { 31 | // Do something 32 | } 33 | 34 | #pragma mark - Drawing Methods 35 | 36 | + (void)drawCheckmark 37 | { 38 | // Checkmark Shape Drawing 39 | UIBezierPath *checkmarkShapePath = [[UIBezierPath alloc] init]; 40 | [checkmarkShapePath moveToPoint:CGPointMake(73.25, 14.05)]; 41 | [checkmarkShapePath addCurveToPoint:CGPointMake(64.51, 13.86) controlPoint1: CGPointMake(70.98, 11.44) controlPoint2: CGPointMake(66.78, 11.26)]; 42 | [checkmarkShapePath addLineToPoint:CGPointMake(27.46, 52)]; 43 | [checkmarkShapePath addLineToPoint:CGPointMake(15.75, 39.54)]; 44 | [checkmarkShapePath addCurveToPoint:CGPointMake(6.84, 39.54) controlPoint1: CGPointMake(13.48, 36.93) controlPoint2: CGPointMake(9.28, 36.93)]; 45 | [checkmarkShapePath addCurveToPoint:CGPointMake(6.84, 49.02) controlPoint1: CGPointMake(4.39, 42.14) controlPoint2: CGPointMake(4.39, 46.42)]; 46 | [checkmarkShapePath addLineToPoint:CGPointMake(22.91, 66.14)]; 47 | [checkmarkShapePath addCurveToPoint:CGPointMake(27.28, 68) controlPoint1: CGPointMake(24.14, 67.44) controlPoint2: CGPointMake(25.71, 68)]; 48 | [checkmarkShapePath addCurveToPoint:CGPointMake(31.65, 66.14) controlPoint1: CGPointMake(28.86, 68) controlPoint2: CGPointMake(30.43, 67.26)]; 49 | [checkmarkShapePath addLineToPoint:CGPointMake(73.08, 23.35)]; 50 | [checkmarkShapePath addCurveToPoint:CGPointMake(73.25, 14.05) controlPoint1: CGPointMake(75.52, 20.75) controlPoint2: CGPointMake(75.7, 16.65)]; 51 | [checkmarkShapePath closePath]; 52 | checkmarkShapePath.miterLimit = 4; 53 | 54 | [[UIColor whiteColor] setFill]; 55 | [checkmarkShapePath fill]; 56 | } 57 | 58 | + (void)drawCross 59 | { 60 | // Cross Shape Drawing 61 | UIBezierPath *crossShapePath = [[UIBezierPath alloc] init]; 62 | [crossShapePath moveToPoint:CGPointMake(10, 70)]; 63 | [crossShapePath addLineToPoint:CGPointMake(70, 10)]; 64 | [crossShapePath moveToPoint:CGPointMake(10, 10)]; 65 | [crossShapePath addLineToPoint:CGPointMake(70, 70)]; 66 | 67 | crossShapePath.lineCapStyle = kCGLineCapRound; 68 | crossShapePath.lineJoinStyle = kCGLineJoinRound; 69 | 70 | [[UIColor whiteColor] setStroke]; 71 | crossShapePath.lineWidth = 14; 72 | [crossShapePath stroke]; 73 | } 74 | 75 | + (void)drawNotice 76 | { 77 | // Notice Shape Drawing 78 | UIBezierPath *noticeShapePath = [[UIBezierPath alloc] init]; 79 | [noticeShapePath moveToPoint:CGPointMake(72, 48.54)]; 80 | [noticeShapePath addLineToPoint:CGPointMake(72, 39.9)]; 81 | [noticeShapePath addCurveToPoint:CGPointMake(66.38, 34.01) controlPoint1: CGPointMake(72, 36.76) controlPoint2: CGPointMake(69.48, 34.01)]; 82 | [noticeShapePath addCurveToPoint:CGPointMake(61.53, 35.97) controlPoint1: CGPointMake(64.82, 34.01) controlPoint2: CGPointMake(62.69, 34.8)]; 83 | [noticeShapePath addCurveToPoint:CGPointMake(60.36, 35.78) controlPoint1: CGPointMake(61.33, 35.97) controlPoint2: CGPointMake(62.3, 35.78)]; 84 | [noticeShapePath addLineToPoint:CGPointMake(60.36, 33.22)]; 85 | [noticeShapePath addCurveToPoint:CGPointMake(54.16, 26.16) controlPoint1: CGPointMake(60.36, 29.3) controlPoint2: CGPointMake(57.65, 26.16)]; 86 | [noticeShapePath addCurveToPoint:CGPointMake(48.73, 29.89) controlPoint1: CGPointMake(51.64, 26.16) controlPoint2: CGPointMake(50.67, 27.73)]; 87 | [noticeShapePath addLineToPoint:CGPointMake(48.73, 28.71)]; 88 | [noticeShapePath addCurveToPoint:CGPointMake(43.49, 21.64) controlPoint1: CGPointMake(48.73, 24.78) controlPoint2: CGPointMake(46.98, 21.64)]; 89 | [noticeShapePath addCurveToPoint:CGPointMake(39.03, 25.37) controlPoint1: CGPointMake(40.97, 21.64) controlPoint2: CGPointMake(39.03, 23.01)]; 90 | [noticeShapePath addLineToPoint:CGPointMake(39.03, 9.07)]; 91 | [noticeShapePath addCurveToPoint:CGPointMake(32.24, 2) controlPoint1: CGPointMake(39.03, 5.14) controlPoint2: CGPointMake(35.73, 2)]; 92 | [noticeShapePath addCurveToPoint:CGPointMake(25.45, 9.07) controlPoint1: CGPointMake(28.56, 2) controlPoint2: CGPointMake(25.45, 5.14)]; 93 | [noticeShapePath addLineToPoint:CGPointMake(25.45, 41.47)]; 94 | [noticeShapePath addCurveToPoint:CGPointMake(24.29, 43.44) controlPoint1: CGPointMake(25.45, 42.45) controlPoint2: CGPointMake(24.68, 43.04)]; 95 | [noticeShapePath addCurveToPoint:CGPointMake(9.55, 43.04) controlPoint1: CGPointMake(16.73, 40.88) controlPoint2: CGPointMake(11.88, 40.69)]; 96 | [noticeShapePath addCurveToPoint:CGPointMake(8, 46.58) controlPoint1: CGPointMake(8.58, 43.83) controlPoint2: CGPointMake(8, 45.2)]; 97 | [noticeShapePath addCurveToPoint:CGPointMake(14.4, 55.81) controlPoint1: CGPointMake(8.19, 50.31) controlPoint2: CGPointMake(12.07, 53.84)]; 98 | [noticeShapePath addLineToPoint:CGPointMake(27.2, 69.56)]; 99 | [noticeShapePath addCurveToPoint:CGPointMake(42.91, 77.8) controlPoint1: CGPointMake(30.5, 74.47) controlPoint2: CGPointMake(35.73, 77.21)]; 100 | [noticeShapePath addCurveToPoint:CGPointMake(43.88, 77.8) controlPoint1: CGPointMake(43.3, 77.8) controlPoint2: CGPointMake(43.68, 77.8)]; 101 | [noticeShapePath addCurveToPoint:CGPointMake(47.18, 78) controlPoint1: CGPointMake(45.04, 77.8) controlPoint2: CGPointMake(46.01, 78)]; 102 | [noticeShapePath addLineToPoint:CGPointMake(48.34, 78)]; 103 | [noticeShapePath addLineToPoint:CGPointMake(48.34, 78)]; 104 | [noticeShapePath addCurveToPoint:CGPointMake(71.61, 52.08) controlPoint1: CGPointMake(56.48, 78) controlPoint2: CGPointMake(69.87, 75.05)]; 105 | [noticeShapePath addCurveToPoint:CGPointMake(72, 48.54) controlPoint1: CGPointMake(71.81, 51.29) controlPoint2: CGPointMake(72, 49.72)]; 106 | [noticeShapePath closePath]; 107 | noticeShapePath.miterLimit = 4; 108 | 109 | [[UIColor whiteColor] setFill]; 110 | [noticeShapePath fill]; 111 | } 112 | 113 | + (void)drawWarning 114 | { 115 | // Color Declarations 116 | UIColor *greyColor = [UIColor colorWithRed:0.236 green:0.236 blue:0.236 alpha:1.000]; 117 | 118 | // Warning Group 119 | // Warning Circle Drawing 120 | UIBezierPath *warningCirclePath = [[UIBezierPath alloc] init]; 121 | [warningCirclePath moveToPoint:CGPointMake(40.94, 63.39)]; 122 | [warningCirclePath addCurveToPoint:CGPointMake(36.03, 65.55) controlPoint1: CGPointMake(39.06, 63.39) controlPoint2: CGPointMake(37.36, 64.18)]; 123 | [warningCirclePath addCurveToPoint:CGPointMake(34.14, 70.45) controlPoint1: CGPointMake(34.9, 66.92) controlPoint2: CGPointMake(34.14, 68.49)]; 124 | [warningCirclePath addCurveToPoint:CGPointMake(36.22, 75.54) controlPoint1: CGPointMake(34.14, 72.41) controlPoint2: CGPointMake(34.9, 74.17)]; 125 | [warningCirclePath addCurveToPoint:CGPointMake(40.94, 77.5) controlPoint1: CGPointMake(37.54, 76.91) controlPoint2: CGPointMake(39.06, 77.5)]; 126 | [warningCirclePath addCurveToPoint:CGPointMake(45.86, 75.35) controlPoint1: CGPointMake(42.83, 77.5) controlPoint2: CGPointMake(44.53, 76.72)]; 127 | [warningCirclePath addCurveToPoint:CGPointMake(47.93, 70.45) controlPoint1: CGPointMake(47.18, 74.17) controlPoint2: CGPointMake(47.93, 72.41)]; 128 | [warningCirclePath addCurveToPoint:CGPointMake(45.86, 65.35) controlPoint1: CGPointMake(47.93, 68.49) controlPoint2: CGPointMake(47.18, 66.72)]; 129 | [warningCirclePath addCurveToPoint:CGPointMake(40.94, 63.39) controlPoint1: CGPointMake(44.53, 64.18) controlPoint2: CGPointMake(42.83, 63.39)]; 130 | [warningCirclePath closePath]; 131 | warningCirclePath.miterLimit = 4; 132 | 133 | [greyColor setFill]; 134 | [warningCirclePath fill]; 135 | 136 | 137 | //// Warning Shape Drawing 138 | UIBezierPath *warningShapePath = [[UIBezierPath alloc] init]; 139 | [warningShapePath moveToPoint:CGPointMake(46.23, 4.26)]; 140 | [warningShapePath addCurveToPoint:CGPointMake(40.94, 2.5) controlPoint1: CGPointMake(44.91, 3.09) controlPoint2: CGPointMake(43.02, 2.5)]; 141 | [warningShapePath addCurveToPoint:CGPointMake(34.71, 4.26) controlPoint1: CGPointMake(38.68, 2.5) controlPoint2: CGPointMake(36.03, 3.09)]; 142 | [warningShapePath addCurveToPoint:CGPointMake(31.5, 8.77) controlPoint1: CGPointMake(33.01, 5.44) controlPoint2: CGPointMake(31.5, 7.01)]; 143 | [warningShapePath addLineToPoint:CGPointMake(31.5, 19.36)]; 144 | [warningShapePath addLineToPoint:CGPointMake(34.71, 54.44)]; 145 | [warningShapePath addCurveToPoint:CGPointMake(40.38, 58.16) controlPoint1: CGPointMake(34.9, 56.2) controlPoint2: CGPointMake(36.41, 58.16)]; 146 | [warningShapePath addCurveToPoint:CGPointMake(45.67, 54.44) controlPoint1: CGPointMake(44.34, 58.16) controlPoint2: CGPointMake(45.67, 56.01)]; 147 | [warningShapePath addLineToPoint:CGPointMake(48.5, 19.36)]; 148 | [warningShapePath addLineToPoint:CGPointMake(48.5, 8.77)]; 149 | [warningShapePath addCurveToPoint:CGPointMake(46.23, 4.26) controlPoint1: CGPointMake(48.5, 7.01) controlPoint2: CGPointMake(47.74, 5.44)]; 150 | [warningShapePath closePath]; 151 | warningShapePath.miterLimit = 4; 152 | 153 | [greyColor setFill]; 154 | [warningShapePath fill]; 155 | } 156 | 157 | + (void)drawInfo 158 | { 159 | // Color Declarations 160 | UIColor *color0 = [UIColor colorWithRed:1.000 green:1.000 blue:1.000 alpha:1.000]; 161 | 162 | // Info Shape Drawing 163 | UIBezierPath *infoShapePath = [[UIBezierPath alloc] init]; 164 | [infoShapePath moveToPoint:CGPointMake(45.66, 15.96)]; 165 | [infoShapePath addCurveToPoint:CGPointMake(45.66, 5.22) controlPoint1: CGPointMake(48.78, 12.99) controlPoint2: CGPointMake(48.78, 8.19)]; 166 | [infoShapePath addCurveToPoint:CGPointMake(34.34, 5.22) controlPoint1: CGPointMake(42.53, 2.26) controlPoint2: CGPointMake(37.47, 2.26)]; 167 | [infoShapePath addCurveToPoint:CGPointMake(34.34, 15.96) controlPoint1: CGPointMake(31.22, 8.19) controlPoint2: CGPointMake(31.22, 12.99)]; 168 | [infoShapePath addCurveToPoint:CGPointMake(45.66, 15.96) controlPoint1: CGPointMake(37.47, 18.92) controlPoint2: CGPointMake(42.53, 18.92)]; 169 | [infoShapePath closePath]; 170 | 171 | [infoShapePath moveToPoint:CGPointMake(48, 69.41)]; 172 | [infoShapePath addCurveToPoint:CGPointMake(40, 77) controlPoint1: CGPointMake(48, 73.58) controlPoint2: CGPointMake(44.4, 77)]; 173 | [infoShapePath addLineToPoint:CGPointMake(40, 77)]; 174 | [infoShapePath addCurveToPoint:CGPointMake(32, 69.41) controlPoint1: CGPointMake(35.6, 77) controlPoint2: CGPointMake(32, 73.58)]; 175 | [infoShapePath addLineToPoint:CGPointMake(32, 35.26)]; 176 | [infoShapePath addCurveToPoint:CGPointMake(40, 27.67) controlPoint1: CGPointMake(32, 31.08) controlPoint2: CGPointMake(35.6, 27.67)]; 177 | [infoShapePath addLineToPoint:CGPointMake(40, 27.67)]; 178 | [infoShapePath addCurveToPoint:CGPointMake(48, 35.26) controlPoint1: CGPointMake(44.4, 27.67) controlPoint2: CGPointMake(48, 31.08)]; 179 | [infoShapePath addLineToPoint:CGPointMake(48, 69.41)]; 180 | [infoShapePath closePath]; 181 | 182 | [color0 setFill]; 183 | [infoShapePath fill]; 184 | } 185 | 186 | + (void)drawEdit 187 | { 188 | // Color Declarations 189 | UIColor *color = [UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:1.0]; 190 | 191 | // Edit shape Drawing 192 | UIBezierPath *editPathPath = [[UIBezierPath alloc] init]; 193 | [editPathPath moveToPoint:CGPointMake(71, 2.7)]; 194 | [editPathPath addCurveToPoint:CGPointMake(71.9, 15.2) controlPoint1:CGPointMake(74.7, 5.9) controlPoint2:CGPointMake(75.1, 11.6)]; 195 | [editPathPath addLineToPoint:CGPointMake(64.5, 23.7)]; 196 | [editPathPath addLineToPoint:CGPointMake(49.9, 11.1)]; 197 | [editPathPath addLineToPoint:CGPointMake(57.3, 2.6)]; 198 | [editPathPath addCurveToPoint:CGPointMake(69.7, 1.7) controlPoint1:CGPointMake(60.4, -1.1) controlPoint2:CGPointMake(66.1, -1.5)]; 199 | [editPathPath addLineToPoint:CGPointMake(71, 2.7)]; 200 | [editPathPath addLineToPoint:CGPointMake(71, 2.7)]; 201 | [editPathPath closePath]; 202 | 203 | [editPathPath moveToPoint:CGPointMake(47.8, 13.5)]; 204 | [editPathPath addLineToPoint:CGPointMake(13.4, 53.1)]; 205 | [editPathPath addLineToPoint:CGPointMake(15.7, 55.1)]; 206 | [editPathPath addLineToPoint:CGPointMake(50.1, 15.5)]; 207 | [editPathPath addLineToPoint:CGPointMake(47.8, 13.5)]; 208 | [editPathPath addLineToPoint:CGPointMake(47.8, 13.5)]; 209 | [editPathPath closePath]; 210 | 211 | [editPathPath moveToPoint:CGPointMake(17.7, 56.7)]; 212 | [editPathPath addLineToPoint:CGPointMake(23.8, 62.2)]; 213 | [editPathPath addLineToPoint:CGPointMake(58.2, 22.6)]; 214 | [editPathPath addLineToPoint:CGPointMake(52, 17.1)]; 215 | [editPathPath addLineToPoint:CGPointMake(17.7, 56.7)]; 216 | [editPathPath addLineToPoint:CGPointMake(17.7, 56.7)]; 217 | [editPathPath closePath]; 218 | 219 | [editPathPath moveToPoint:CGPointMake(25.8, 63.8)]; 220 | [editPathPath addLineToPoint:CGPointMake(60.1, 24.2)]; 221 | [editPathPath addLineToPoint:CGPointMake(62.3, 26.1)]; 222 | [editPathPath addLineToPoint:CGPointMake(28.1, 65.7)]; 223 | [editPathPath addLineToPoint:CGPointMake(25.8, 63.8)]; 224 | [editPathPath addLineToPoint:CGPointMake(25.8, 63.8)]; 225 | [editPathPath closePath]; 226 | 227 | [editPathPath moveToPoint:CGPointMake(25.9, 68.1)]; 228 | [editPathPath addLineToPoint:CGPointMake(4.2, 79.5)]; 229 | [editPathPath addLineToPoint:CGPointMake(11.3, 55.5)]; 230 | [editPathPath addLineToPoint:CGPointMake(25.9, 68.1)]; 231 | [editPathPath closePath]; 232 | 233 | editPathPath.miterLimit = 4; 234 | editPathPath.usesEvenOddFillRule = YES; 235 | [color setFill]; 236 | [editPathPath fill]; 237 | } 238 | 239 | + (void)drawQuestion 240 | { 241 | // Color Declarations 242 | UIColor *color = [UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:1.0]; 243 | 244 | // Questionmark Shape Drawing 245 | UIBezierPath *questionShapePath = [[UIBezierPath alloc] init]; 246 | [questionShapePath moveToPoint: CGPointMake(33.75, 54.1)]; 247 | [questionShapePath addLineToPoint: CGPointMake(44.15, 54.1)]; 248 | [questionShapePath addLineToPoint: CGPointMake(44.15, 47.5)]; 249 | [questionShapePath addCurveToPoint: CGPointMake(51.85, 37.2) controlPoint1: CGPointMake(44.15, 42.9) controlPoint2: CGPointMake(46.75, 41.2)]; 250 | [questionShapePath addCurveToPoint: CGPointMake(61.95, 19.9) controlPoint1: CGPointMake(59.05, 31.6) controlPoint2: CGPointMake(61.95, 28.5)]; 251 | [questionShapePath addCurveToPoint: CGPointMake(41.45, 2.8) controlPoint1: CGPointMake(61.95, 7.6) controlPoint2: CGPointMake(52.85, 2.8)]; 252 | [questionShapePath addCurveToPoint: CGPointMake(25.05, 5.8) controlPoint1: CGPointMake(34.75, 2.8) controlPoint2: CGPointMake(29.65, 3.8)]; 253 | [questionShapePath addLineToPoint: CGPointMake(25.05, 14.4)]; 254 | [questionShapePath addCurveToPoint: CGPointMake(38.15, 12.3) controlPoint1: CGPointMake(29.15, 13.2) controlPoint2: CGPointMake(32.35, 12.3)]; 255 | [questionShapePath addCurveToPoint: CGPointMake(49.65, 20.8) controlPoint1: CGPointMake(45.65, 12.3) controlPoint2: CGPointMake(49.65, 14.4)]; 256 | [questionShapePath addCurveToPoint: CGPointMake(43.65, 31.7) controlPoint1: CGPointMake(49.65, 26) controlPoint2: CGPointMake(47.95, 28.4)]; 257 | [questionShapePath addCurveToPoint: CGPointMake(33.75, 46.6) controlPoint1: CGPointMake(37.15, 36.9) controlPoint2: CGPointMake(33.75, 39.7)]; 258 | [questionShapePath addLineToPoint: CGPointMake(33.75, 54.1)]; 259 | [questionShapePath closePath]; 260 | 261 | [questionShapePath moveToPoint: CGPointMake(33.15, 75.4)]; 262 | [questionShapePath addLineToPoint: CGPointMake(45.35, 75.4)]; 263 | [questionShapePath addLineToPoint: CGPointMake(45.35, 63.7)]; 264 | [questionShapePath addLineToPoint: CGPointMake(33.15, 63.7)]; 265 | [questionShapePath addLineToPoint: CGPointMake(33.15, 75.4)]; 266 | [questionShapePath closePath]; 267 | 268 | [color setFill]; 269 | [questionShapePath fill]; 270 | } 271 | 272 | #pragma mark - Images 273 | 274 | + (UIImage*)imageOfCheckmark 275 | { 276 | if (imageOfCheckmark != nil) 277 | { 278 | return imageOfCheckmark; 279 | } 280 | 281 | UIGraphicsBeginImageContextWithOptions(CGSizeMake(80, 80), NO, 0); 282 | [SCLAlertViewStyleKit drawCheckmark]; 283 | imageOfCheckmark = UIGraphicsGetImageFromCurrentImageContext(); 284 | UIGraphicsEndImageContext(); 285 | 286 | return imageOfCheckmark; 287 | } 288 | 289 | 290 | + (UIImage*)imageOfCross 291 | { 292 | if (imageOfCross != nil) 293 | { 294 | return imageOfCross; 295 | } 296 | 297 | UIGraphicsBeginImageContextWithOptions(CGSizeMake(80, 80), NO, 0); 298 | [SCLAlertViewStyleKit drawCross]; 299 | imageOfCross = UIGraphicsGetImageFromCurrentImageContext(); 300 | UIGraphicsEndImageContext(); 301 | 302 | return imageOfCross; 303 | } 304 | 305 | + (UIImage*)imageOfNotice 306 | { 307 | if (imageOfNotice != nil) 308 | { 309 | return imageOfNotice; 310 | } 311 | 312 | UIGraphicsBeginImageContextWithOptions(CGSizeMake(80, 80), NO, 0); 313 | [SCLAlertViewStyleKit drawNotice]; 314 | imageOfNotice = UIGraphicsGetImageFromCurrentImageContext(); 315 | UIGraphicsEndImageContext(); 316 | 317 | return imageOfNotice; 318 | } 319 | 320 | + (UIImage*)imageOfWarning 321 | { 322 | if (imageOfWarning != nil) 323 | { 324 | return imageOfWarning; 325 | } 326 | 327 | UIGraphicsBeginImageContextWithOptions(CGSizeMake(80, 80), NO, 0); 328 | [SCLAlertViewStyleKit drawWarning]; 329 | imageOfWarning = UIGraphicsGetImageFromCurrentImageContext(); 330 | UIGraphicsEndImageContext(); 331 | 332 | return imageOfWarning; 333 | } 334 | 335 | + (UIImage*)imageOfInfo 336 | { 337 | if (imageOfInfo != nil) 338 | { 339 | return imageOfInfo; 340 | } 341 | 342 | UIGraphicsBeginImageContextWithOptions(CGSizeMake(80, 80), NO, 0); 343 | [SCLAlertViewStyleKit drawInfo]; 344 | imageOfInfo = UIGraphicsGetImageFromCurrentImageContext(); 345 | UIGraphicsEndImageContext(); 346 | 347 | return imageOfInfo; 348 | } 349 | 350 | + (UIImage*)imageOfEdit 351 | { 352 | if (imageOfEdit != nil) 353 | { 354 | return imageOfEdit; 355 | } 356 | 357 | UIGraphicsBeginImageContextWithOptions(CGSizeMake(80, 80), NO, 0); 358 | [SCLAlertViewStyleKit drawEdit]; 359 | imageOfEdit = UIGraphicsGetImageFromCurrentImageContext(); 360 | UIGraphicsEndImageContext(); 361 | 362 | return imageOfEdit; 363 | } 364 | 365 | + (UIImage*)imageOfQuestion 366 | { 367 | if (imageOfQuestion != nil) 368 | { 369 | return imageOfQuestion; 370 | } 371 | 372 | UIGraphicsBeginImageContextWithOptions(CGSizeMake(80, 80), NO, 0); 373 | [SCLAlertViewStyleKit drawQuestion]; 374 | imageOfQuestion = UIGraphicsGetImageFromCurrentImageContext(); 375 | UIGraphicsEndImageContext(); 376 | 377 | return imageOfQuestion; 378 | } 379 | 380 | @end 381 | -------------------------------------------------------------------------------- /Includes/SCLAlertView/SCLButton.h: -------------------------------------------------------------------------------- 1 | // 2 | // SCLButton.h 3 | // SCLAlertView 4 | // 5 | // Created by Diogo Autilio on 9/26/14. 6 | // Copyright (c) 2014-2017 AnyKey Entertainment. All rights reserved. 7 | // 8 | 9 | #if defined(__has_feature) && __has_feature(modules) 10 | @import UIKit; 11 | #else 12 | #import 13 | #endif 14 | 15 | @class SCLTimerDisplay; 16 | 17 | @interface SCLButton : UIButton 18 | 19 | typedef void (^SCLActionBlock)(void); 20 | typedef BOOL (^SCLValidationBlock)(void); 21 | typedef NSDictionary* (^CompleteButtonFormatBlock)(void); 22 | typedef NSDictionary* (^ButtonFormatBlock)(void); 23 | 24 | // Action Types 25 | typedef NS_ENUM(NSInteger, SCLActionType) 26 | { 27 | SCLNone, 28 | SCLSelector, 29 | SCLBlock 30 | }; 31 | 32 | /** Set button action type. 33 | * 34 | * Holds the button action type. 35 | */ 36 | @property SCLActionType actionType; 37 | 38 | /** Set action button block. 39 | * 40 | * TODO 41 | */ 42 | @property (copy, nonatomic) SCLActionBlock actionBlock; 43 | 44 | /** Set Validation button block. 45 | * 46 | * Set one kind of validation and keeps the alert visible until the validation is successful 47 | */ 48 | @property (copy, nonatomic) SCLValidationBlock validationBlock; 49 | 50 | /** Set Complete button format block. 51 | * 52 | * Holds the complete button format block. 53 | * Support keys : backgroundColor, borderWidth, borderColor, textColor 54 | */ 55 | @property (copy, nonatomic) CompleteButtonFormatBlock completeButtonFormatBlock; 56 | 57 | /** Set button format block. 58 | * 59 | * Holds the button format block. 60 | * Support keys : backgroundColor, borderWidth, borderColor, textColor 61 | */ 62 | @property (copy, nonatomic) ButtonFormatBlock buttonFormatBlock; 63 | 64 | /** Set SCLButton color. 65 | * 66 | * Set SCLButton color. 67 | */ 68 | @property (strong, nonatomic) UIColor *defaultBackgroundColor UI_APPEARANCE_SELECTOR; 69 | 70 | /** Set Target object. 71 | * 72 | * Target is an object that holds the information necessary to send a message to another object when an event occurs. 73 | */ 74 | @property id target; 75 | 76 | /** Set selector id. 77 | * 78 | * A selector is the name used to select a method to execute for an object, 79 | * or the unique identifier that replaces the name when the source code is compiled. 80 | */ 81 | @property SEL selector; 82 | 83 | /** Parse button configuration 84 | * 85 | * Parse ButtonFormatBlock and CompleteButtonFormatBlock setting custom configuration. 86 | * Set keys : backgroundColor, borderWidth, borderColor, textColor 87 | */ 88 | - (void)parseConfig:(NSDictionary *)buttonConfig; 89 | 90 | /** Set button timer. 91 | * 92 | * Holds the button timer, if present. 93 | */ 94 | @property (strong, nonatomic) SCLTimerDisplay *timer; 95 | 96 | /** Init method 97 | * 98 | */ 99 | - (instancetype)initWithWindowWidth:(CGFloat)windowWidth; 100 | 101 | /** Adjust width of the button according to the width of the alert and 102 | * the number of buttons. Only used when buttons are horizontally aligned. 103 | * 104 | * @param windowWidth The width of the alert. 105 | * @param numberOfButtons The number of buttons in the alert. 106 | */ 107 | - (void)adjustWidthWithWindowWidth:(CGFloat)windowWidth numberOfButtons:(NSUInteger)numberOfButtons; 108 | 109 | @end 110 | -------------------------------------------------------------------------------- /Includes/SCLAlertView/SCLButton.m: -------------------------------------------------------------------------------- 1 | // 2 | // SCLButton.m 3 | // SCLAlertView 4 | // 5 | // Created by Diogo Autilio on 9/26/14. 6 | // Copyright (c) 2014-2017 AnyKey Entertainment. All rights reserved. 7 | // 8 | 9 | #import "SCLButton.h" 10 | #import "SCLTimerDisplay.h" 11 | 12 | #define MARGIN_BUTTON 12.0f 13 | #define DEFAULT_WINDOW_WIDTH 240 14 | #define MIN_HEIGHT 35.0f 15 | 16 | @implementation SCLButton 17 | 18 | - (instancetype)init 19 | { 20 | self = [super init]; 21 | if (self) 22 | { 23 | [self setupWithWindowWidth:DEFAULT_WINDOW_WIDTH]; 24 | } 25 | return self; 26 | } 27 | 28 | - (instancetype)initWithWindowWidth:(CGFloat)windowWidth 29 | { 30 | self = [super init]; 31 | if (self) 32 | { 33 | [self setupWithWindowWidth:windowWidth]; 34 | } 35 | return self; 36 | } 37 | 38 | - (instancetype)initWithCoder:(NSCoder *)aDecoder 39 | { 40 | self = [super initWithCoder:aDecoder]; 41 | if(self) 42 | { 43 | [self setupWithWindowWidth:DEFAULT_WINDOW_WIDTH]; 44 | } 45 | return self; 46 | } 47 | 48 | - (instancetype)initWithFrame:(CGRect)frame 49 | { 50 | self = [super initWithFrame:frame]; 51 | if (self) 52 | { 53 | [self setupWithWindowWidth:DEFAULT_WINDOW_WIDTH]; 54 | } 55 | return self; 56 | } 57 | 58 | - (void)setupWithWindowWidth:(CGFloat)windowWidth 59 | { 60 | self.frame = CGRectMake(0.0f, 0.0f, windowWidth - (MARGIN_BUTTON * 2), MIN_HEIGHT); 61 | self.titleLabel.lineBreakMode = NSLineBreakByWordWrapping; 62 | self.titleLabel.textAlignment = NSTextAlignmentCenter; 63 | self.layer.cornerRadius = 3.0f; 64 | } 65 | 66 | - (void)adjustWidthWithWindowWidth:(CGFloat)windowWidth numberOfButtons:(NSUInteger)numberOfButtons 67 | { 68 | CGFloat allButtonsWidth = windowWidth - (MARGIN_BUTTON * 2); 69 | CGFloat buttonWidth = (allButtonsWidth - ((numberOfButtons - 1) * 10)) / numberOfButtons; 70 | 71 | self.frame = CGRectMake(0.0f, 0.0f, buttonWidth, MIN_HEIGHT); 72 | } 73 | 74 | - (void)setTitle:(NSString *)title forState:(UIControlState)state 75 | { 76 | [super setTitle:title forState:state]; 77 | self.titleLabel.numberOfLines = 0; 78 | 79 | // Update title frame. 80 | [self.titleLabel sizeToFit]; 81 | 82 | // Update button frame 83 | [self layoutIfNeeded]; 84 | 85 | // Get height needed to display title label completely 86 | CGFloat buttonHeight = MAX(self.titleLabel.frame.size.height, MIN_HEIGHT); 87 | 88 | // Update button frame 89 | self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y, self.frame.size.width, buttonHeight); 90 | } 91 | 92 | - (void)setHighlighted:(BOOL)highlighted 93 | { 94 | self.backgroundColor = (highlighted) ? [self darkerColorForColor:_defaultBackgroundColor] : _defaultBackgroundColor; 95 | [super setHighlighted:highlighted]; 96 | } 97 | 98 | - (void)setDefaultBackgroundColor:(UIColor *)defaultBackgroundColor 99 | { 100 | self.backgroundColor = _defaultBackgroundColor = defaultBackgroundColor; 101 | } 102 | 103 | - (void)setTimer:(SCLTimerDisplay *)timer 104 | { 105 | _timer = timer; 106 | [self addSubview:timer]; 107 | [timer updateFrame:self.frame.size]; 108 | timer.color = self.titleLabel.textColor; 109 | } 110 | 111 | #pragma mark - Button Apperance 112 | 113 | - (void)parseConfig:(NSDictionary *)buttonConfig 114 | { 115 | if (buttonConfig[@"backgroundColor"]) 116 | { 117 | self.defaultBackgroundColor = buttonConfig[@"backgroundColor"]; 118 | } 119 | if (buttonConfig[@"textColor"]) 120 | { 121 | [self setTitleColor:buttonConfig[@"textColor"] forState:UIControlStateNormal]; 122 | } 123 | if (buttonConfig[@"cornerRadius"]) 124 | { 125 | self.layer.cornerRadius = [buttonConfig[@"cornerRadius"] floatValue]; 126 | } 127 | if ((buttonConfig[@"borderColor"]) && (buttonConfig[@"borderWidth"])) 128 | { 129 | self.layer.borderColor = ((UIColor*)buttonConfig[@"borderColor"]).CGColor; 130 | self.layer.borderWidth = [buttonConfig[@"borderWidth"] floatValue]; 131 | } 132 | else if (buttonConfig[@"borderWidth"]) 133 | { 134 | self.layer.borderWidth = [buttonConfig[@"borderWidth"] floatValue]; 135 | } 136 | 137 | // Add Button custom font with buttonConfig parameters 138 | if (buttonConfig[@"font"]) { 139 | self.titleLabel.font = buttonConfig[@"font"]; 140 | } 141 | } 142 | 143 | #pragma mark - Helpers 144 | 145 | - (UIColor *)darkerColorForColor:(UIColor *)color 146 | { 147 | CGFloat r, g, b, a; 148 | if ([color getRed:&r green:&g blue:&b alpha:&a]) 149 | return [UIColor colorWithRed:MAX(r - 0.2f, 0.0f) 150 | green:MAX(g - 0.2f, 0.0f) 151 | blue:MAX(b - 0.2f, 0.0f) 152 | alpha:a]; 153 | return nil; 154 | } 155 | 156 | - (UIColor *)lighterColorForColor:(UIColor *)color 157 | { 158 | CGFloat r, g, b, a; 159 | if ([color getRed:&r green:&g blue:&b alpha:&a]) 160 | return [UIColor colorWithRed:MIN(r + 0.2f, 1.0f) 161 | green:MIN(g + 0.2f, 1.0f) 162 | blue:MIN(b + 0.2f, 1.0f) 163 | alpha:a]; 164 | return nil; 165 | } 166 | 167 | @end 168 | -------------------------------------------------------------------------------- /Includes/SCLAlertView/SCLMacros.h: -------------------------------------------------------------------------------- 1 | // 2 | // SCLMacros.h 3 | // SCLAlertView 4 | // 5 | // Created by Diogo Autilio on 10/03/15. 6 | // Copyright (c) 2015-2017 AnyKey Entertainment. All rights reserved. 7 | // 8 | 9 | #ifndef SCL_MACROS_H 10 | #define SCL_MACROS_H 11 | 12 | #define UIColorFromHEX(rgbValue) [UIColor \ 13 | colorWithRed:((float)((rgbValue & 0xFF0000) >> 16))/255.0 \ 14 | green:((float)((rgbValue & 0xFF00) >> 8))/255.0 \ 15 | blue:((float)(rgbValue & 0xFF))/255.0 alpha:1.0] 16 | 17 | #define DEGREES_TO_RADIANS(degrees) ((M_PI * degrees)/ 180) 18 | #define TIMER_STEP .01 19 | #define START_DEGREE_OFFSET -90 20 | 21 | #define SYSTEM_VERSION_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedSame) 22 | #define SYSTEM_VERSION_GREATER_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedDescending) 23 | #define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending) 24 | #define SYSTEM_VERSION_LESS_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending) 25 | #define SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedDescending) 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /Includes/SCLAlertView/SCLSwitchView.h: -------------------------------------------------------------------------------- 1 | // 2 | // SCLSwitchView.h 3 | // SCLAlertView 4 | // 5 | // Created by André Felipe Santos on 27/01/16. 6 | // Copyright (c) 2016-2017 AnyKey Entertainment. All rights reserved. 7 | // 8 | 9 | #if defined(__has_feature) && __has_feature(modules) 10 | @import UIKit; 11 | #else 12 | #import 13 | #endif 14 | 15 | @interface SCLSwitchView : UIView 16 | 17 | @property (strong, nonatomic) UIColor *tintColor UI_APPEARANCE_SELECTOR; 18 | @property (strong, nonatomic) UIColor *labelColor UI_APPEARANCE_SELECTOR; 19 | @property (strong, nonatomic) UIFont *labelFont UI_APPEARANCE_SELECTOR; 20 | @property (strong, nonatomic) NSString *labelText UI_APPEARANCE_SELECTOR; 21 | @property (nonatomic, getter=isSelected) BOOL selected; 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /Includes/SCLAlertView/SCLSwitchView.m: -------------------------------------------------------------------------------- 1 | // 2 | // SCLSwitchView.m 3 | // SCLAlertView 4 | // 5 | // Created by André Felipe Santos on 27/01/16. 6 | // Copyright (c) 2016-2017 AnyKey Entertainment. All rights reserved. 7 | // 8 | 9 | #import "SCLSwitchView.h" 10 | #import "SCLMacros.h" 11 | 12 | @interface SCLSwitchView () 13 | 14 | @property (strong, nonatomic) UISwitch *switchKnob; 15 | @property (strong, nonatomic) UILabel *switchLabel; 16 | 17 | @end 18 | 19 | #pragma mark 20 | 21 | @implementation SCLSwitchView 22 | 23 | #pragma mark - Constructors 24 | 25 | - (instancetype)init 26 | { 27 | self = [super init]; 28 | if (self) 29 | { 30 | [self setup]; 31 | } 32 | return self; 33 | } 34 | 35 | - (instancetype)initWithCoder:(NSCoder *)aDecoder 36 | { 37 | self = [super initWithCoder:aDecoder]; 38 | if(self) 39 | { 40 | [self setup]; 41 | } 42 | return self; 43 | } 44 | 45 | - (instancetype)initWithFrame:(CGRect)frame 46 | { 47 | self = [super initWithFrame:frame]; 48 | if (self) 49 | { 50 | [self setup]; 51 | } 52 | return self; 53 | } 54 | 55 | #pragma mark - Initialization 56 | 57 | - (void)setup 58 | { 59 | // Add switch knob 60 | self.switchKnob = [[UISwitch alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 0.0f, 0.f)]; 61 | [self addSubview:self.switchKnob]; 62 | 63 | // Add switch label 64 | CGFloat x, width, height; 65 | x = self.switchKnob.frame.size.width + 8.0f; 66 | width = self.frame.size.width - self.switchKnob.frame.size.width - 8.0f; 67 | height = self.switchKnob.frame.size.height; 68 | 69 | self.switchLabel = [[UILabel alloc] initWithFrame:CGRectMake(x, 0.0f, width, height)]; 70 | 71 | NSString *switchFontFamily = @"HelveticaNeue-Bold"; 72 | CGFloat switchFontSize = 12.0f; 73 | 74 | self.switchLabel.numberOfLines = 1; 75 | self.switchLabel.textAlignment = NSTextAlignmentLeft; 76 | self.switchLabel.lineBreakMode = NSLineBreakByTruncatingTail; 77 | self.switchLabel.adjustsFontSizeToFitWidth = YES; 78 | self.switchLabel.baselineAdjustment = UIBaselineAdjustmentAlignCenters; 79 | self.switchLabel.minimumScaleFactor = 0.5f; 80 | self.switchLabel.font = [UIFont fontWithName:switchFontFamily size:switchFontSize]; 81 | self.switchLabel.textColor = UIColorFromHEX(0x4D4D4D); 82 | 83 | [self addSubview:self.switchLabel]; 84 | } 85 | 86 | #pragma mark - Getters 87 | 88 | - (UIColor *)tintColor 89 | { 90 | return self.switchKnob.tintColor; 91 | } 92 | 93 | - (UIColor *)labelColor 94 | { 95 | return self.switchLabel.textColor; 96 | } 97 | 98 | - (UIFont *)labelFont 99 | { 100 | return self.switchLabel.font; 101 | } 102 | 103 | - (NSString *)labelText 104 | { 105 | return self.switchLabel.text; 106 | } 107 | 108 | - (BOOL)isSelected 109 | { 110 | return self.switchKnob.isOn; 111 | } 112 | 113 | #pragma mark - Setters 114 | 115 | - (void)setTintColor:(UIColor *)tintColor 116 | { 117 | self.switchKnob.onTintColor = tintColor; 118 | } 119 | 120 | - (void)setLabelColor:(UIColor *)labelColor 121 | { 122 | self.switchLabel.textColor = labelColor; 123 | } 124 | 125 | - (void)setLabelFont:(UIFont *)labelFont 126 | { 127 | self.switchLabel.font = labelFont; 128 | } 129 | 130 | - (void)setLabelText:(NSString *)labelText 131 | { 132 | self.switchLabel.text = labelText; 133 | } 134 | 135 | - (void)setSelected:(BOOL)selected 136 | { 137 | self.switchKnob.on = selected; 138 | } 139 | 140 | @end 141 | -------------------------------------------------------------------------------- /Includes/SCLAlertView/SCLTextView.h: -------------------------------------------------------------------------------- 1 | // 2 | // SCLTextView.h 3 | // SCLAlertView 4 | // 5 | // Created by Diogo Autilio on 9/18/15. 6 | // Copyright (c) 2015-2017 AnyKey Entertainment. All rights reserved. 7 | // 8 | 9 | #if defined(__has_feature) && __has_feature(modules) 10 | @import UIKit; 11 | #else 12 | #import 13 | #endif 14 | 15 | @interface SCLTextView : UITextField 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /Includes/SCLAlertView/SCLTextView.m: -------------------------------------------------------------------------------- 1 | // 2 | // SCLTextView.m 3 | // SCLAlertView 4 | // 5 | // Created by Diogo Autilio on 9/18/15. 6 | // Copyright (c) 2015-2017 AnyKey Entertainment. All rights reserved. 7 | // 8 | 9 | #import "SCLTextView.h" 10 | 11 | #define MIN_HEIGHT 30.0f 12 | 13 | @implementation SCLTextView 14 | 15 | - (instancetype)init 16 | { 17 | self = [super init]; 18 | if (self) 19 | { 20 | [self setup]; 21 | } 22 | return self; 23 | } 24 | 25 | - (instancetype)initWithCoder:(NSCoder *)aDecoder 26 | { 27 | self = [super initWithCoder:aDecoder]; 28 | if(self) 29 | { 30 | [self setup]; 31 | } 32 | return self; 33 | } 34 | 35 | - (instancetype)initWithFrame:(CGRect)frame 36 | { 37 | self = [super initWithFrame:frame]; 38 | if (self) 39 | { 40 | [self setup]; 41 | } 42 | return self; 43 | } 44 | 45 | - (void)setup 46 | { 47 | self.frame = CGRectMake(0.0f, 0.0f, 0.0f, MIN_HEIGHT); 48 | self.returnKeyType = UIReturnKeyDone; 49 | self.borderStyle = UITextBorderStyleRoundedRect; 50 | self.autocapitalizationType = UITextAutocapitalizationTypeSentences; 51 | self.clearButtonMode = UITextFieldViewModeWhileEditing; 52 | self.layer.masksToBounds = YES; 53 | self.layer.borderWidth = 1.0f; 54 | } 55 | 56 | @end 57 | -------------------------------------------------------------------------------- /Includes/SCLAlertView/SCLTimerDisplay.h: -------------------------------------------------------------------------------- 1 | // 2 | // SCLTimerDisplay.h 3 | // SCLAlertView 4 | // 5 | // Created by Taylor Ryan on 8/18/15. 6 | // Copyright (c) 2015-2017 AnyKey Entertainment. All rights reserved. 7 | // 8 | // Taken from https://stackoverflow.com/questions/11783439/uibutton-with-timer 9 | 10 | #if defined(__has_feature) && __has_feature(modules) 11 | @import UIKit; 12 | #else 13 | #import 14 | #endif 15 | #import "SCLButton.h" 16 | 17 | @interface SCLTimerDisplay : UIView { 18 | CGFloat currentAngle; 19 | CGFloat currentTime; 20 | CGFloat timerLimit; 21 | CGFloat radius; 22 | CGFloat lineWidth; 23 | NSTimer *timer; 24 | SCLActionBlock completedBlock; 25 | } 26 | 27 | @property CGFloat currentAngle; 28 | @property NSInteger buttonIndex; 29 | @property (strong, nonatomic) UIColor *color; 30 | @property (assign, nonatomic) BOOL reverse; 31 | 32 | - (instancetype)initWithOrigin:(CGPoint)origin radius:(CGFloat)r; 33 | - (instancetype)initWithOrigin:(CGPoint)origin radius:(CGFloat)r lineWidth:(CGFloat)width; 34 | - (void)updateFrame:(CGSize)size; 35 | - (void)cancelTimer; 36 | - (void)stopTimer; 37 | - (void)startTimerWithTimeLimit:(int)tl completed:(SCLActionBlock)completed; 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /Includes/SCLAlertView/SCLTimerDisplay.m: -------------------------------------------------------------------------------- 1 | // 2 | // SCLTimerDisplay.m 3 | // SCLAlertView 4 | // 5 | // Created by Taylor Ryan on 8/18/15. 6 | // Copyright (c) 2015-2017 AnyKey Entertainment. All rights reserved. 7 | // 8 | 9 | #import "SCLTimerDisplay.h" 10 | #import "SCLMacros.h" 11 | 12 | @interface SCLTimerDisplay () 13 | 14 | @property (strong, nonatomic) UILabel *countLabel; 15 | 16 | @end 17 | 18 | @implementation SCLTimerDisplay 19 | 20 | @synthesize currentAngle; 21 | 22 | - (instancetype)initWithFrame:(CGRect)frame 23 | { 24 | self = [super initWithFrame:frame]; 25 | if (self) 26 | { 27 | self.backgroundColor = [UIColor clearColor]; 28 | currentAngle = 0.0f; 29 | } 30 | return self; 31 | } 32 | 33 | - (instancetype)initWithOrigin:(CGPoint)origin radius:(CGFloat)r 34 | { 35 | return [self initWithOrigin:(CGPoint)origin radius:r lineWidth:5.0f]; 36 | } 37 | 38 | - (instancetype)initWithOrigin:(CGPoint)origin radius:(CGFloat)r lineWidth:(CGFloat)width 39 | { 40 | self = [super initWithFrame:CGRectMake(origin.x, origin.y, r*2, r*2)]; 41 | if (self) { 42 | self.backgroundColor = [UIColor clearColor]; 43 | currentAngle = START_DEGREE_OFFSET; 44 | radius = r-(width/2); 45 | lineWidth = width; 46 | self.color = [UIColor whiteColor]; 47 | self.userInteractionEnabled = NO; 48 | 49 | // Add count label 50 | _countLabel = [[UILabel alloc] init]; 51 | _countLabel.textColor = [UIColor whiteColor]; 52 | _countLabel.backgroundColor = [UIColor clearColor]; 53 | _countLabel.font = [UIFont fontWithName: @"HelveticaNeue-Bold" size:12.0f]; 54 | _countLabel.textAlignment = NSTextAlignmentCenter; 55 | _countLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin; 56 | [self addSubview:_countLabel]; 57 | } 58 | return self; 59 | } 60 | 61 | - (void)updateFrame:(CGSize)size 62 | { 63 | CGFloat r = radius+(lineWidth/2); 64 | 65 | CGFloat originX = size.width - (2*r) - 5; 66 | CGFloat originY = (size.height - (2*r))/2; 67 | 68 | self.frame = CGRectMake(originX, originY, r*2, r*2); 69 | self.countLabel.frame = CGRectMake(0, 0, r*2, r*2); 70 | } 71 | 72 | - (void)drawRect:(CGRect)rect 73 | { 74 | UIBezierPath* aPath = [UIBezierPath bezierPathWithArcCenter:CGPointMake(radius+(lineWidth/2), radius+(lineWidth/2)) 75 | radius:radius 76 | startAngle:DEGREES_TO_RADIANS(START_DEGREE_OFFSET) 77 | endAngle:DEGREES_TO_RADIANS(currentAngle) 78 | clockwise:YES]; 79 | [self.color setStroke]; 80 | aPath.lineWidth = lineWidth; 81 | [aPath stroke]; 82 | 83 | _countLabel.text = [NSString stringWithFormat:@"%d", (int)currentTime]; 84 | } 85 | 86 | - (void)startTimerWithTimeLimit:(int)tl completed:(SCLActionBlock)completed 87 | { 88 | if (_reverse) 89 | { 90 | currentTime = tl; 91 | } 92 | timerLimit = tl; 93 | timer = [NSTimer scheduledTimerWithTimeInterval:TIMER_STEP target:self selector:@selector(updateTimerButton:) userInfo:nil repeats:YES]; 94 | completedBlock = completed; 95 | _countLabel.textColor = _color; 96 | } 97 | 98 | - (void)cancelTimer 99 | { 100 | [timer invalidate]; 101 | } 102 | 103 | - (void)stopTimer 104 | { 105 | [timer invalidate]; 106 | if (completedBlock != nil) { 107 | completedBlock(); 108 | } 109 | } 110 | 111 | - (void)updateTimerButton:(NSTimer *)timer 112 | { 113 | if (_reverse) 114 | { 115 | currentTime -= TIMER_STEP; 116 | currentAngle = (currentTime/timerLimit) * 360 + START_DEGREE_OFFSET; 117 | 118 | if(currentTime <= 0) { 119 | [self stopTimer]; 120 | } 121 | } 122 | else { 123 | currentTime += TIMER_STEP; 124 | currentAngle = (currentTime/timerLimit) * 360 + START_DEGREE_OFFSET; 125 | 126 | if(currentAngle >= (360 + START_DEGREE_OFFSET)) { 127 | [self stopTimer]; 128 | } 129 | } 130 | [self setNeedsDisplay]; 131 | } 132 | 133 | @end 134 | -------------------------------------------------------------------------------- /Includes/SCLAlertView/UIImage+ImageEffects.h: -------------------------------------------------------------------------------- 1 | /* 2 | File: UIImage+ImageEffects.h 3 | Abstract: This is a category of UIImage that adds methods to apply blur and tint effects to an image. This is the code you’ll want to look out to find out how to use vImage to efficiently calculate a blur. 4 | Version: 1.0 5 | 6 | Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple 7 | Inc. ("Apple") in consideration of your agreement to the following 8 | terms, and your use, installation, modification or redistribution of 9 | this Apple software constitutes acceptance of these terms. If you do 10 | not agree with these terms, please do not use, install, modify or 11 | redistribute this Apple software. 12 | 13 | In consideration of your agreement to abide by the following terms, and 14 | subject to these terms, Apple grants you a personal, non-exclusive 15 | license, under Apple's copyrights in this original Apple software (the 16 | "Apple Software"), to use, reproduce, modify and redistribute the Apple 17 | Software, with or without modifications, in source and/or binary forms; 18 | provided that if you redistribute the Apple Software in its entirety and 19 | without modifications, you must retain this notice and the following 20 | text and disclaimers in all such redistributions of the Apple Software. 21 | Neither the name, trademarks, service marks or logos of Apple Inc. may 22 | be used to endorse or promote products derived from the Apple Software 23 | without specific prior written permission from Apple. Except as 24 | expressly stated in this notice, no other rights or licenses, express or 25 | implied, are granted by Apple herein, including but not limited to any 26 | patent rights that may be infringed by your derivative works or by other 27 | works in which the Apple Software may be incorporated. 28 | 29 | The Apple Software is provided by Apple on an "AS IS" basis. APPLE 30 | MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION 31 | THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS 32 | FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND 33 | OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. 34 | 35 | IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL 36 | OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 37 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 38 | INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, 39 | MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED 40 | AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), 41 | STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE 42 | POSSIBILITY OF SUCH DAMAGE. 43 | 44 | Copyright (C) 2013 Apple Inc. All Rights Reserved. 45 | 46 | 47 | Copyright © 2013 Apple Inc. All rights reserved. 48 | WWDC 2013 License 49 | 50 | NOTE: This Apple Software was supplied by Apple as part of a WWDC 2013 51 | Session. Please refer to the applicable WWDC 2013 Session for further 52 | information. 53 | 54 | IMPORTANT: This Apple software is supplied to you by Apple Inc. 55 | ("Apple") in consideration of your agreement to the following terms, and 56 | your use, installation, modification or redistribution of this Apple 57 | software constitutes acceptance of these terms. If you do not agree with 58 | these terms, please do not use, install, modify or redistribute this 59 | Apple software. 60 | 61 | In consideration of your agreement to abide by the following terms, and 62 | subject to these terms, Apple grants you a non-exclusive license, under 63 | Apple's copyrights in this original Apple software (the "Apple 64 | Software"), to use, reproduce, modify and redistribute the Apple 65 | Software, with or without modifications, in source and/or binary forms; 66 | provided that if you redistribute the Apple Software in its entirety and 67 | without modifications, you must retain this notice and the following 68 | text and disclaimers in all such redistributions of the Apple Software. 69 | Neither the name, trademarks, service marks or logos of Apple Inc. may 70 | be used to endorse or promote products derived from the Apple Software 71 | without specific prior written permission from Apple. Except as 72 | expressly stated in this notice, no other rights or licenses, express or 73 | implied, are granted by Apple herein, including but not limited to any 74 | patent rights that may be infringed by your derivative works or by other 75 | works in which the Apple Software may be incorporated. 76 | 77 | The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES 78 | NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE 79 | IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR 80 | A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND 81 | OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. 82 | 83 | IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL 84 | OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 85 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 86 | INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, 87 | MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED 88 | AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), 89 | STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE 90 | POSSIBILITY OF SUCH DAMAGE. 91 | 92 | EA1002 93 | 5/3/2013 94 | */ 95 | 96 | #if defined(__has_feature) && __has_feature(modules) 97 | @import UIKit; 98 | #else 99 | #import 100 | #endif 101 | 102 | @interface UIImage (ImageEffects) 103 | 104 | - (UIImage *)applyLightEffect; 105 | - (UIImage *)applyExtraLightEffect; 106 | - (UIImage *)applyDarkEffect; 107 | - (UIImage *)applyTintEffectWithColor:(UIColor *)tintColor; 108 | 109 | - (UIImage *)applyBlurWithRadius:(CGFloat)blurRadius tintColor:(UIColor *)tintColor saturationDeltaFactor:(CGFloat)saturationDeltaFactor maskImage:(UIImage *)maskImage; 110 | 111 | + (UIImage *)imageWithColor:(UIColor *)color; 112 | + (UIImage *)convertViewToImage; 113 | + (UIImage *)convertViewToImage:(UIView *)view; 114 | 115 | @end 116 | -------------------------------------------------------------------------------- /Includes/SCLAlertView/UIImage+ImageEffects.m: -------------------------------------------------------------------------------- 1 | /* 2 | File: UIImage+ImageEffects.m 3 | Abstract: This is a category of UIImage that adds methods to apply blur and tint effects to an image. This is the code you’ll want to look out to find out how to use vImage to efficiently calculate a blur. 4 | Version: 1.0 5 | 6 | Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple 7 | Inc. ("Apple") in consideration of your agreement to the following 8 | terms, and your use, installation, modification or redistribution of 9 | this Apple software constitutes acceptance of these terms. If you do 10 | not agree with these terms, please do not use, install, modify or 11 | redistribute this Apple software. 12 | 13 | In consideration of your agreement to abide by the following terms, and 14 | subject to these terms, Apple grants you a personal, non-exclusive 15 | license, under Apple's copyrights in this original Apple software (the 16 | "Apple Software"), to use, reproduce, modify and redistribute the Apple 17 | Software, with or without modifications, in source and/or binary forms; 18 | provided that if you redistribute the Apple Software in its entirety and 19 | without modifications, you must retain this notice and the following 20 | text and disclaimers in all such redistributions of the Apple Software. 21 | Neither the name, trademarks, service marks or logos of Apple Inc. may 22 | be used to endorse or promote products derived from the Apple Software 23 | without specific prior written permission from Apple. Except as 24 | expressly stated in this notice, no other rights or licenses, express or 25 | implied, are granted by Apple herein, including but not limited to any 26 | patent rights that may be infringed by your derivative works or by other 27 | works in which the Apple Software may be incorporated. 28 | 29 | The Apple Software is provided by Apple on an "AS IS" basis. APPLE 30 | MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION 31 | THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS 32 | FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND 33 | OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. 34 | 35 | IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL 36 | OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 37 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 38 | INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, 39 | MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED 40 | AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), 41 | STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE 42 | POSSIBILITY OF SUCH DAMAGE. 43 | 44 | Copyright (C) 2013 Apple Inc. All Rights Reserved. 45 | 46 | 47 | Copyright © 2013 Apple Inc. All rights reserved. 48 | WWDC 2013 License 49 | 50 | NOTE: This Apple Software was supplied by Apple as part of a WWDC 2013 51 | Session. Please refer to the applicable WWDC 2013 Session for further 52 | information. 53 | 54 | IMPORTANT: This Apple software is supplied to you by Apple Inc. 55 | ("Apple") in consideration of your agreement to the following terms, and 56 | your use, installation, modification or redistribution of this Apple 57 | software constitutes acceptance of these terms. If you do not agree with 58 | these terms, please do not use, install, modify or redistribute this 59 | Apple software. 60 | 61 | In consideration of your agreement to abide by the following terms, and 62 | subject to these terms, Apple grants you a non-exclusive license, under 63 | Apple's copyrights in this original Apple software (the "Apple 64 | Software"), to use, reproduce, modify and redistribute the Apple 65 | Software, with or without modifications, in source and/or binary forms; 66 | provided that if you redistribute the Apple Software in its entirety and 67 | without modifications, you must retain this notice and the following 68 | text and disclaimers in all such redistributions of the Apple Software. 69 | Neither the name, trademarks, service marks or logos of Apple Inc. may 70 | be used to endorse or promote products derived from the Apple Software 71 | without specific prior written permission from Apple. Except as 72 | expressly stated in this notice, no other rights or licenses, express or 73 | implied, are granted by Apple herein, including but not limited to any 74 | patent rights that may be infringed by your derivative works or by other 75 | works in which the Apple Software may be incorporated. 76 | 77 | The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES 78 | NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE 79 | IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR 80 | A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND 81 | OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. 82 | 83 | IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL 84 | OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 85 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 86 | INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, 87 | MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED 88 | AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), 89 | STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE 90 | POSSIBILITY OF SUCH DAMAGE. 91 | 92 | EA1002 93 | 5/3/2013 94 | */ 95 | 96 | #import "UIImage+ImageEffects.h" 97 | #import "SCLMacros.h" 98 | 99 | #if defined(__has_feature) && __has_feature(modules) 100 | @import Accelerate; 101 | #else 102 | #import 103 | #endif 104 | #import 105 | 106 | 107 | @implementation UIImage (ImageEffects) 108 | 109 | 110 | - (UIImage *)applyLightEffect 111 | { 112 | UIColor *tintColor = [UIColor colorWithWhite:1.0 alpha:0.3]; 113 | return [self applyBlurWithRadius:30 tintColor:tintColor saturationDeltaFactor:1.8 maskImage:nil]; 114 | } 115 | 116 | 117 | - (UIImage *)applyExtraLightEffect 118 | { 119 | UIColor *tintColor = [UIColor colorWithWhite:0.97 alpha:0.82]; 120 | return [self applyBlurWithRadius:20 tintColor:tintColor saturationDeltaFactor:1.8 maskImage:nil]; 121 | } 122 | 123 | 124 | - (UIImage *)applyDarkEffect 125 | { 126 | UIColor *tintColor = [UIColor colorWithWhite:0.11 alpha:0.73]; 127 | return [self applyBlurWithRadius:20 tintColor:tintColor saturationDeltaFactor:1.8 maskImage:nil]; 128 | } 129 | 130 | 131 | - (UIImage *)applyTintEffectWithColor:(UIColor *)tintColor 132 | { 133 | const CGFloat EffectColorAlpha = 0.6; 134 | UIColor *effectColor = tintColor; 135 | NSUInteger componentCount = CGColorGetNumberOfComponents(tintColor.CGColor); 136 | if (componentCount == 2) { 137 | CGFloat b; 138 | if ([tintColor getWhite:&b alpha:NULL]) { 139 | effectColor = [UIColor colorWithWhite:b alpha:EffectColorAlpha]; 140 | } 141 | } 142 | else { 143 | CGFloat r, g, b; 144 | if ([tintColor getRed:&r green:&g blue:&b alpha:NULL]) { 145 | effectColor = [UIColor colorWithRed:r green:g blue:b alpha:EffectColorAlpha]; 146 | } 147 | } 148 | return [self applyBlurWithRadius:10 tintColor:effectColor saturationDeltaFactor:-1.0 maskImage:nil]; 149 | } 150 | 151 | 152 | - (UIImage *)applyBlurWithRadius:(CGFloat)blurRadius tintColor:(UIColor *)tintColor saturationDeltaFactor:(CGFloat)saturationDeltaFactor maskImage:(UIImage *)maskImage 153 | { 154 | // Check pre-conditions. 155 | if (self.size.width < 1 || self.size.height < 1) { 156 | NSLog (@"*** error: invalid size: (%.2f x %.2f). Both dimensions must be >= 1: %@", self.size.width, self.size.height, self); 157 | return nil; 158 | } 159 | if (!self.CGImage) { 160 | NSLog (@"*** error: image must be backed by a CGImage: %@", self); 161 | return nil; 162 | } 163 | if (maskImage && !maskImage.CGImage) { 164 | NSLog (@"*** error: maskImage must be backed by a CGImage: %@", maskImage); 165 | return nil; 166 | } 167 | 168 | CGRect imageRect = { CGPointZero, self.size }; 169 | UIImage *effectImage = self; 170 | 171 | BOOL hasBlur = blurRadius > __FLT_EPSILON__; 172 | BOOL hasSaturationChange = fabs(saturationDeltaFactor - 1.) > __FLT_EPSILON__; 173 | if (hasBlur || hasSaturationChange) { 174 | UIGraphicsBeginImageContextWithOptions(self.size, NO, [[UIScreen mainScreen] scale]); 175 | CGContextRef effectInContext = UIGraphicsGetCurrentContext(); 176 | CGContextScaleCTM(effectInContext, 1.0, -1.0); 177 | CGContextTranslateCTM(effectInContext, 0, -self.size.height); 178 | CGContextDrawImage(effectInContext, imageRect, self.CGImage); 179 | 180 | vImage_Buffer effectInBuffer; 181 | effectInBuffer.data = CGBitmapContextGetData(effectInContext); 182 | effectInBuffer.width = CGBitmapContextGetWidth(effectInContext); 183 | effectInBuffer.height = CGBitmapContextGetHeight(effectInContext); 184 | effectInBuffer.rowBytes = CGBitmapContextGetBytesPerRow(effectInContext); 185 | 186 | UIGraphicsBeginImageContextWithOptions(self.size, NO, [[UIScreen mainScreen] scale]); 187 | CGContextRef effectOutContext = UIGraphicsGetCurrentContext(); 188 | vImage_Buffer effectOutBuffer; 189 | effectOutBuffer.data = CGBitmapContextGetData(effectOutContext); 190 | effectOutBuffer.width = CGBitmapContextGetWidth(effectOutContext); 191 | effectOutBuffer.height = CGBitmapContextGetHeight(effectOutContext); 192 | effectOutBuffer.rowBytes = CGBitmapContextGetBytesPerRow(effectOutContext); 193 | 194 | if (hasBlur) { 195 | // A description of how to compute the box kernel width from the Gaussian 196 | // radius (aka standard deviation) appears in the SVG spec: 197 | // http://www.w3.org/TR/SVG/filters.html#feGaussianBlurElement 198 | // 199 | // For larger values of 's' (s >= 2.0), an approximation can be used: Three 200 | // successive box-blurs build a piece-wise quadratic convolution kernel, which 201 | // approximates the Gaussian kernel to within roughly 3%. 202 | // 203 | // let d = floor(s * 3*sqrt(2*pi)/4 + 0.5) 204 | // 205 | // ... if d is odd, use three box-blurs of size 'd', centered on the output pixel. 206 | // 207 | CGFloat inputRadius = blurRadius * [[UIScreen mainScreen] scale]; 208 | uint32_t radius = floor(inputRadius * 3. * sqrt(2 * M_PI) / 4 + 0.5); 209 | if (radius % 2 != 1) { 210 | radius += 1; // force radius to be odd so that the three box-blur methodology works. 211 | } 212 | vImageBoxConvolve_ARGB8888(&effectInBuffer, &effectOutBuffer, NULL, 0, 0, radius, radius, 0, kvImageEdgeExtend); 213 | vImageBoxConvolve_ARGB8888(&effectOutBuffer, &effectInBuffer, NULL, 0, 0, radius, radius, 0, kvImageEdgeExtend); 214 | vImageBoxConvolve_ARGB8888(&effectInBuffer, &effectOutBuffer, NULL, 0, 0, radius, radius, 0, kvImageEdgeExtend); 215 | } 216 | BOOL effectImageBuffersAreSwapped = NO; 217 | if (hasSaturationChange) { 218 | CGFloat s = saturationDeltaFactor; 219 | CGFloat floatingPointSaturationMatrix[] = { 220 | 0.0722 + 0.9278 * s, 0.0722 - 0.0722 * s, 0.0722 - 0.0722 * s, 0, 221 | 0.7152 - 0.7152 * s, 0.7152 + 0.2848 * s, 0.7152 - 0.7152 * s, 0, 222 | 0.2126 - 0.2126 * s, 0.2126 - 0.2126 * s, 0.2126 + 0.7873 * s, 0, 223 | 0, 0, 0, 1, 224 | }; 225 | const int32_t divisor = 256; 226 | NSUInteger matrixSize = sizeof(floatingPointSaturationMatrix)/sizeof(floatingPointSaturationMatrix[0]); 227 | int16_t saturationMatrix[matrixSize]; 228 | for (NSUInteger i = 0; i < matrixSize; ++i) { 229 | saturationMatrix[i] = (int16_t)roundf(floatingPointSaturationMatrix[i] * divisor); 230 | } 231 | if (hasBlur) { 232 | vImageMatrixMultiply_ARGB8888(&effectOutBuffer, &effectInBuffer, saturationMatrix, divisor, NULL, NULL, kvImageNoFlags); 233 | effectImageBuffersAreSwapped = YES; 234 | } 235 | else { 236 | vImageMatrixMultiply_ARGB8888(&effectInBuffer, &effectOutBuffer, saturationMatrix, divisor, NULL, NULL, kvImageNoFlags); 237 | } 238 | } 239 | if (!effectImageBuffersAreSwapped) 240 | effectImage = UIGraphicsGetImageFromCurrentImageContext(); 241 | UIGraphicsEndImageContext(); 242 | 243 | if (effectImageBuffersAreSwapped) 244 | effectImage = UIGraphicsGetImageFromCurrentImageContext(); 245 | UIGraphicsEndImageContext(); 246 | } 247 | 248 | // Set up output context. 249 | UIGraphicsBeginImageContextWithOptions(self.size, NO, [[UIScreen mainScreen] scale]); 250 | CGContextRef outputContext = UIGraphicsGetCurrentContext(); 251 | CGContextScaleCTM(outputContext, 1.0, -1.0); 252 | CGContextTranslateCTM(outputContext, 0, -self.size.height); 253 | 254 | // Draw base image. 255 | CGContextDrawImage(outputContext, imageRect, self.CGImage); 256 | 257 | // Draw effect image. 258 | if (hasBlur) { 259 | CGContextSaveGState(outputContext); 260 | if (maskImage) { 261 | CGContextClipToMask(outputContext, imageRect, maskImage.CGImage); 262 | } 263 | CGContextDrawImage(outputContext, imageRect, effectImage.CGImage); 264 | CGContextRestoreGState(outputContext); 265 | } 266 | 267 | // Add in color tint. 268 | if (tintColor) { 269 | CGContextSaveGState(outputContext); 270 | CGContextSetFillColorWithColor(outputContext, tintColor.CGColor); 271 | CGContextFillRect(outputContext, imageRect); 272 | CGContextRestoreGState(outputContext); 273 | } 274 | 275 | // Output image is ready. 276 | UIImage *outputImage = UIGraphicsGetImageFromCurrentImageContext(); 277 | UIGraphicsEndImageContext(); 278 | 279 | return outputImage; 280 | } 281 | 282 | + (UIImage *)imageWithColor:(UIColor *)color 283 | { 284 | CGRect rect = CGRectMake(0.0f, 0.0f, 1.0f, 1.0f); 285 | UIGraphicsBeginImageContext(rect.size); 286 | CGContextRef context = UIGraphicsGetCurrentContext(); 287 | 288 | CGContextSetFillColorWithColor(context, [color CGColor]); 289 | CGContextFillRect(context, rect); 290 | 291 | UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); 292 | UIGraphicsEndImageContext(); 293 | 294 | return image; 295 | } 296 | 297 | + (UIImage *)convertViewToImage 298 | { 299 | UIWindow *keyWindow = [[UIApplication sharedApplication]keyWindow]; 300 | CGRect rect = [keyWindow bounds]; 301 | UIGraphicsBeginImageContextWithOptions(rect.size, YES, 0.0f); 302 | CGContextRef context = UIGraphicsGetCurrentContext(); 303 | [keyWindow.layer renderInContext:context]; 304 | UIImage *capturedScreen = UIGraphicsGetImageFromCurrentImageContext(); 305 | UIGraphicsEndImageContext(); 306 | 307 | return capturedScreen; 308 | } 309 | 310 | + (UIImage *)convertViewToImage:(UIView *)view 311 | { 312 | CGFloat scale = [UIScreen mainScreen].scale; 313 | UIImage *capturedScreen; 314 | 315 | //Optimized/fast method for rendering a UIView as image on iOS 7 and later versions. 316 | UIGraphicsBeginImageContextWithOptions(view.bounds.size, YES, scale); 317 | [view drawViewHierarchyInRect:view.bounds afterScreenUpdates:NO]; 318 | capturedScreen = UIGraphicsGetImageFromCurrentImageContext(); 319 | UIGraphicsEndImageContext(); 320 | 321 | return capturedScreen; 322 | } 323 | 324 | @end 325 | -------------------------------------------------------------------------------- /Includes/Unity/Unity.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include "Vector3.h" 3 | #include 4 | #include 5 | #include 6 | #import "UIKit/UIKit.h" 7 | #import 8 | #import 9 | #import 10 | #ifndef UNITY_H 11 | #define UNITY_H 12 | 13 | template 14 | struct monoArray 15 | { 16 | 17 | void *klass; 18 | void *monitor; 19 | void *bounds; 20 | int max_length; 21 | void *vector[1]; 22 | int getLength() 23 | { 24 | return max_length; 25 | } 26 | T getPointer() 27 | { 28 | return (T)vector; 29 | } 30 | T operator[](int i) 31 | { 32 | return getPointer()[i]; 33 | } 34 | 35 | const T operator[](int i) const 36 | { 37 | return getPointer()[i]; 38 | } 39 | 40 | bool Contains(T item) 41 | { 42 | for (int i = 0; i < max_length; i++) 43 | { 44 | if (getPointer()[i] == item) 45 | return true; 46 | } 47 | return false; 48 | } 49 | }; 50 | 51 | typedef struct _monoString 52 | { 53 | void *klass; 54 | void *monitor; 55 | int length; 56 | wchar_t chars[1]; 57 | int getLength() 58 | { 59 | return length; 60 | } 61 | const char *getChars() 62 | { 63 | NSString *str = [[NSString alloc] initWithBytes:chars 64 | length:length * sizeof(wchar_t) 65 | encoding:NSUTF16LittleEndianStringEncoding]; 66 | return [str UTF8String]; 67 | } 68 | NSString *toNSString() 69 | { 70 | return [[NSString alloc] initWithBytes:chars 71 | length:length * sizeof(wchar_t) 72 | encoding:NSUTF16LittleEndianStringEncoding]; 73 | } 74 | 75 | char *toCString() 76 | { 77 | NSString *str = toNSString(); 78 | return (char *)[str UTF8String]; 79 | } 80 | std::string toCPPString() 81 | { 82 | return std::string(toCString()); 83 | } 84 | } monoString; 85 | 86 | /* 87 | monoString *CreateMonoString(const char *str) { 88 | monoString *(*String_CreateString)(void *instance, const char *str) = (monoString *(*)(void *, const char *))getRealOffset(0x10257A5B8); 89 | 90 | return String_CreateString(NULL, str); 91 | }*/ 92 | 93 | template 94 | struct monoList 95 | { 96 | void *unk0; 97 | void *unk1; 98 | monoArray *items; 99 | int size; 100 | int version; 101 | 102 | T getItems() 103 | { 104 | return items->getPointer(); 105 | } 106 | 107 | int getSize() 108 | { 109 | return size; 110 | } 111 | 112 | int getVersion() 113 | { 114 | return version; 115 | } 116 | }; 117 | 118 | /* 119 | This struct represents a Dictionary. In the dump, a Dictionary is defined as Dictionary`1. 120 | 121 | You could think of this as a Map in Java or C++. Keys correspond with values. This wraps the C arrays for keys and values. 122 | 123 | If you had this in a dump, 124 | 125 | public class GameManager { 126 | public Dictionary`1 players; // 0xB0 127 | public Dictionary`1 playerWeapons; // 0xB8 128 | public Dictionary`1 playerNames; // 0xBC 129 | } 130 | 131 | to get players, it would look like this: monoDictionary *players = *(monoDictionary **)((uint64_t)player + 0xb0); 132 | to get playerWeapons, it would look like this: monoDictionary *playerWeapons = *(monoDictionary **)((uint64_t)player + 0xb8); 133 | to get playerNames, it would look like this: monoDictionary *playerNames = *(monoDictionary **)((uint64_t)player + 0xbc); 134 | 135 | To get the C array of keys, call getKeys. 136 | To get the C array of values, call getValues. 137 | To get the number of keys, call getNumKeys. 138 | To get the number of values, call getNumValues. 139 | */ 140 | template 141 | struct monoDictionary 142 | { 143 | void *unk0; 144 | void *unk1; 145 | monoArray *table; 146 | monoArray *linkSlots; 147 | monoArray *keys; 148 | monoArray *values; 149 | int touchedSlots; 150 | int emptySlot; 151 | int size; 152 | 153 | K getKeys() 154 | { 155 | return keys->getPointer(); 156 | } 157 | 158 | V getValues() 159 | { 160 | return values->getPointer(); 161 | } 162 | 163 | int getNumKeys() 164 | { 165 | return keys->getLength(); 166 | } 167 | 168 | int getNumValues() 169 | { 170 | return values->getLength(); 171 | } 172 | 173 | int getSize() 174 | { 175 | return size; 176 | } 177 | }; 178 | 179 | template 180 | struct monoDictionary2 181 | { 182 | struct Entry 183 | { 184 | int hashCode, next; 185 | TKey key; 186 | TValue value; 187 | }; 188 | void *klass; 189 | void *monitor; 190 | monoArray *buckets; 191 | monoArray *entries; 192 | int count; 193 | int version; 194 | int freeList; 195 | int freeCount; 196 | void *comparer; 197 | monoArray *keys; 198 | monoArray *values; 199 | void *syncRoot; 200 | 201 | std::map toMap() 202 | { 203 | std::map ret; 204 | auto lst = entries->template toCPPlist(); 205 | for (auto enter : lst) 206 | ret.insert(std::make_pair(enter.key, enter.value)); 207 | return std::move(ret); 208 | } 209 | 210 | std::vector getKeys() 211 | { 212 | std::vector ret; 213 | auto lst = entries->template toCPPlist(); 214 | for (auto enter : lst) 215 | ret.push_back(enter.key); 216 | return std::move(ret); 217 | } 218 | 219 | std::vector getValues() 220 | { 221 | std::vector ret; 222 | auto lst = entries->template toCPPlist(); 223 | for (auto enter : lst) 224 | ret.push_back(enter.value); 225 | return std::move(ret); 226 | } 227 | 228 | int getSize() 229 | { 230 | return count; 231 | } 232 | 233 | int getVersion() 234 | { 235 | return version; 236 | } 237 | 238 | bool TryGet(TKey key, TValue &value); 239 | void Add(TKey key, TValue value); 240 | void Insert(TKey key, TValue value); 241 | bool Remove(TKey key); 242 | bool ContainsKey(TKey key); 243 | bool ContainsValue(TValue value); 244 | 245 | TValue Get(TKey key) 246 | { 247 | TValue ret; 248 | if (TryGet(key, ret)) 249 | return ret; 250 | return {}; 251 | } 252 | 253 | TValue operator[](TKey key) 254 | { 255 | return Get(key); 256 | } 257 | }; 258 | 259 | inline int GetObscuredIntValue(uint64_t location) 260 | { 261 | int cryptoKey = *(int *)location; 262 | int obfuscatedValue = *(int *)(location + 0x4); 263 | return obfuscatedValue ^ cryptoKey; 264 | } 265 | 266 | inline bool GetObscuredBoolValue(uint64_t location) 267 | { 268 | int cryptoKey = *(int *)location; 269 | int obfuscatedValue = *(int *)(location + 0x4); 270 | return (bool)obfuscatedValue ^ cryptoKey; 271 | } 272 | 273 | inline void SetObscuredIntValue(uint64_t location, int value) 274 | { 275 | int cryptoKey = *(int *)location; 276 | *(int *)(location + 0x4) = value ^ cryptoKey; 277 | } 278 | 279 | inline void SetObscuredBoolValue(uint64_t location, bool value) 280 | { 281 | int cryptoKey = *(int *)location; 282 | *(int *)(location + 0x4) = value ^ cryptoKey; 283 | } 284 | 285 | inline float GetObscuredFloatValue(uint64_t location) 286 | { 287 | int cryptoKey = *(int *)location; 288 | int obfuscatedValue = *(int *)(location + 0x4); 289 | 290 | union intfloat 291 | { 292 | int i; 293 | float f; 294 | }; 295 | 296 | /* use this intfloat to set the integer representation of our parameter value, which will also set the float value */ 297 | intfloat IF; 298 | IF.i = obfuscatedValue ^ cryptoKey; 299 | 300 | return IF.f; 301 | } 302 | 303 | inline void SetObscuredFloatValue(uint64_t location, float value) 304 | { 305 | int cryptoKey = *(int *)location; 306 | 307 | union intfloat 308 | { 309 | int i; 310 | float f; 311 | }; 312 | 313 | /* use this intfloat to get the integer representation of our parameter value */ 314 | intfloat IF; 315 | IF.f = value; 316 | 317 | /* use this intfloat to generate our hacked ObscuredFloat */ 318 | intfloat IF2; 319 | IF2.i = IF.i ^ cryptoKey; 320 | 321 | *(float *)(location + 0x4) = IF2.f; 322 | } 323 | #endif UNITY_H 324 | -------------------------------------------------------------------------------- /Includes/Unity/Vector3.h: -------------------------------------------------------------------------------- 1 | /** 2 | * ============================================================================ 3 | * MIT License 4 | * 5 | * Copyright (c) 2016 Eric Phillips 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a 8 | * copy of this software and associated documentation files (the "Software"), 9 | * to deal in the Software without restriction, including without limitation 10 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | * and/or sell copies of the Software, and to permit persons to whom the 12 | * Software is furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | * DEALINGS IN THE SOFTWARE. 24 | * ============================================================================ 25 | * 26 | * 27 | * This file implements a series of math functions for manipulating a 28 | * 3D vector. 29 | * 30 | * Created by Eric Phillips on October 8, 2016. 31 | */ 32 | 33 | #pragma once 34 | 35 | #define _USE_MATH_DEFINES 36 | #include 37 | 38 | 39 | struct Vector3 40 | { 41 | union 42 | { 43 | struct 44 | { 45 | float x; 46 | float y; 47 | float z; 48 | }; 49 | float data[3]; 50 | }; 51 | 52 | 53 | 54 | /** 55 | * Constructors. 56 | */ 57 | inline Vector3(); 58 | inline Vector3(float data[]); 59 | inline Vector3(float value); 60 | inline Vector3(float x, float y); 61 | inline Vector3(float x, float y, float z); 62 | inline Vector3(const Vector3 &v); 63 | 64 | 65 | /** 66 | * Constants for common vectors. 67 | */ 68 | static inline Vector3 Zero(); 69 | static inline Vector3 One(); 70 | static inline Vector3 Right(); 71 | static inline Vector3 Left(); 72 | static inline Vector3 Up(); 73 | static inline Vector3 Down(); 74 | static inline Vector3 Forward(); 75 | static inline Vector3 Backward(); 76 | 77 | 78 | /** 79 | * Returns the angle between two vectors in radians. 80 | * @param a: The first vector. 81 | * @param b: The second vector. 82 | * @return: A scalar value. 83 | */ 84 | static inline float Angle(Vector3 a, Vector3 b); 85 | 86 | /** 87 | * Returns a vector with its magnitude clamped to maxLength. 88 | * @param vector: The target vector. 89 | * @param maxLength: The maximum length of the return vector. 90 | * @return: A new vector. 91 | */ 92 | static inline Vector3 ClampMagnitude(Vector3 vector, float maxLength); 93 | 94 | /** 95 | * Returns the component of a in the direction of b (scalar projection). 96 | * @param a: The target vector. 97 | * @param b: The vector being compared against. 98 | * @return: A scalar value. 99 | */ 100 | static inline float Component(Vector3 a, Vector3 b); 101 | 102 | /** 103 | * Returns the cross product of two vectors. 104 | * @param lhs: The left side of the multiplication. 105 | * @param rhs: The right side of the multiplication. 106 | * @return: A new vector. 107 | */ 108 | static inline Vector3 Cross(Vector3 lhs, Vector3 rhs); 109 | 110 | /** 111 | * Returns the distance between a and b. 112 | * @param a: The first point. 113 | * @param b: The second point. 114 | * @return: A scalar value. 115 | */ 116 | static inline float Distance(Vector3 a, Vector3 b); 117 | 118 | static inline char ToChar(Vector3 a); 119 | 120 | /** 121 | * Returns the dot product of two vectors. 122 | * @param lhs: The left side of the multiplication. 123 | * @param rhs: The right side of the multiplication. 124 | * @return: A scalar value. 125 | */ 126 | static inline float Dot(Vector3 lhs, Vector3 rhs); 127 | 128 | /** 129 | * Converts a spherical representation of a vector into cartesian 130 | * coordinates. 131 | * This uses the ISO convention (radius r, inclination theta, azimuth phi). 132 | * @param rad: The magnitude of the vector. 133 | * @param theta: The angle in the XY plane from the x axis. 134 | * @param phi: The angle from the positive z axis to the vector. 135 | * @return: A new vector. 136 | */ 137 | static inline Vector3 FromSpherical(float rad, float theta, float phi); 138 | 139 | /** 140 | * Returns a vector linearly interpolated between a and b, moving along 141 | * a straight line. The vector is clamped to never go beyond the end points. 142 | * @param a: The starting point. 143 | * @param b: The ending point. 144 | * @param t: The interpolation value [0-1]. 145 | * @return: A new vector. 146 | */ 147 | static inline Vector3 Lerp(Vector3 a, Vector3 b, float t); 148 | 149 | /** 150 | * Returns a vector linearly interpolated between a and b, moving along 151 | * a straight line. 152 | * @param a: The starting point. 153 | * @param b: The ending point. 154 | * @param t: The interpolation value [0-1] (no actual bounds). 155 | * @return: A new vector. 156 | */ 157 | static inline Vector3 LerpUnclamped(Vector3 a, Vector3 b, float t); 158 | 159 | /** 160 | * Returns the magnitude of a vector. 161 | * @param v: The vector in question. 162 | * @return: A scalar value. 163 | */ 164 | static inline float Magnitude(Vector3 v); 165 | 166 | /** 167 | * Returns a vector made from the largest components of two other vectors. 168 | * @param a: The first vector. 169 | * @param b: The second vector. 170 | * @return: A new vector. 171 | */ 172 | static inline Vector3 Max(Vector3 a, Vector3 b); 173 | 174 | /** 175 | * Returns a vector made from the smallest components of two other vectors. 176 | * @param a: The first vector. 177 | * @param b: The second vector. 178 | * @return: A new vector. 179 | */ 180 | static inline Vector3 Min(Vector3 a, Vector3 b); 181 | 182 | /** 183 | * Returns a vector "maxDistanceDelta" units closer to the target. This 184 | * interpolation is in a straight line, and will not overshoot. 185 | * @param current: The current position. 186 | * @param target: The destination position. 187 | * @param maxDistanceDelta: The maximum distance to move. 188 | * @return: A new vector. 189 | */ 190 | static inline Vector3 MoveTowards(Vector3 current, Vector3 target, 191 | float maxDistanceDelta); 192 | 193 | /** 194 | * Returns a new vector with magnitude of one. 195 | * @param v: The vector in question. 196 | * @return: A new vector. 197 | */ 198 | static inline Vector3 Normalized(Vector3 v); 199 | 200 | /** 201 | * Returns an arbitrary vector orthogonal to the input. 202 | * This vector is not normalized. 203 | * @param v: The input vector. 204 | * @return: A new vector. 205 | */ 206 | static inline Vector3 Orthogonal(Vector3 v); 207 | 208 | /** 209 | * Creates a new coordinate system out of the three vectors. 210 | * Normalizes "normal", normalizes "tangent" and makes it orthogonal to 211 | * "normal" and normalizes "binormal" and makes it orthogonal to both 212 | * "normal" and "tangent". 213 | * @param normal: A reference to the first axis vector. 214 | * @param tangent: A reference to the second axis vector. 215 | * @param binormal: A reference to the third axis vector. 216 | */ 217 | static inline void OrthoNormalize(Vector3 &normal, Vector3 &tangent, 218 | Vector3 &binormal); 219 | 220 | /** 221 | * Returns the vector projection of a onto b. 222 | * @param a: The target vector. 223 | * @param b: The vector being projected onto. 224 | * @return: A new vector. 225 | */ 226 | static inline Vector3 Project(Vector3 a, Vector3 b); 227 | 228 | /** 229 | * Returns a vector projected onto a plane orthogonal to "planeNormal". 230 | * This can be visualized as the shadow of the vector onto the plane, if 231 | * the light source were in the direction of the plane normal. 232 | * @param vector: The vector to project. 233 | * @param planeNormal: The normal of the plane onto which to project. 234 | * @param: A new vector. 235 | */ 236 | static inline Vector3 ProjectOnPlane(Vector3 vector, Vector3 planeNormal); 237 | 238 | /** 239 | * Returns a vector reflected off the plane orthogonal to the normal. 240 | * The input vector is pointed inward, at the plane, and the return vector 241 | * is pointed outward from the plane, like a beam of light hitting and then 242 | * reflecting off a mirror. 243 | * @param vector: The vector traveling inward at the plane. 244 | * @param planeNormal: The normal of the plane off of which to reflect. 245 | * @return: A new vector pointing outward from the plane. 246 | */ 247 | static inline Vector3 Reflect(Vector3 vector, Vector3 planeNormal); 248 | 249 | /** 250 | * Returns the vector rejection of a on b. 251 | * @param a: The target vector. 252 | * @param b: The vector being projected onto. 253 | * @return: A new vector. 254 | */ 255 | static inline Vector3 Reject(Vector3 a, Vector3 b); 256 | 257 | /** 258 | * Rotates vector "current" towards vector "target" by "maxRadiansDelta". 259 | * This treats the vectors as directions and will linearly interpolate 260 | * between their magnitudes by "maxMagnitudeDelta". This function does not 261 | * overshoot. If a negative delta is supplied, it will rotate away from 262 | * "target" until it is pointing the opposite direction, but will not 263 | * overshoot that either. 264 | * @param current: The starting direction. 265 | * @param target: The destination direction. 266 | * @param maxRadiansDelta: The maximum number of radians to rotate. 267 | * @param maxMagnitudeDelta: The maximum delta for magnitude interpolation. 268 | * @return: A new vector. 269 | */ 270 | static inline Vector3 RotateTowards(Vector3 current, Vector3 target, 271 | float maxRadiansDelta, 272 | float maxMagnitudeDelta); 273 | 274 | /** 275 | * Multiplies two vectors element-wise. 276 | * @param a: The lhs of the multiplication. 277 | * @param b: The rhs of the multiplication. 278 | * @return: A new vector. 279 | */ 280 | static inline Vector3 Scale(Vector3 a, Vector3 b); 281 | 282 | /** 283 | * Returns a vector rotated towards b from a by the percent t. 284 | * Since interpolation is done spherically, the vector moves at a constant 285 | * angular velocity. This rotation is clamped to 0 <= t <= 1. 286 | * @param a: The starting direction. 287 | * @param b: The ending direction. 288 | * @param t: The interpolation value [0-1]. 289 | */ 290 | static inline Vector3 Slerp(Vector3 a, Vector3 b, float t); 291 | 292 | /** 293 | * Returns a vector rotated towards b from a by the percent t. 294 | * Since interpolation is done spherically, the vector moves at a constant 295 | * angular velocity. This rotation is unclamped. 296 | * @param a: The starting direction. 297 | * @param b: The ending direction. 298 | * @param t: The interpolation value [0-1]. 299 | */ 300 | static inline Vector3 SlerpUnclamped(Vector3 a, Vector3 b, float t); 301 | 302 | /** 303 | * Returns the squared magnitude of a vector. 304 | * This is useful when comparing relative lengths, where the exact length 305 | * is not important, and much time can be saved by not calculating the 306 | * square root. 307 | * @param v: The vector in question. 308 | * @return: A scalar value. 309 | */ 310 | static inline float SqrMagnitude(Vector3 v); 311 | 312 | /** 313 | * Calculates the spherical coordinate space representation of a vector. 314 | * This uses the ISO convention (radius r, inclination theta, azimuth phi). 315 | * @param vector: The vector to convert. 316 | * @param rad: The magnitude of the vector. 317 | * @param theta: The angle in the XY plane from the x axis. 318 | * @param phi: The angle from the positive z axis to the vector. 319 | */ 320 | static inline void ToSpherical(Vector3 vector, float &rad, float &theta, 321 | float &phi); 322 | 323 | 324 | /** 325 | * Operator overloading. 326 | */ 327 | inline struct Vector3& operator+=(const float rhs); 328 | inline struct Vector3& operator-=(const float rhs); 329 | inline struct Vector3& operator*=(const float rhs); 330 | inline struct Vector3& operator/=(const float rhs); 331 | inline struct Vector3& operator+=(const Vector3 rhs); 332 | inline struct Vector3& operator-=(const Vector3 rhs); 333 | }; 334 | 335 | inline Vector3 operator-(Vector3 rhs); 336 | inline Vector3 operator+(Vector3 lhs, const float rhs); 337 | inline Vector3 operator-(Vector3 lhs, const float rhs); 338 | inline Vector3 operator*(Vector3 lhs, const float rhs); 339 | inline Vector3 operator/(Vector3 lhs, const float rhs); 340 | inline Vector3 operator+(const float lhs, Vector3 rhs); 341 | inline Vector3 operator-(const float lhs, Vector3 rhs); 342 | inline Vector3 operator*(const float lhs, Vector3 rhs); 343 | inline Vector3 operator/(const float lhs, Vector3 rhs); 344 | inline Vector3 operator+(Vector3 lhs, const Vector3 rhs); 345 | inline Vector3 operator-(Vector3 lhs, const Vector3 rhs); 346 | inline bool operator==(const Vector3 lhs, const Vector3 rhs); 347 | inline bool operator!=(const Vector3 lhs, const Vector3 rhs); 348 | 349 | 350 | 351 | /******************************************************************************* 352 | * Implementation 353 | */ 354 | 355 | Vector3::Vector3() : x(0), y(0), z(0) {} 356 | Vector3::Vector3(float data[]) : x(data[0]), y(data[1]), z(data[2]) {} 357 | Vector3::Vector3(float value) : x(value), y(value), z(value) {} 358 | Vector3::Vector3(float x, float y) : x(x), y(y), z(0) {} 359 | Vector3::Vector3(float x, float y, float z) : x(x), y(y), z(z) {} 360 | 361 | //Vector3(const Vector3 &v); 362 | Vector3::Vector3(const Vector3 &v) : x(v.x), y(v.y), z(v.z) {} 363 | 364 | 365 | Vector3 Vector3::Zero() { return Vector3(0, 0, 0); } 366 | Vector3 Vector3::One() { return Vector3(1, 1, 1); } 367 | Vector3 Vector3::Right() { return Vector3(1, 0, 0); } 368 | Vector3 Vector3::Left() { return Vector3(-1, 0, 0); } 369 | Vector3 Vector3::Up() { return Vector3(0, 1, 0); } 370 | Vector3 Vector3::Down() { return Vector3(0, -1, 0); } 371 | Vector3 Vector3::Forward() { return Vector3(0, 0, 1); } 372 | Vector3 Vector3::Backward() { return Vector3(0, 0, -1); } 373 | 374 | 375 | float Vector3::Angle(Vector3 a, Vector3 b) 376 | { 377 | float v = Dot(a, b) / (Magnitude(a) * Magnitude(b)); 378 | v = fmax(v, -1.0); 379 | v = fmin(v, 1.0); 380 | return acos(v); 381 | } 382 | 383 | Vector3 Vector3::ClampMagnitude(Vector3 vector, float maxLength) 384 | { 385 | float length = Magnitude(vector); 386 | if (length > maxLength) 387 | vector *= maxLength / length; 388 | return vector; 389 | } 390 | 391 | float Vector3::Component(Vector3 a, Vector3 b) 392 | { 393 | return Dot(a, b) / Magnitude(b); 394 | } 395 | 396 | Vector3 Vector3::Cross(Vector3 lhs, Vector3 rhs) 397 | { 398 | float x = lhs.y * rhs.z - lhs.z * rhs.y; 399 | float y = lhs.z * rhs.x - lhs.x * rhs.z; 400 | float z = lhs.x * rhs.y - lhs.y * rhs.x; 401 | return Vector3(x, y, z); 402 | } 403 | 404 | float Vector3::Distance(Vector3 a, Vector3 b) 405 | { 406 | return Vector3::Magnitude(a - b); 407 | } 408 | 409 | float Vector3::Dot(Vector3 lhs, Vector3 rhs) 410 | { 411 | return lhs.x * rhs.x + lhs.y * rhs.y + lhs.z * rhs.z; 412 | } 413 | 414 | Vector3 Vector3::FromSpherical(float rad, float theta, float phi) 415 | { 416 | Vector3 v; 417 | v.x = rad * sin(theta) * cos(phi); 418 | v.y = rad * sin(theta) * sin(phi); 419 | v.z = rad * cos(theta); 420 | return v; 421 | } 422 | 423 | Vector3 Vector3::Lerp(Vector3 a, Vector3 b, float t) 424 | { 425 | if (t < 0) return a; 426 | else if (t > 1) return b; 427 | return LerpUnclamped(a, b, t); 428 | } 429 | 430 | Vector3 Vector3::LerpUnclamped(Vector3 a, Vector3 b, float t) 431 | { 432 | return (b - a) * t + a; 433 | } 434 | 435 | float Vector3::Magnitude(Vector3 v) 436 | { 437 | return sqrt(SqrMagnitude(v)); 438 | } 439 | 440 | Vector3 Vector3::Max(Vector3 a, Vector3 b) 441 | { 442 | float x = a.x > b.x ? a.x : b.x; 443 | float y = a.y > b.y ? a.y : b.y; 444 | float z = a.z > b.z ? a.z : b.z; 445 | return Vector3(x, y, z); 446 | } 447 | 448 | Vector3 Vector3::Min(Vector3 a, Vector3 b) 449 | { 450 | float x = a.x > b.x ? b.x : a.x; 451 | float y = a.y > b.y ? b.y : a.y; 452 | float z = a.z > b.z ? b.z : a.z; 453 | return Vector3(x, y, z); 454 | } 455 | 456 | Vector3 Vector3::MoveTowards(Vector3 current, Vector3 target, 457 | float maxDistanceDelta) 458 | { 459 | Vector3 d = target - current; 460 | float m = Magnitude(d); 461 | if (m < maxDistanceDelta || m == 0) 462 | return target; 463 | return current + (d * maxDistanceDelta / m); 464 | } 465 | 466 | Vector3 Vector3::Normalized(Vector3 v) 467 | { 468 | float mag = Magnitude(v); 469 | if (mag == 0) 470 | return Vector3::Zero(); 471 | return v / mag; 472 | } 473 | 474 | Vector3 Vector3::Orthogonal(Vector3 v) 475 | { 476 | return v.z < v.x ? Vector3(v.y, -v.x, 0) : Vector3(0, -v.z, v.y); 477 | } 478 | 479 | void Vector3::OrthoNormalize(Vector3 &normal, Vector3 &tangent, 480 | Vector3 &binormal) 481 | { 482 | normal = Normalized(normal); 483 | tangent = ProjectOnPlane(tangent, normal); 484 | tangent = Normalized(tangent); 485 | binormal = ProjectOnPlane(binormal, tangent); 486 | binormal = ProjectOnPlane(binormal, normal); 487 | binormal = Normalized(binormal); 488 | } 489 | 490 | Vector3 Vector3::Project(Vector3 a, Vector3 b) 491 | { 492 | float m = Magnitude(b); 493 | return Dot(a, b) / (m * m) * b; 494 | } 495 | 496 | Vector3 Vector3::ProjectOnPlane(Vector3 vector, Vector3 planeNormal) 497 | { 498 | return Reject(vector, planeNormal); 499 | } 500 | 501 | Vector3 Vector3::Reflect(Vector3 vector, Vector3 planeNormal) 502 | { 503 | return vector - 2 * Project(vector, planeNormal); 504 | } 505 | 506 | Vector3 Vector3::Reject(Vector3 a, Vector3 b) 507 | { 508 | return a - Project(a, b); 509 | } 510 | 511 | Vector3 Vector3::RotateTowards(Vector3 current, Vector3 target, 512 | float maxRadiansDelta, 513 | float maxMagnitudeDelta) 514 | { 515 | float magCur = Magnitude(current); 516 | float magTar = Magnitude(target); 517 | float newMag = magCur + maxMagnitudeDelta * 518 | ((magTar > magCur) - (magCur > magTar)); 519 | newMag = fmin(newMag, fmax(magCur, magTar)); 520 | newMag = fmax(newMag, fmin(magCur, magTar)); 521 | 522 | float totalAngle = Angle(current, target) - maxRadiansDelta; 523 | if (totalAngle <= 0) 524 | return Normalized(target) * newMag; 525 | else if (totalAngle >= M_PI) 526 | return Normalized(-target) * newMag; 527 | 528 | Vector3 axis = Cross(current, target); 529 | float magAxis = Magnitude(axis); 530 | if (magAxis == 0) 531 | axis = Normalized(Cross(current, current + Vector3(3.95, 5.32, -4.24))); 532 | else 533 | axis /= magAxis; 534 | current = Normalized(current); 535 | Vector3 newVector = current * cos(maxRadiansDelta) + 536 | Cross(axis, current) * sin(maxRadiansDelta); 537 | return newVector * newMag; 538 | } 539 | 540 | Vector3 Vector3::Scale(Vector3 a, Vector3 b) 541 | { 542 | return Vector3(a.x * b.x, a.y * b.y, a.z * b.z); 543 | } 544 | 545 | Vector3 Vector3::Slerp(Vector3 a, Vector3 b, float t) 546 | { 547 | if (t < 0) return a; 548 | else if (t > 1) return b; 549 | return SlerpUnclamped(a, b, t); 550 | } 551 | 552 | Vector3 Vector3::SlerpUnclamped(Vector3 a, Vector3 b, float t) 553 | { 554 | float magA = Magnitude(a); 555 | float magB = Magnitude(b); 556 | a /= magA; 557 | b /= magB; 558 | float dot = Dot(a, b); 559 | dot = fmax(dot, -1.0); 560 | dot = fmin(dot, 1.0); 561 | float theta = acos(dot) * t; 562 | Vector3 relativeVec = Normalized(b - a * dot); 563 | Vector3 newVec = a * cos(theta) + relativeVec * sin(theta); 564 | return newVec * (magA + (magB - magA) * t); 565 | } 566 | 567 | float Vector3::SqrMagnitude(Vector3 v) 568 | { 569 | return v.x * v.x + v.y * v.y + v.z * v.z; 570 | } 571 | 572 | void Vector3::ToSpherical(Vector3 vector, float &rad, float &theta, 573 | float &phi) 574 | { 575 | rad = Magnitude(vector); 576 | float v = vector.z / rad; 577 | v = fmax(v, -1.0); 578 | v = fmin(v, 1.0); 579 | theta = acos(v); 580 | phi = atan2(vector.y, vector.x); 581 | } 582 | 583 | 584 | struct Vector3& Vector3::operator+=(const float rhs) 585 | { 586 | x += rhs; 587 | y += rhs; 588 | z += rhs; 589 | return *this; 590 | } 591 | 592 | struct Vector3& Vector3::operator-=(const float rhs) 593 | { 594 | x -= rhs; 595 | y -= rhs; 596 | z -= rhs; 597 | return *this; 598 | } 599 | 600 | struct Vector3& Vector3::operator*=(const float rhs) 601 | { 602 | x *= rhs; 603 | y *= rhs; 604 | z *= rhs; 605 | return *this; 606 | } 607 | 608 | struct Vector3& Vector3::operator/=(const float rhs) 609 | { 610 | x /= rhs; 611 | y /= rhs; 612 | z /= rhs; 613 | return *this; 614 | } 615 | 616 | struct Vector3& Vector3::operator+=(const Vector3 rhs) 617 | { 618 | x += rhs.x; 619 | y += rhs.y; 620 | z += rhs.z; 621 | return *this; 622 | } 623 | 624 | struct Vector3& Vector3::operator-=(const Vector3 rhs) 625 | { 626 | x -= rhs.x; 627 | y -= rhs.y; 628 | z -= rhs.z; 629 | return *this; 630 | } 631 | 632 | char Vector3::ToChar(Vector3 a) { 633 | /* 634 | const char* x = (const char*)(intptr_t)a.x; 635 | const char* y = (const char*)(intptr_t)a.y; 636 | const char* z = (const char*)(intptr_t)a.z; 637 | char buffer[25]; 638 | strncpy(buffer, x, sizeof(buffer)); 639 | strncpy(buffer, ", ", sizeof(buffer)); 640 | strncpy(buffer, y, sizeof(buffer)); 641 | strncpy(buffer, ", ", sizeof(buffer)); 642 | strncpy(buffer, z, sizeof(buffer)); 643 | strncpy(buffer, ", ", sizeof(buffer)); 644 | return buffer[25]; 645 | */ 646 | return '\0'; 647 | } 648 | 649 | Vector3 operator-(Vector3 rhs) { return rhs * -1; } 650 | Vector3 operator+(Vector3 lhs, const float rhs) { return lhs += rhs; } 651 | Vector3 operator-(Vector3 lhs, const float rhs) { return lhs -= rhs; } 652 | Vector3 operator*(Vector3 lhs, const float rhs) { return lhs *= rhs; } 653 | Vector3 operator/(Vector3 lhs, const float rhs) { return lhs /= rhs; } 654 | Vector3 operator+(const float lhs, Vector3 rhs) { return rhs += lhs; } 655 | Vector3 operator-(const float lhs, Vector3 rhs) { return rhs -= lhs; } 656 | Vector3 operator*(const float lhs, Vector3 rhs) { return rhs *= lhs; } 657 | Vector3 operator/(const float lhs, Vector3 rhs) { return rhs /= lhs; } 658 | Vector3 operator+(Vector3 lhs, const Vector3 rhs) { return lhs += rhs; } 659 | Vector3 operator-(Vector3 lhs, const Vector3 rhs) { return lhs -= rhs; } 660 | 661 | bool operator==(const Vector3 lhs, const Vector3 rhs) 662 | { 663 | return lhs.x == rhs.x && lhs.y == rhs.y && lhs.z == rhs.z; 664 | } 665 | 666 | bool operator!=(const Vector3 lhs, const Vector3 rhs) 667 | { 668 | return !(lhs == rhs); 669 | } 670 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ARCHS = arm64 2 | DEBUG = 0 3 | FINALPACKAGE = 1 4 | FOR_RELEASE = 1 5 | 6 | TARGET = iphone:clang:latest:latest 7 | CFLAGS = -fobjc-arc 8 | 9 | include $(THEOS)/makefiles/common.mk 10 | 11 | TWEAK_NAME = iOSImGui 12 | 13 | $(TWEAK_NAME)_FRAMEWORKS = UIKit Foundation Security QuartzCore CoreGraphics CoreText AVFoundation Accelerate GLKit SystemConfiguration GameController 14 | $(TWEAK_NAME)_CCFLAGS = -std=c++11 -fno-rtti -fno-exceptions -DNDEBUG 15 | $(TWEAK_NAME)_CFLAGS = -fobjc-arc -w 16 | $(TWEAK_NAME)_FILES = Menu.mm Mods.mm $(wildcard ImGui/*.mm) $(wildcard ImGui/*.cpp) $(wildcard Includes/*.mm) $(wildcard Includes/*.m) $(wildcard Includes/*.cpp) $(wildcard Includes/Esp/*.m) $(wildcard Includes/Hooking/*.mm) $(wildcard Includes/SCLAlertView/*.m) 17 | 18 | $(TWEAK_NAME)_LIBRARIES += substrate 19 | $(TWEAK_NAME)_LDFLAGS += -L./Includes/Libs 20 | $(TWEAK_NAME)_LDFLAGS += -lz -stdlib=libc++ -ldobby_fixed 21 | 22 | #LQMNemOS_LIBRARIES += substrate 23 | # GO_EASY_ON_ME = 1 24 | 25 | include $(THEOS_MAKE_PATH)/tweak.mk 26 | include $(THEOS)/makefiles/aggregate.mk 27 | after-install:: 28 | install.exec "killall -9 Springboard || :" 29 | -------------------------------------------------------------------------------- /Menu.h: -------------------------------------------------------------------------------- 1 | #ifndef Menu_h 2 | #define Menu_h 3 | #include 4 | #include 5 | #include 6 | #include "ImGui/imgui.h" 7 | #include "ImGui/imgui_internal.h" 8 | #include "ImGui/imgui_impl_metal.h" 9 | #include "ImGui/CustomWidgets.h" 10 | #include "Includes/Fonts/Fonts.hpp" 11 | #include "Mods.h" 12 | 13 | using namespace std; 14 | 15 | void LoadMenu(); 16 | void SetStyles(); 17 | extern ImVec2 MenuOrigin; 18 | extern ImVec2 MenuSize; 19 | extern bool MoveMenu; 20 | extern bool StreamerMode; 21 | extern UITextField* hideRecordTextfield; 22 | extern void LoadMods(); 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /Mods.h: -------------------------------------------------------------------------------- 1 | #ifndef MODS_H 2 | #define MODS_H 3 | 4 | #include "Includes/Unity/Vector3.h" 5 | #include "Includes/Unity/Unity.h" 6 | #include "Includes/Unity/Quaternion.h" 7 | #include 8 | #include 9 | #include "dlfcn.h" 10 | #include 11 | #include 12 | #include 13 | #include "ImGui/imgui.h" 14 | #include "Includes/Hooking/JailedHook.h" 15 | 16 | struct Mods { 17 | bool bool1 = false, bool2 = false, bool3 = false; 18 | std::string myText = "Initial Text"; 19 | std::string inputText = ""; 20 | float floatVal = 0; 21 | int intval = 0, intval2 = 0; 22 | }; 23 | 24 | extern Mods mods; 25 | void LoadMods(); 26 | 27 | #endif // MODS_H 28 | -------------------------------------------------------------------------------- /Mods.mm: -------------------------------------------------------------------------------- 1 | #include "Mods.h" 2 | 3 | Mods mods; 4 | char* BinaryName = ""; 5 | 6 | /* 7 | bool *(*FunctionPointer)(void *) = nullptr; 8 | 9 | void(*old_HookFunction)(void *instance); 10 | void HookFunction(void *instance) 11 | { 12 | 13 | return old_HookFunction(instance); 14 | } 15 | */ 16 | 17 | void LoadMods() 18 | { 19 | /* 20 | HOOK(0x0000000, HookFunction, old_HookFunction); 21 | HOOKPTR(0x0000000, FunctionPointer); 22 | PATCHOFFSET(0x0000000, "00008052C0035FD6", true); 23 | */ 24 | } 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Jailed ImGui Mod Menu 2 | 3 | ![Screenshot](menupic/screenshot.png) 4 | 5 | ## Requirements 6 | 7 | * Game's IPA file 8 | * Theos 9 | * Sideloadly 10 | * File sharing enabled on sideloadly 11 | * No JIT needed to run 12 | 13 | ### Setting Up 14 | 15 | * Change the base64 string for the icon to your own in Menu.mm 16 | ``` 17 | NSString *baseimage = @""; 18 | ``` 19 | * Change the BinaryName to yours in Mods.mm 20 | ``` 21 | char* BinaryName = "executableName"; //if app uses default executable 22 | 23 | //or if its a unityframework app 24 | char* BinaryName = "Frameworks/UnityFramework.framework/UnityFramework"; 25 | ``` 26 | 27 | * Add variables for cheats in the struct in Mods.h 28 | ``` 29 | struct Mods { 30 | bool bool1 = false, bool2 = false, bool3 = false; 31 | std::string myText = "Initial Text"; 32 | float floatVal = 0; 33 | int intval = 0, intval2 = 0; 34 | }; 35 | ``` 36 | 37 | ### Usage 38 | 39 | * UI elements are added in Menu.mm 40 | 41 | * Main Switch Widget 42 | ``` 43 | // Having the same name is important 44 | newChildVisible = childVisibilityMap["Toggle 1"]; 45 | ToggleWidget(ICON_FA_BOLT, "Toggle 1", & mods.bool1, & newChildVisible); 46 | childVisibilityMap["Toggle 1"] = newChildVisible; 47 | ``` 48 | 49 | * Widget Slide View 50 | ``` 51 | // use the same name as your widget name 52 | if (widgetName == "Toggle 1") { 53 | // Content for Toggle 1 54 | } 55 | else if (widgetName == "Toggle 2") { 56 | // Content for Toggle 2 57 | } 58 | else if (widgetName == "Toggle 3") { 59 | // Content for Toggle 3 60 | } 61 | ``` 62 | 63 | * Inside of the slide view you can add these your other widgets such as these (More are to come) 64 | ``` 65 | ToggleButtonMini("Toggle A", & toggleValue); 66 | ``` 67 | ``` 68 | SliderFloatMini("SliderFloat", & mods.floatVal, 0.0f, 500.0f); 69 | ``` 70 | ``` 71 | SliderIntMini("SliderInt", & mods.intval, 0, 500); 72 | ``` 73 | ``` 74 | IntInputMini("IntInput", & mods.intval2, 0, 100); 75 | ``` 76 | ``` 77 | TextInputMini("TextInput", mods.myText, false); 78 | ``` 79 | 80 | * In Mods.mm you add your hooks and code patches (examples in Mods.mm) 81 | ``` 82 | HOOK(0x0000000, HookFunction, old_HookFunction); 83 | HOOKPTR(0x0000000, FunctionPointer); 84 | PATCHOFFSET(0x0000000, "00008052C0035FD6", true); 85 | ``` 86 | 87 | * You can use PATCHOFFSET like this to make it toggleable 88 | ``` 89 | if (mods.bool1) 90 | { 91 | PATCHOFFSET(0x0000000, "00008052C0035FD6", true); 92 | }else{ 93 | PATCHOFFSET(0x0000000, "00008052C0035FD6", false); 94 | } 95 | ``` 96 | 97 | * When you hook or patch a function, you need to run your tweak in the app and then go to the files app in the On My IPhone directory and then go to your game's folder. Then in the static-inline-hook folder your patched binary will be there. Replace the old one in the IPA file with this one for the cheats to work. The cheats will do nothing until you replace the patched binary and re-sideload your app. 98 | 99 | ## Credits 100 | 101 | * This is a heavily modified version of CarsonArk's template 102 | * Hooking from ItsPow45 103 | * I made all the widgets, menu ui, icon animations, ptr and patch macro 104 | * #ModzTeam2025 105 | 106 | ## Version History 107 | 108 | * 0.1 109 | * Initial Release 110 | 111 | * 0.2 112 | * Added Toggleable Patching 113 | * Fixed Monostring Struct 114 | * Added Obscured Types to Unity.h 115 | 116 | * 0.3 117 | * Added Text Input Support (Shows Keyboard, Returns & Deletes Text) 118 | * Added Placeholder Menu Icon 119 | -------------------------------------------------------------------------------- /control: -------------------------------------------------------------------------------- 1 | Package: com.flaco510.iosimgui 2 | Name: Flaco 3 | Depends: mobilesubstrate 4 | Version: 2.0.0 5 | Architecture: iphoneos-arm 6 | Description: Simple ImGui Menu 7 | Maintainer: Flaco 8 | Author: Flaco 9 | -------------------------------------------------------------------------------- /iOSImGui.plist: -------------------------------------------------------------------------------- 1 | { Filter = { Bundles = ( "com.spotify.client" ); }; } -------------------------------------------------------------------------------- /menupic/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Duende510/iOS-ImGui-ModMenu-Jailed/c91916012c5b78bda036cfdd65276f498f35d365/menupic/.DS_Store -------------------------------------------------------------------------------- /menupic/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Duende510/iOS-ImGui-ModMenu-Jailed/c91916012c5b78bda036cfdd65276f498f35d365/menupic/screenshot.png --------------------------------------------------------------------------------