]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/menu/item/inputbox.qc
Header police
[xonotic/xonotic-data.pk3dir.git] / qcsrc / menu / item / inputbox.qc
1 #include "inputbox.qh"
2 #ifndef ITEM_INPUTBOX_H
3         #define ITEM_INPUTBOX_H
4         #include "label.qc"
5         CLASS(InputBox, Label)
6                 METHOD(InputBox, configureInputBox, void(entity, string, float, float, string));
7                 METHOD(InputBox, draw, void(entity));
8                 METHOD(InputBox, setText, void(entity, string));
9                 METHOD(InputBox, enterText, void(entity, string));
10                 METHOD(InputBox, keyDown, float(entity, float, float, float));
11                 METHOD(InputBox, mouseMove, float(entity, vector));
12                 METHOD(InputBox, mouseRelease, float(entity, vector));
13                 METHOD(InputBox, mousePress, float(entity, vector));
14                 METHOD(InputBox, mouseDrag, float(entity, vector));
15                 METHOD(InputBox, showNotify, void(entity));
16                 METHOD(InputBox, resizeNotify, void(entity, vector, vector, vector, vector));
17
18                 ATTRIB(InputBox, src, string, string_null)
19
20                 ATTRIB(InputBox, cursorPos, float, 0)  // characters
21                 ATTRIB(InputBox, scrollPos, float, 0)  // widths
22
23                 ATTRIB(InputBox, focusable, float, 1)
24                 ATTRIB(InputBox, allowFocusSound, float, 1)
25                 ATTRIB(InputBox, disabled, float, 0)
26                 ATTRIB(InputBox, lastChangeTime, float, 0)
27                 ATTRIB(InputBox, dragScrollTimer, float, 0)
28                 ATTRIB(InputBox, dragScrollPos, vector, '0 0 0')
29                 ATTRIB(InputBox, pressed, float, 0)
30                 ATTRIB(InputBox, editColorCodes, float, 1)
31                 ATTRIB(InputBox, forbiddenCharacters, string, "")
32                 ATTRIB(InputBox, color, vector, '1 1 1')
33                 ATTRIB(InputBox, colorF, vector, '1 1 1')
34                 ATTRIB(InputBox, maxLength, float, 255)  // if negative, it counts bytes, not chars
35                 ATTRIB(InputBox, applyButton, entity, NULL)
36
37                 ATTRIB(InputBox, enableClearButton, float, 1)
38                 ATTRIB(InputBox, clearButton, entity, NULL)
39                 ATTRIB(InputBox, cb_width, float, 0)
40                 ATTRIB(InputBox, cb_pressed, float, 0)
41                 ATTRIB(InputBox, cb_focused, float, 0)
42                 ATTRIB(InputBox, cb_color, vector, '1 1 1')
43                 ATTRIB(InputBox, cb_colorF, vector, '1 1 1')
44                 ATTRIB(InputBox, cb_colorC, vector, '1 1 1')
45         ENDCLASS(InputBox)
46 #endif
47
48 #ifdef IMPLEMENTATION
49         void InputBox_configureInputBox(entity me, string theText, float theCursorPos, float theFontSize, string gfx)
50         {
51                 SUPER(InputBox).configureLabel(me, theText, theFontSize, 0.0);
52                 me.src = gfx;
53                 me.cursorPos = theCursorPos;
54         }
55         void InputBox_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
56         {
57                 SUPER(InputBox).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
58                 if (me.enableClearButton)
59                 {
60                         me.cb_width = absSize.y / absSize.x;
61                         me.cb_offset = bound(-1, me.cb_offset, 0) * me.cb_width;  // bound to range -1, 0
62                         me.keepspaceRight = me.keepspaceRight - me.cb_offset + me.cb_width;
63                 }
64         }
65
66         void InputBox_setText(entity me, string txt)
67         {
68                 if (me.text) strunzone(me.text);
69                 SUPER(InputBox).setText(me, strzone(txt));
70         }
71
72         float over_ClearButton(entity me, vector pos)
73         {
74                 if (pos.x >= 1 + me.cb_offset - me.cb_width)
75                         if (pos.x < 1 + me.cb_offset)
76                                 if (pos.y >= 0)
77                                         if (pos.y < 1) 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                                 m_play_click_sound(MENU_SOUND_CLEAR);
136                                 me.setText(me, "");
137                                 if(me.applyButton)
138                                         me.applyButton.disabled = false;
139                                 me.cb_pressed = 0;
140                                 return 1;
141                         }
142                 float r = InputBox_mouseDrag(me, pos);
143                 // reset cb_pressed after mouseDrag, mouseDrag could set cb_pressed in this case:
144                 // mouse press out of the clear button, drag and then mouse release over the clear button
145                 me.cb_pressed = 0;
146                 me.pressed = 0;
147                 return r;
148         }
149
150         void InputBox_enterText(entity me, string ch)
151         {
152                 float i;
153                 for (i = 0; i < strlen(ch); ++i)
154                         if (strstrofs(me.forbiddenCharacters, substring(ch, i, 1), 0) > -1) return;
155                 if (me.maxLength > 0)
156                 {
157                         if (strlen(ch) + strlen(me.text) > me.maxLength) return;
158                 }
159                 else if (me.maxLength < 0)
160                 {
161                         if (u8_strsize(ch) + u8_strsize(me.text) > -me.maxLength) 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                         if(me.applyButton)
175                                 me.applyButton.disabled = false;
176                         return 1;
177                 }
178                 switch (key)
179                 {
180                         case K_KP_LEFTARROW:
181                         case K_LEFTARROW:
182                                 me.cursorPos -= 1;
183                                 return 1;
184                         case K_KP_RIGHTARROW:
185                         case K_RIGHTARROW:
186                                 me.cursorPos += 1;
187                                 return 1;
188                         case K_KP_HOME:
189                         case K_HOME:
190                                 me.cursorPos = 0;
191                                 return 1;
192                         case K_KP_END:
193                         case K_END:
194                                 me.cursorPos = strlen(me.text);
195                                 return 1;
196                         case K_BACKSPACE:
197                                 if (me.cursorPos > 0)
198                                 {
199                                         me.cursorPos -= 1;
200                                         me.setText(me, strcat(substring(me.text, 0, me.cursorPos), substring(me.text, me.cursorPos + 1, strlen(me.text) - me.cursorPos - 1)));
201                                         if(me.applyButton)
202                                                 me.applyButton.disabled = false;
203                                 }
204                                 return 1;
205                         case K_KP_DEL:
206                         case K_DEL:
207                                 if (shift & S_CTRL)
208                                 {
209                                         m_play_click_sound(MENU_SOUND_CLEAR);
210                                         me.setText(me, "");
211                                 }
212                                 else
213                                         me.setText(me, strcat(substring(me.text, 0, me.cursorPos), substring(me.text, me.cursorPos + 1, strlen(me.text) - me.cursorPos - 1)));
214                                 if(me.applyButton)
215                                         me.applyButton.disabled = false;
216                                 return 1;
217                 }
218                 return 0;
219         }
220
221         void InputBox_draw(entity me)
222         {
223                 string CURSOR = "_";
224                 float cursorPosInWidths, totalSizeInWidths;
225
226                 if (me.pressed) me.mouseDrag(me, me.dragScrollPos);  // simulate mouseDrag event
227
228                 if (me.recalcPos) me.recalcPositionWithText(me, me.text);
229
230                 me.focusable = !me.disabled;
231                 if (me.disabled) draw_alpha *= me.disabledAlpha;
232
233                 if (me.src)
234                 {
235                         if (me.focused && !me.disabled) draw_ButtonPicture('0 0 0', strcat(me.src, "_f"), '1 1 0', me.colorF, 1);
236                         else 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) 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';
287                                                                 theAlpha = 1;
288                                                                 break;
289                                                         case 1: theColor = '1 0 0';
290                                                                 theAlpha = 1;
291                                                                 break;
292                                                         case 2: theColor = '0 1 0';
293                                                                 theAlpha = 1;
294                                                                 break;
295                                                         case 3: theColor = '1 1 0';
296                                                                 theAlpha = 1;
297                                                                 break;
298                                                         case 4: theColor = '0 0 1';
299                                                                 theAlpha = 1;
300                                                                 break;
301                                                         case 5: theColor = '0 1 1';
302                                                                 theAlpha = 1;
303                                                                 break;
304                                                         case 6: theColor = '1 0 1';
305                                                                 theAlpha = 1;
306                                                                 break;
307                                                         case 7: theColor = '1 1 1';
308                                                                 theAlpha = 1;
309                                                                 break;
310                                                         case 8: theColor = '1 1 1';
311                                                                 theAlpha = 0.5;
312                                                                 break;
313                                                         case 9: theColor = '0.5 0.5 0.5';
314                                                                 theAlpha = 1;
315                                                                 break;
316                                                 }
317                                                 draw_Fill(p, eX * w + eY * me.realFontSize.y, '1 1 1', 0.5);
318                                                 draw_Text(p, strcat(ch, ch2), me.realFontSize, theColor, theAlpha, 0);
319                                         }
320                                         else if (ch2 == "x")  // ^x found
321                                         {
322                                                 theColor = '1 1 1';
323
324                                                 component = HEXDIGIT_TO_DEC(substring(me.text, i + 2, 1));
325                                                 if (component >= 0)  // ^xr found
326                                                 {
327                                                         theTempColor.x = component / 15;
328
329                                                         component = HEXDIGIT_TO_DEC(substring(me.text, i + 3, 1));
330                                                         if (component >= 0)  // ^xrg found
331                                                         {
332                                                                 theTempColor.y = component / 15;
333
334                                                                 component = HEXDIGIT_TO_DEC(substring(me.text, i + 4, 1));
335                                                                 if (component >= 0)  // ^xrgb found
336                                                                 {
337                                                                         theTempColor.z = component / 15;
338                                                                         theColor = theTempColor;
339                                                                         w = draw_TextWidth(substring(me.text, i, 5), 0, me.realFontSize);
340
341                                                                         draw_Fill(p, eX * w + eY * me.realFontSize.y, '1 1 1', 0.5);
342                                                                         draw_Text(p, substring(me.text, i, 5), me.realFontSize, theColor, 1, 0);  // theVariableAlpha instead of 1 using alpha tags ^ax
343                                                                         i += 3;
344                                                                 }
345                                                                 else
346                                                                 {
347                                                                         // blue missing
348                                                                         w = draw_TextWidth(substring(me.text, i, 4), 0, me.realFontSize);
349                                                                         draw_Fill(p, eX * w + eY * me.realFontSize.y, eZ, 0.5);
350                                                                         draw_Text(p, substring(me.text, i, 4), me.realFontSize, '1 1 1', theAlpha, 0);
351                                                                         i += 2;
352                                                                 }
353                                                         }
354                                                         else
355                                                         {
356                                                                 // green missing
357                                                                 w = draw_TextWidth(substring(me.text, i, 3), 0, me.realFontSize);
358                                                                 draw_Fill(p, eX * w + eY * me.realFontSize.y, eY, 0.5);
359                                                                 draw_Text(p, substring(me.text, i, 3), me.realFontSize, '1 1 1', theAlpha, 0);
360                                                                 i += 1;
361                                                         }
362                                                 }
363                                                 else
364                                                 {
365                                                         // red missing
366                                                         // w = draw_TextWidth(substring(me.text, i, 2), 0) * me.realFontSize_x;
367                                                         draw_Fill(p, eX * w + eY * me.realFontSize.y, eX, 0.5);
368                                                         draw_Text(p, substring(me.text, i, 2), me.realFontSize, '1 1 1', theAlpha, 0);
369                                                 }
370                                         }
371                                         else
372                                         {
373                                                 draw_Fill(p, eX * w + eY * me.realFontSize.y, '1 1 1', 0.5);
374                                                 draw_Text(p, strcat(ch, ch2), me.realFontSize, theColor, theAlpha, 0);
375                                         }
376                                         p += w * eX;
377                                         ++i;
378                                         continue;
379                                 }
380                                 draw_Text(p, ch, me.realFontSize, theColor, theAlpha, 0);  // TODO theVariableAlpha
381                                 p += eX * draw_TextWidth(ch, 0, me.realFontSize);
382                         }
383                 }
384                 else
385                 {
386                         draw_Text(me.realOrigin - eX * me.scrollPos, me.text, me.realFontSize, '1 1 1', 1, 0);
387                 }
388
389                 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);
390
391                 draw_ClearClip();
392
393                 if (me.enableClearButton)
394                         if (me.text != "")
395                         {
396                                 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);
397                                 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);
398                                 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);
399                         }
400
401                 // skipping SUPER(InputBox).draw(me);
402                 Item_draw(me);
403         }
404
405         void InputBox_showNotify(entity me)
406         {
407                 me.focusable = !me.disabled;
408         }
409 #endif