1 /* 2 Copyright © 2020, Inochi2D Project 3 Distributed under the 2-Clause BSD License, see LICENSE file. 4 5 Authors: Luna Nielsen 6 */ 7 module creator.widgets.inputtext; 8 import creator.widgets; 9 import creator.core; 10 import inochi2d; 11 import bindbc.sdl; 12 import std.stdio; 13 import std.string; 14 import core.memory : GC; 15 16 private { 17 18 struct TextCallbackUserData { 19 string* str; 20 } 21 } 22 23 /** 24 D compatible text input 25 */ 26 bool incInputText(string wId, ref string buffer, ImGuiInputTextFlags flags = ImGuiInputTextFlags.None) { 27 auto available = incAvailableSpace(); 28 return incInputText(wId, available.x, buffer, flags); 29 } 30 31 /** 32 D compatible text input 33 */ 34 bool incInputText(string wId, float width, ref string buffer, ImGuiInputTextFlags flags = ImGuiInputTextFlags.None) { 35 36 // NOTE: null strings would result in segfault, make sure it's at least just empty. 37 if (buffer.ptr is null) { 38 buffer = ""; 39 } 40 41 if (buffer.ptr[buffer.length] != '\0') { 42 // If buffer.ptr does not end with '\0', recreate string to force '\0' at the end. 43 buffer = buffer.ptr[0..buffer.length]~'\0'; 44 } 45 46 // Push ID 47 auto id = igGetID(wId.ptr, wId.ptr+wId.length); 48 igPushID(id); 49 scope(exit) igPopID(); 50 51 // Set desired width 52 igPushItemWidth(width); 53 scope(success) igPopItemWidth(); 54 55 // Create callback data 56 TextCallbackUserData cb; 57 cb.str = &buffer; 58 59 // Call ImGui's input handling 60 if (igInputText( 61 "###INPUT", 62 cast(char*)buffer.ptr, 63 buffer.length+1, 64 flags | ImGuiInputTextFlags.CallbackResize, 65 cast(ImGuiInputTextCallback)(ImGuiInputTextCallbackData* data) { 66 TextCallbackUserData* udata = cast(TextCallbackUserData*)data.UserData; 67 68 // Allow resizing strings on GC heap 69 if (data.EventFlag == ImGuiInputTextFlags.CallbackResize) { 70 71 // Make sure the buffer doesn't become negatively sized. 72 if (data.BufTextLen < 0) data.BufTextLen = 0; 73 74 // Resize and pass buffer ptr in 75 (*udata.str).length = data.BufTextLen+1; 76 77 // slice out the null terminator 78 data.Buf = cast(char*)(*udata.str).ptr; 79 data.Buf[data.BufTextLen] = '\0'; 80 (*udata.str) = (*udata.str)[0..$-1]; 81 } 82 return 0; 83 }, 84 &cb 85 )) { 86 return true; 87 } 88 89 ImVec2 min, max; 90 igGetItemRectMin(&min); 91 igGetItemRectMax(&max); 92 93 auto rect = SDL_Rect( 94 cast(int)min.x+32, 95 cast(int)min.y, 96 cast(int)max.x, 97 32 98 ); 99 100 SDL_SetTextInputRect(&rect); 101 return false; 102 } 103 /** 104 D compatible text input 105 */ 106 bool incInputText(string wId, string label, ref string buffer, ImGuiInputTextFlags flags = ImGuiInputTextFlags.None) { 107 auto available = incAvailableSpace(); 108 return incInputText(wId, label, available.x, buffer, flags); 109 } 110 111 /** 112 D compatible text input 113 */ 114 bool incInputText(string wId, string label, float width, ref string buffer, ImGuiInputTextFlags flags = ImGuiInputTextFlags.None) { 115 116 // NOTE: null strings would result in segfault, make sure it's at least just empty. 117 if (buffer.ptr is null) { 118 buffer = ""; 119 } 120 121 // Push ID 122 auto id = igGetID(wId.ptr, wId.ptr+wId.length); 123 igPushID(id); 124 scope(exit) igPopID(); 125 126 // Set desired width 127 igPushItemWidth(width); 128 scope(success) igPopItemWidth(); 129 130 // Render label 131 scope(success) { 132 igSameLine(0, igGetStyle().ItemSpacing.x); 133 igTextEx(label.ptr, label.ptr+label.length); 134 } 135 136 // Create callback data 137 TextCallbackUserData cb; 138 cb.str = &buffer; 139 140 // Call ImGui's input handling 141 if (igInputText( 142 "###INPUT", 143 cast(char*)buffer.ptr, 144 buffer.length+1, 145 flags | ImGuiInputTextFlags.CallbackResize, 146 cast(ImGuiInputTextCallback)(ImGuiInputTextCallbackData* data) { 147 TextCallbackUserData* udata = cast(TextCallbackUserData*)data.UserData; 148 149 // Allow resizing strings on GC heap 150 if (data.EventFlag == ImGuiInputTextFlags.CallbackResize) { 151 152 // Make sure the buffer doesn't become negatively sized. 153 if (data.BufTextLen < 0) data.BufTextLen = 0; 154 155 // Resize and pass buffer ptr in 156 (*udata.str).length = data.BufTextLen+1; 157 158 // slice out the null terminator 159 data.Buf = cast(char*)(*udata.str).ptr; 160 data.Buf[data.BufTextLen] = '\0'; 161 (*udata.str) = (*udata.str)[0..$-1]; 162 } 163 return 0; 164 }, 165 &cb 166 )) { 167 return true; 168 } 169 170 ImVec2 min, max; 171 igGetItemRectMin(&min); 172 igGetItemRectMax(&max); 173 174 auto rect = SDL_Rect( 175 cast(int)min.x+32, 176 cast(int)min.y, 177 cast(int)max.x, 178 32 179 ); 180 181 SDL_SetTextInputRect(&rect); 182 return false; 183 }