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