Fix images directory for wickedx, it was default/ 1 year ago
[xonotic/xonotic-data.pk3dir.git] / qcsrc / menu / item / inputbox.c
1 #ifdef INTERFACE
2 CLASS(InputBox) EXTENDS(Label)
3         METHOD(InputBox, configureInputBox, void(entity, string, float, float, string))
4         METHOD(InputBox, draw, void(entity))
5         METHOD(InputBox, setText, void(entity, string))
6         METHOD(InputBox, enterText, void(entity, string))
7         METHOD(InputBox, keyDown, float(entity, float, float, float))
8         METHOD(InputBox, mouseMove, float(entity, vector))
9         METHOD(InputBox, mouseRelease, float(entity, vector))
10         METHOD(InputBox, mousePress, float(entity, vector))
11         METHOD(InputBox, mouseDrag, float(entity, vector))
12         METHOD(InputBox, showNotify, void(entity))
13         METHOD(InputBox, resizeNotify, void(entity, vector, vector, vector, vector))
14
15         ATTRIB(InputBox, src, string, string_null)
16
17         ATTRIB(InputBox, cursorPos, float, 0) // characters
18         ATTRIB(InputBox, scrollPos, float, 0) // widths
19
20         ATTRIB(InputBox, focusable, float, 1)
21         ATTRIB(InputBox, disabled, float, 0)
22         ATTRIB(InputBox, lastChangeTime, float, 0)
23         ATTRIB(InputBox, dragScrollTimer, float, 0)
24         ATTRIB(InputBox, dragScrollPos, vector, '0 0 0')
25         ATTRIB(InputBox, pressed, float, 0)
26         ATTRIB(InputBox, editColorCodes, float, 1)
27         ATTRIB(InputBox, forbiddenCharacters, string, "")
28         ATTRIB(InputBox, color, vector, '1 1 1')
29         ATTRIB(InputBox, colorF, vector, '1 1 1')
30         ATTRIB(InputBox, maxLength, float, 255) // if negative, it counts bytes, not chars
31
32         ATTRIB(InputBox, enableClearButton, float, 1)
33         ATTRIB(InputBox, clearButton, entity, NULL)
34         ATTRIB(InputBox, cb_width, float, 0)
35         ATTRIB(InputBox, cb_pressed, float, 0)
36         ATTRIB(InputBox, cb_focused, float, 0)
37 ENDCLASS(InputBox)
38 void InputBox_Clear_Click(entity btn, entity me);
39 #endif
40
41 #ifdef IMPLEMENTATION
42 void InputBox_configureInputBox(entity me, string theText, float theCursorPos, float theFontSize, string gfx)
43 {
44         SUPER(InputBox).configureLabel(me, theText, theFontSize, 0.0);
45         me.src = gfx;
46         me.cursorPos = theCursorPos;
47 }
48 void InputBox_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
49 {
50         SUPER(InputBox).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
51         if (me.enableClearButton)
52         {
53                 me.cb_width = absSize_y / absSize_x;
54                 me.cb_offset = bound(-1, me.cb_offset, 0) * me.cb_width; // bound to range -1, 0
55                 me.keepspaceRight = me.keepspaceRight - me.cb_offset + me.cb_width;
56         }
57 }
58
59 void InputBox_setText(entity me, string txt)
60 {
61         if(me.text)
62                 strunzone(me.text);
63         SUPER(InputBox).setText(me, strzone(txt));
64 }
65
66 void InputBox_Clear_Click(entity btn, entity me)
67 {
68         me.setText(me, "");
69 }
70
71 float over_ClearButton(entity me, vector pos)
72 {
73         if (pos_x >= 1 + me.cb_offset - me.cb_width)
74         if (pos_x < 1 + me.cb_offset)
75         if (pos_y >= 0)
76         if (pos_y < 1)
77                 return 1;
78         return 0;
79 }
80
81 float InputBox_mouseMove(entity me, vector pos)
82 {
83         if (me.enableClearButton)
84         {
85                 if (over_ClearButton(me, pos))
86                 {
87                         me.cb_focused = 1;
88                         return 1;
89                 }
90                 me.cb_focused = 0;
91         }
92         return 1;
93 }
94
95 float InputBox_mouseDrag(entity me, vector pos)
96 {
97         float p;
98         if(me.pressed)
99         {
100                 me.dragScrollPos = pos;
101                 p = me.scrollPos + pos_x - me.keepspaceLeft;
102                 me.cursorPos = draw_TextLengthUpToWidth(me.text, p, 0, me.realFontSize);
103                 me.lastChangeTime = time;
104         }
105         else if (me.enableClearButton)
106         {
107                 if (over_ClearButton(me, pos))
108                 {
109                         me.cb_pressed = 1;
110                         return 1;
111                 }
112         }
113         me.cb_pressed = 0;
114         return 1;
115 }
116
117 float InputBox_mousePress(entity me, vector pos)
118 {
119         if (me.enableClearButton)
120         if (over_ClearButton(me, pos))
121         {
122                 me.cb_pressed = 1;
123                 return 1;
124         }
125         me.dragScrollTimer = time;
126         me.pressed = 1;
127         return InputBox_mouseDrag(me, pos);
128 }
129
130 float InputBox_mouseRelease(entity me, vector pos)
131 {
132         if(me.cb_pressed)
133         if (over_ClearButton(me, pos))
134         {
135                 me.cb_pressed = 0;
136                 InputBox_Clear_Click(world, me);
137                 return 1;
138         }
139         float r = InputBox_mouseDrag(me, pos);
140         //reset cb_pressed after mouseDrag, mouseDrag could set cb_pressed in this case:
141         //mouse press out of the clear button, drag and then mouse release over the clear button
142         me.cb_pressed = 0;
143         me.pressed = 0;
144         return r;
145 }
146
147 void InputBox_enterText(entity me, string ch)
148 {
149         float i;
150         for(i = 0; i < strlen(ch); ++i)
151                 if(strstrofs(me.forbiddenCharacters, substring(ch, i, 1), 0) > -1)
152                         return;
153         if(me.maxLength > 0)
154         {
155                 if(strlen(ch) + strlen(me.text) > me.maxLength)
156                         return;
157         }
158         else if(me.maxLength < 0)
159         {
160                 if(u8_strsize(ch) + u8_strsize(me.text) > -me.maxLength)
161                         return;
162         }
163         me.setText(me, strcat(substring(me.text, 0, me.cursorPos), ch, substring(me.text, me.cursorPos, strlen(me.text) - me.cursorPos)));
164         me.cursorPos += strlen(ch);
165 }
166
167 float InputBox_keyDown(entity me, float key, float ascii, float shift)
168 {
169         me.lastChangeTime = time;
170         me.dragScrollTimer = time;
171         if(ascii >= 32 && ascii != 127)
172         {
173                 me.enterText(me, chr(ascii));
174                 return 1;
175         }
176         switch(key)
177         {
178                 case K_KP_LEFTARROW:
179                 case K_LEFTARROW:
180                         me.cursorPos -= 1;
181                         return 1;
182                 case K_KP_RIGHTARROW:
183                 case K_RIGHTARROW:
184                         me.cursorPos += 1;
185                         return 1;
186                 case K_KP_HOME:
187                 case K_HOME:
188                         me.cursorPos = 0;
189                         return 1;
190                 case K_KP_END:
191                 case K_END:
192                         me.cursorPos = strlen(me.text);
193                         return 1;
194                 case K_BACKSPACE:
195                         if(me.cursorPos > 0)
196                         {
197                                 me.cursorPos -= 1;
198                                 me.setText(me, strcat(substring(me.text, 0, me.cursorPos), substring(me.text, me.cursorPos + 1, strlen(me.text) - me.cursorPos - 1)));
199                         }
200                         return 1;
201                 case K_KP_DEL:
202                 case K_DEL:
203                         if(shift & S_CTRL)
204                                 me.setText(me, "");
205                         else
206                                 me.setText(me, strcat(substring(me.text, 0, me.cursorPos), substring(me.text, me.cursorPos + 1, strlen(me.text) - me.cursorPos - 1)));
207                         return 1;
208         }
209         return 0;
210 }
211
212 void InputBox_draw(entity me)
213 {
214 #define CURSOR "_"
215         float cursorPosInWidths, totalSizeInWidths;
216
217         if(me.pressed)
218                 me.mouseDrag(me, me.dragScrollPos); // simulate mouseDrag event
219
220         me.focusable = !me.disabled;
221         if(me.disabled)
222                 draw_alpha *= me.disabledAlpha;
223
224         if(me.src)
225         {
226                 if(me.focused && !me.disabled)
227                         draw_ButtonPicture('0 0 0', strcat(me.src, "_f"), '1 1 0', me.colorF, 1);
228                 else
229                         draw_ButtonPicture('0 0 0', strcat(me.src, "_n"), '1 1 0', me.color, 1);
230         }
231
232         me.cursorPos = bound(0, me.cursorPos, strlen(me.text));
233         cursorPosInWidths = draw_TextWidth(substring(me.text, 0, me.cursorPos), 0, me.realFontSize);
234         totalSizeInWidths = draw_TextWidth(strcat(me.text, CURSOR), 0, me.realFontSize);
235
236         if(me.dragScrollTimer < time)
237         {
238                 float save;
239                 save = me.scrollPos;
240                 me.scrollPos = bound(cursorPosInWidths - (0.875 - me.keepspaceLeft - me.keepspaceRight), me.scrollPos, cursorPosInWidths - 0.125);
241                 if(me.scrollPos != save)
242                         me.dragScrollTimer = time + 0.2;
243         }
244         me.scrollPos = min(me.scrollPos, totalSizeInWidths - (1 - me.keepspaceRight - me.keepspaceLeft));
245         me.scrollPos = max(0, me.scrollPos);
246
247         draw_SetClipRect(eX * me.keepspaceLeft, eX * (1 - me.keepspaceLeft - me.keepspaceRight) + eY);
248         if(me.editColorCodes)
249         {
250                 string ch, ch2;
251                 float i, n;
252                 vector theColor;
253                 float theAlpha;    //float theVariableAlpha;
254                 vector p;
255                 vector theTempColor;
256                 float component;
257                 
258                 p = me.realOrigin - eX * me.scrollPos;
259                 theColor = '1 1 1';
260                 theAlpha = 1;    //theVariableAlpha = 1; // changes when ^ax found
261                 
262                 n = strlen(me.text);
263                 for(i = 0; i < n; ++i)
264                 {
265                         ch = substring(me.text, i, 1);
266                         if(ch == "^")
267                         {
268                                 float w;
269                                 ch2 = substring(me.text, i+1, 1);
270                                 w = draw_TextWidth(strcat(ch, ch2), 0, me.realFontSize);
271                                 if(ch2 == "^")
272                                 {
273                                         draw_Fill(p, eX * w + eY * me.realFontSize_y, '1 1 1', 0.5);
274                                         draw_Text(p + eX * 0.25 * w, "^", me.realFontSize, theColor, theAlpha, 0);
275                                 }
276                                 else if(ch2 == "0" || stof(ch2)) // digit?
277                                 {
278                                         switch(stof(ch2))
279                                         {
280                                                 case 0: theColor = '0 0 0'; theAlpha = 1; break;
281                                                 case 1: theColor = '1 0 0'; theAlpha = 1; break;
282                                                 case 2: theColor = '0 1 0'; theAlpha = 1; break;
283                                                 case 3: theColor = '1 1 0'; theAlpha = 1; break;
284                                                 case 4: theColor = '0 0 1'; theAlpha = 1; break;
285                                                 case 5: theColor = '0 1 1'; theAlpha = 1; break;
286                                                 case 6: theColor = '1 0 1'; theAlpha = 1; break;
287                                                 case 7: theColor = '1 1 1'; theAlpha = 1; break;
288                                                 case 8: theColor = '1 1 1'; theAlpha = 0.5; break;
289                                                 case 9: theColor = '0.5 0.5 0.5'; theAlpha = 1; break;
290                                         }
291                                         draw_Fill(p, eX * w + eY * me.realFontSize_y, '1 1 1', 0.5);
292                                         draw_Text(p, strcat(ch, ch2), me.realFontSize, theColor, theAlpha, 0);
293                                 }
294                                 else if(ch2 == "x") // ^x found
295                                 {
296                                         theColor = '1 1 1';
297                                         theTempColor = '0 0 0';
298                                         
299                                         component = HEXDIGIT_TO_DEC(substring(me.text, i+2, 1));
300                                         if (component >= 0) // ^xr found
301                                         {
302                                                 theTempColor_x = component/15;
303                                                 
304                                                 component = HEXDIGIT_TO_DEC(substring(me.text, i+3, 1));
305                                                 if (component >= 0) // ^xrg found
306                                                 {
307                                                         theTempColor_y = component/15;
308                                                         
309                                                         component = HEXDIGIT_TO_DEC(substring(me.text, i+4, 1));
310                                                         if (component >= 0) // ^xrgb found
311                                                         {
312                                                                 theTempColor_z = component/15;
313                                                                 theColor = theTempColor;
314                                                                 w = draw_TextWidth(substring(me.text, i, 5), 0, me.realFontSize);
315                                                                 
316                                                                 draw_Fill(p, eX * w + eY * me.realFontSize_y, '1 1 1', 0.5);
317                                                                 draw_Text(p, substring(me.text, i, 5), me.realFontSize, theColor, 1, 0);    // theVariableAlpha instead of 1 using alpha tags ^ax
318                                                                 i += 3;
319                                                         }
320                                                         else
321                                                         {
322                                                                 // blue missing
323                                                                 w = draw_TextWidth(substring(me.text, i, 4), 0, me.realFontSize);
324                                                                 draw_Fill(p, eX * w + eY * me.realFontSize_y, eZ, 0.5);
325                                                                 draw_Text(p, substring(me.text, i, 4), me.realFontSize, '1 1 1', theAlpha, 0);
326                                                                 i += 2;
327                                                         }
328                                                 }
329                                                 else
330                                                 {
331                                                         // green missing
332                                                         w = draw_TextWidth(substring(me.text, i, 3), 0, me.realFontSize);
333                                                         draw_Fill(p, eX * w + eY * me.realFontSize_y, eY, 0.5);
334                                                         draw_Text(p, substring(me.text, i, 3), me.realFontSize, '1 1 1', theAlpha, 0);
335                                                         i += 1;
336                                                 }
337                                         }
338                                         else
339                                         {
340                                                 // red missing
341                                                 //w = draw_TextWidth(substring(me.text, i, 2), 0) * me.realFontSize_x;
342                                                 draw_Fill(p, eX * w + eY * me.realFontSize_y, eX, 0.5);
343                                                 draw_Text(p, substring(me.text, i, 2), me.realFontSize, '1 1 1', theAlpha, 0);
344                                         }
345                                 }
346                                 else
347                                 {
348                                         draw_Fill(p, eX * w + eY * me.realFontSize_y, '1 1 1', 0.5);
349                                         draw_Text(p, strcat(ch, ch2), me.realFontSize, theColor, theAlpha, 0);
350                                 }
351                                 p += w * eX;
352                                 ++i;
353                                 continue;
354                         }
355                         draw_Text(p, ch, me.realFontSize, theColor, theAlpha, 0); // TODO theVariableAlpha
356                         p += eX * draw_TextWidth(ch, 0, me.realFontSize);
357                 }
358         }
359         else
360                 draw_Text(me.realOrigin - eX * me.scrollPos, me.text, me.realFontSize, '1 1 1', 1, 0);
361                 // skipping SUPER(InputBox).draw(me);
362         if(!me.focused || (time - me.lastChangeTime) < floor(time - me.lastChangeTime) + 0.5)
363                 draw_Text(me.realOrigin + eX * (cursorPosInWidths - me.scrollPos), CURSOR, me.realFontSize, '1 1 1', 1, 0);
364
365         draw_ClearClip();
366
367         if (me.enableClearButton)
368         if (me.text != "")
369         {
370                 if(me.focused && me.cb_pressed)
371                         draw_Picture(eX * (1 + me.cb_offset - me.cb_width), strcat(me.cb_src, "_c"), eX * me.cb_width + eY, '1 1 1', 1);
372                 else if(me.focused && me.cb_focused)
373                         draw_Picture(eX * (1 + me.cb_offset - me.cb_width), strcat(me.cb_src, "_f"), eX * me.cb_width + eY, '1 1 1', 1);
374                 else
375                         draw_Picture(eX * (1 + me.cb_offset - me.cb_width), strcat(me.cb_src, "_n"), eX * me.cb_width + eY, '1 1 1', 1);
376         }
377 }
378
379 void InputBox_showNotify(entity me)
380 {
381         me.focusable = !me.disabled;
382 }
383 #endif