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