]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/menu/item/inputbox.qc
fd6eab1fad459fe662b2840b282f85d4717bae94
[xonotic/xonotic-data.pk3dir.git] / qcsrc / menu / item / inputbox.qc
1 #ifndef ITEM_INPUTBOX_H
2 #define ITEM_INPUTBOX_H
3 CLASS(InputBox, Label)
4         METHOD(InputBox, configureInputBox, void(entity, string, float, float, string))
5         METHOD(InputBox, draw, void(entity))
6         METHOD(InputBox, setText, void(entity, string))
7         METHOD(InputBox, enterText, void(entity, string))
8         METHOD(InputBox, keyDown, float(entity, float, float, float))
9         METHOD(InputBox, mouseMove, float(entity, vector))
10         METHOD(InputBox, mouseRelease, float(entity, vector))
11         METHOD(InputBox, mousePress, float(entity, vector))
12         METHOD(InputBox, mouseDrag, float(entity, vector))
13         METHOD(InputBox, showNotify, void(entity))
14         METHOD(InputBox, resizeNotify, void(entity, vector, vector, vector, vector))
15
16         ATTRIB(InputBox, src, string, string_null)
17
18         ATTRIB(InputBox, cursorPos, float, 0) // characters
19         ATTRIB(InputBox, scrollPos, float, 0) // widths
20
21         ATTRIB(InputBox, focusable, float, 1)
22         ATTRIB(InputBox, allowFocusSound, float, 1)
23         ATTRIB(InputBox, disabled, float, 0)
24         ATTRIB(InputBox, lastChangeTime, float, 0)
25         ATTRIB(InputBox, dragScrollTimer, float, 0)
26         ATTRIB(InputBox, dragScrollPos, vector, '0 0 0')
27         ATTRIB(InputBox, pressed, float, 0)
28         ATTRIB(InputBox, editColorCodes, float, 1)
29         ATTRIB(InputBox, forbiddenCharacters, string, "")
30         ATTRIB(InputBox, color, vector, '1 1 1')
31         ATTRIB(InputBox, colorF, vector, '1 1 1')
32         ATTRIB(InputBox, maxLength, float, 255) // if negative, it counts bytes, not chars
33
34         ATTRIB(InputBox, enableClearButton, float, 1)
35         ATTRIB(InputBox, clearButton, entity, NULL)
36         ATTRIB(InputBox, cb_width, float, 0)
37         ATTRIB(InputBox, cb_pressed, float, 0)
38         ATTRIB(InputBox, cb_focused, float, 0)
39         ATTRIB(InputBox, cb_color, vector, '1 1 1')
40         ATTRIB(InputBox, cb_colorF, vector, '1 1 1')
41         ATTRIB(InputBox, cb_colorC, vector, '1 1 1')
42 ENDCLASS(InputBox)
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 float over_ClearButton(entity me, vector pos)
71 {
72         if (pos.x >= 1 + me.cb_offset - me.cb_width)
73         if (pos.x < 1 + me.cb_offset)
74         if (pos.y >= 0)
75         if (pos.y < 1)
76                 return 1;
77         return 0;
78 }
79
80 float InputBox_mouseMove(entity me, vector pos)
81 {
82         if (me.enableClearButton)
83         {
84                 if (over_ClearButton(me, pos))
85                 {
86                         me.cb_focused = 1;
87                         return 1;
88                 }
89                 me.cb_focused = 0;
90         }
91         return 1;
92 }
93
94 float InputBox_mouseDrag(entity me, vector pos)
95 {
96         float p;
97         if(me.pressed)
98         {
99                 me.dragScrollPos = pos;
100                 p = me.scrollPos + pos.x - me.keepspaceLeft;
101                 me.cursorPos = draw_TextLengthUpToWidth(me.text, p, 0, me.realFontSize);
102                 me.lastChangeTime = time;
103         }
104         else if (me.enableClearButton)
105         {
106                 if (over_ClearButton(me, pos))
107                 {
108                         me.cb_pressed = 1;
109                         return 1;
110                 }
111         }
112         me.cb_pressed = 0;
113         return 1;
114 }
115
116 float InputBox_mousePress(entity me, vector pos)
117 {
118         if (me.enableClearButton)
119         if (over_ClearButton(me, pos))
120         {
121                 me.cb_pressed = 1;
122                 return 1;
123         }
124         me.dragScrollTimer = time;
125         me.pressed = 1;
126         return InputBox_mouseDrag(me, pos);
127 }
128
129 float InputBox_mouseRelease(entity me, vector pos)
130 {
131         if(me.cb_pressed)
132         if (over_ClearButton(me, pos))
133         {
134                 m_play_click_sound(MENU_SOUND_CLEAR);
135                 me.setText(me, "");
136                 me.cb_pressed = 0;
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                         {
205                                 m_play_click_sound(MENU_SOUND_CLEAR);
206                                 me.setText(me, "");
207                         }
208                         else
209                                 me.setText(me, strcat(substring(me.text, 0, me.cursorPos), substring(me.text, me.cursorPos + 1, strlen(me.text) - me.cursorPos - 1)));
210                         return 1;
211         }
212         return 0;
213 }
214
215 void InputBox_draw(entity me)
216 {
217         string CURSOR = "_";
218         float cursorPosInWidths, totalSizeInWidths;
219
220         if(me.pressed)
221                 me.mouseDrag(me, me.dragScrollPos); // simulate mouseDrag event
222
223         if(me.recalcPos)
224                 me.recalcPositionWithText(me, me.text);
225
226         me.focusable = !me.disabled;
227         if(me.disabled)
228                 draw_alpha *= me.disabledAlpha;
229
230         if(me.src)
231         {
232                 if(me.focused && !me.disabled)
233                         draw_ButtonPicture('0 0 0', strcat(me.src, "_f"), '1 1 0', me.colorF, 1);
234                 else
235                         draw_ButtonPicture('0 0 0', strcat(me.src, "_n"), '1 1 0', me.color, 1);
236         }
237
238         me.cursorPos = bound(0, me.cursorPos, strlen(me.text));
239         cursorPosInWidths = draw_TextWidth(substring(me.text, 0, me.cursorPos), 0, me.realFontSize);
240         totalSizeInWidths = draw_TextWidth(strcat(me.text, CURSOR), 0, me.realFontSize);
241
242         if(me.dragScrollTimer < time)
243         {
244                 float save;
245                 save = me.scrollPos;
246                 me.scrollPos = bound(cursorPosInWidths - (0.875 - me.keepspaceLeft - me.keepspaceRight), me.scrollPos, cursorPosInWidths - 0.125);
247                 if(me.scrollPos != save)
248                         me.dragScrollTimer = time + 0.2;
249         }
250         me.scrollPos = min(me.scrollPos, totalSizeInWidths - (1 - me.keepspaceRight - me.keepspaceLeft));
251         me.scrollPos = max(0, me.scrollPos);
252
253         draw_SetClipRect(eX * me.keepspaceLeft, eX * (1 - me.keepspaceLeft - me.keepspaceRight) + eY);
254         if(me.editColorCodes)
255         {
256                 string ch, ch2;
257                 float i, n;
258                 vector theColor;
259                 float theAlpha;    //float theVariableAlpha;
260                 vector p;
261                 vector theTempColor;
262                 float component;
263
264                 p = me.realOrigin - eX * me.scrollPos;
265                 theColor = '1 1 1';
266                 theAlpha = 1;    //theVariableAlpha = 1; // changes when ^ax found
267
268                 n = strlen(me.text);
269                 for(i = 0; i < n; ++i)
270                 {
271                         ch = substring(me.text, i, 1);
272                         if(ch == "^")
273                         {
274                                 float w;
275                                 ch2 = substring(me.text, i+1, 1);
276                                 w = draw_TextWidth(strcat(ch, ch2), 0, me.realFontSize);
277                                 if(ch2 == "^")
278                                 {
279                                         draw_Fill(p, eX * w + eY * me.realFontSize.y, '1 1 1', 0.5);
280                                         draw_Text(p + eX * 0.25 * w, "^", me.realFontSize, theColor, theAlpha, 0);
281                                 }
282                                 else if(ch2 == "0" || stof(ch2)) // digit?
283                                 {
284                                         switch(stof(ch2))
285                                         {
286                                                 case 0: theColor = '0 0 0'; theAlpha = 1; break;
287                                                 case 1: theColor = '1 0 0'; theAlpha = 1; break;
288                                                 case 2: theColor = '0 1 0'; theAlpha = 1; break;
289                                                 case 3: theColor = '1 1 0'; theAlpha = 1; break;
290                                                 case 4: theColor = '0 0 1'; theAlpha = 1; break;
291                                                 case 5: theColor = '0 1 1'; theAlpha = 1; break;
292                                                 case 6: theColor = '1 0 1'; theAlpha = 1; break;
293                                                 case 7: theColor = '1 1 1'; theAlpha = 1; break;
294                                                 case 8: theColor = '1 1 1'; theAlpha = 0.5; break;
295                                                 case 9: theColor = '0.5 0.5 0.5'; theAlpha = 1; break;
296                                         }
297                                         draw_Fill(p, eX * w + eY * me.realFontSize.y, '1 1 1', 0.5);
298                                         draw_Text(p, strcat(ch, ch2), me.realFontSize, theColor, theAlpha, 0);
299                                 }
300                                 else if(ch2 == "x") // ^x found
301                                 {
302                                         theColor = '1 1 1';
303
304                                         component = HEXDIGIT_TO_DEC(substring(me.text, i+2, 1));
305                                         if (component >= 0) // ^xr found
306                                         {
307                                                 theTempColor.x = component/15;
308
309                                                 component = HEXDIGIT_TO_DEC(substring(me.text, i+3, 1));
310                                                 if (component >= 0) // ^xrg found
311                                                 {
312                                                         theTempColor.y = component/15;
313
314                                                         component = HEXDIGIT_TO_DEC(substring(me.text, i+4, 1));
315                                                         if (component >= 0) // ^xrgb found
316                                                         {
317                                                                 theTempColor.z = component/15;
318                                                                 theColor = theTempColor;
319                                                                 w = draw_TextWidth(substring(me.text, i, 5), 0, me.realFontSize);
320
321                                                                 draw_Fill(p, eX * w + eY * me.realFontSize.y, '1 1 1', 0.5);
322                                                                 draw_Text(p, substring(me.text, i, 5), me.realFontSize, theColor, 1, 0);    // theVariableAlpha instead of 1 using alpha tags ^ax
323                                                                 i += 3;
324                                                         }
325                                                         else
326                                                         {
327                                                                 // blue missing
328                                                                 w = draw_TextWidth(substring(me.text, i, 4), 0, me.realFontSize);
329                                                                 draw_Fill(p, eX * w + eY * me.realFontSize.y, eZ, 0.5);
330                                                                 draw_Text(p, substring(me.text, i, 4), me.realFontSize, '1 1 1', theAlpha, 0);
331                                                                 i += 2;
332                                                         }
333                                                 }
334                                                 else
335                                                 {
336                                                         // green missing
337                                                         w = draw_TextWidth(substring(me.text, i, 3), 0, me.realFontSize);
338                                                         draw_Fill(p, eX * w + eY * me.realFontSize.y, eY, 0.5);
339                                                         draw_Text(p, substring(me.text, i, 3), me.realFontSize, '1 1 1', theAlpha, 0);
340                                                         i += 1;
341                                                 }
342                                         }
343                                         else
344                                         {
345                                                 // red missing
346                                                 //w = draw_TextWidth(substring(me.text, i, 2), 0) * me.realFontSize_x;
347                                                 draw_Fill(p, eX * w + eY * me.realFontSize.y, eX, 0.5);
348                                                 draw_Text(p, substring(me.text, i, 2), me.realFontSize, '1 1 1', theAlpha, 0);
349                                         }
350                                 }
351                                 else
352                                 {
353                                         draw_Fill(p, eX * w + eY * me.realFontSize.y, '1 1 1', 0.5);
354                                         draw_Text(p, strcat(ch, ch2), me.realFontSize, theColor, theAlpha, 0);
355                                 }
356                                 p += w * eX;
357                                 ++i;
358                                 continue;
359                         }
360                         draw_Text(p, ch, me.realFontSize, theColor, theAlpha, 0); // TODO theVariableAlpha
361                         p += eX * draw_TextWidth(ch, 0, me.realFontSize);
362                 }
363         }
364         else
365                 draw_Text(me.realOrigin - eX * me.scrollPos, me.text, me.realFontSize, '1 1 1', 1, 0);
366
367         if(!me.focused || (time - me.lastChangeTime) < floor(time - me.lastChangeTime) + 0.5)
368                 draw_Text(me.realOrigin + eX * (cursorPosInWidths - me.scrollPos), CURSOR, me.realFontSize, '1 1 1', 1, 0);
369
370         draw_ClearClip();
371
372         if (me.enableClearButton)
373         if (me.text != "")
374         {
375                 if(me.focused && me.cb_pressed)
376                         draw_Picture(eX * (1 + me.cb_offset - me.cb_width), strcat(me.cb_src, "_c"), eX * me.cb_width + eY, me.cb_colorC, 1);
377                 else if(me.focused && me.cb_focused)
378                         draw_Picture(eX * (1 + me.cb_offset - me.cb_width), strcat(me.cb_src, "_f"), eX * me.cb_width + eY, me.cb_colorF, 1);
379                 else
380                         draw_Picture(eX * (1 + me.cb_offset - me.cb_width), strcat(me.cb_src, "_n"), eX * me.cb_width + eY, me.cb_color, 1);
381         }
382
383         // skipping SUPER(InputBox).draw(me);
384         Item_draw(me);
385 }
386
387 void InputBox_showNotify(entity me)
388 {
389         me.focusable = !me.disabled;
390 }
391 #endif