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 core.memory : GC;
14 
15 private {
16     struct Str {
17         string str;
18     }
19 }
20 
21 /**
22     D compatible text input
23 */
24 bool incInputText(const(char)* label, ref string buffer, ImGuiInputTextFlags flags = ImGuiInputTextFlags.None) {
25     auto id = igGetID(label);
26     auto storage = igGetStateStorage();
27     auto available = incAvailableSpace();
28 
29     // We put a new string container on the heap and make sure the GC doesn't yeet it.
30     if (ImGuiStorage_GetVoidPtr(storage, id) is null) {
31         Str* cursedString = new Str(buffer~"\0");
32         GC.addRoot(cursedString);
33         ImGuiStorage_SetVoidPtr(storage, id, cursedString);
34     }
35 
36     // We get it
37     Str* str = cast(Str*)ImGuiStorage_GetVoidPtr(storage, id);
38 
39     igPushItemWidth(available.x);
40     if (igInputText(
41         label,
42         cast(char*)str.str.ptr, 
43         str.str.length,
44         flags | 
45             ImGuiInputTextFlags.CallbackResize,
46         cast(ImGuiInputTextCallback)(ImGuiInputTextCallbackData* data) {
47 
48             // Allow resizing strings on GC heap
49             if (data.EventFlag == ImGuiInputTextFlags.CallbackResize) {
50                 Str* str = (cast(Str*)data.UserData);
51                 str.str ~= "\0";
52                 str.str.length = data.BufTextLen;
53             }
54             return 1;
55         },
56         str
57     )) {
58 
59         // Apply string, without null terminator
60         buffer = str.str;
61         GC.removeRoot(ImGuiStorage_GetVoidPtr(storage, id));
62         ImGuiStorage_SetVoidPtr(storage, id, null);
63         return true;
64     }
65 
66     ImVec2 min, max;
67     igGetItemRectMin(&min);
68     igGetItemRectMax(&max);
69 
70     auto rect = SDL_Rect(
71         cast(int)min.x+32, 
72         cast(int)min.y, 
73         cast(int)max.x, 
74         32
75     );
76 
77     SDL_SetTextInputRect(&rect);
78     return false;
79 }
80 
81 /**
82     D compatible text input
83 */
84 bool incInputText(const(char)* label, float width, ref string buffer, ImGuiInputTextFlags flags = ImGuiInputTextFlags.None) {
85     auto id = igGetID(label);
86     auto storage = igGetStateStorage();
87 
88     // We put a new string container on the heap and make sure the GC doesn't yeet it.
89     if (ImGuiStorage_GetVoidPtr(storage, id) is null) {
90         Str* cursedString = new Str(buffer~"\0");
91         GC.addRoot(cursedString);
92         ImGuiStorage_SetVoidPtr(storage, id, cursedString);
93     }
94 
95     // We get it
96     Str* str = cast(Str*)ImGuiStorage_GetVoidPtr(storage, id);
97 
98     igPushItemWidth(width);
99     if (igInputText(
100         label,
101         cast(char*)str.str.ptr, 
102         str.str.length,
103         flags | 
104             ImGuiInputTextFlags.CallbackResize,
105         cast(ImGuiInputTextCallback)(ImGuiInputTextCallbackData* data) {
106 
107             // Allow resizing strings on GC heap
108             if (data.EventFlag == ImGuiInputTextFlags.CallbackResize) {
109                 Str* str = (cast(Str*)data.UserData);
110                 str.str ~= "\0";
111                 str.str.length = data.BufTextLen;
112             }
113             return 1;
114         },
115         str
116     )) {
117 
118         // Apply string, without null terminator
119         buffer = str.str;
120         GC.removeRoot(ImGuiStorage_GetVoidPtr(storage, id));
121         ImGuiStorage_SetVoidPtr(storage, id, null);
122         return true;
123     }
124 
125     ImVec2 min, max;
126     igGetItemRectMin(&min);
127     igGetItemRectMax(&max);
128 
129     auto rect = SDL_Rect(
130         cast(int)min.x+32, 
131         cast(int)min.y, 
132         cast(int)max.x, 
133         32
134     );
135 
136     SDL_SetTextInputRect(&rect);
137     return false;
138 }
139 
140 // /**
141 //     D compatible text input
142 // */
143 // bool incInputTextEx(const(char)* label, ref string buffer, ImGuiInputTextFlags flags, uint limit) {
144 //     limit = clamp(limit, 1, uint.max);
145 //     return igInputText(
146 //         label, 
147 //         cast(char*)(buffer).ptr, 
148 //         clamp(buffer.length, 0, limit),
149 //         flags | 
150 //             ImGuiInputTextFlags.CallbackResize |
151 //             ImGuiInputTextFlags.EnterReturnsTrue,
152 //         cast(ImGuiInputTextCallback)(ImGuiInputTextCallbackData* data) {
153 //             if (data.EventFlag == ImGuiInputTextFlags.CallbackCompletion) {
154 
155 //             }
156 //             if (data.EventFlag == ImGuiInputTextFlags.CallbackResize) {
157 //                 string* str = (cast(string*)data.UserData);
158 //                 str.length = data.BufTextLen;
159 //                 (*str) ~= "\0";
160 //             }
161 //             return 1;
162 //         },
163 //         &buffer
164 //     );
165 // }