750bc83b890453eb917fcaaac3aa804a54142727
[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, mouseRelease, float(entity, vector))
9         METHOD(InputBox, mousePress, float(entity, vector))
10         METHOD(InputBox, mouseDrag, float(entity, vector))
11         METHOD(InputBox, showNotify, void(entity))
12
13         ATTRIB(InputBox, src, string, string_null)
14
15         ATTRIB(InputBox, cursorPos, float, 0) // characters
16         ATTRIB(InputBox, scrollPos, float, 0) // widths
17
18         ATTRIB(InputBox, focusable, float, 1)
19         ATTRIB(InputBox, disabled, float, 0)
20         ATTRIB(InputBox, lastChangeTime, float, 0)
21         ATTRIB(InputBox, dragScrollTimer, float, 0)
22         ATTRIB(InputBox, dragScrollPos, vector, '0 0 0')
23         ATTRIB(InputBox, pressed, float, 0)
24         ATTRIB(InputBox, editColorCodes, float, 1)
25         ATTRIB(InputBox, forbiddenCharacters, string, "")
26         ATTRIB(InputBox, color, vector, '1 1 1')
27         ATTRIB(InputBox, colorF, vector, '1 1 1')
28         ATTRIB(InputBox, maxLength, float, 255) // if negative, it counts bytes, not chars
29 ENDCLASS(InputBox)
30 void InputBox_Clear_Click(entity btn, entity me);
31 #endif
32
33 #ifdef IMPLEMENTATION
34 void InputBox_configureInputBox(entity me, string theText, float theCursorPos, float theFontSize, string gfx)
35 {
36         SUPER(InputBox).configureLabel(me, theText, theFontSize, 0.0);
37         me.src = gfx;
38         me.cursorPos = theCursorPos;
39 }
40
41 void InputBox_setText(entity me, string txt)
42 {
43         if(me.text)
44                 strunzone(me.text);
45         SUPER(InputBox).setText(me, strzone(txt));
46 }
47
48 void InputBox_Clear_Click(entity btn, entity me)
49 {
50         me.setText(me, "");
51 }
52
53 float InputBox_mouseDrag(entity me, vector pos)
54 {
55         float p;
56         me.dragScrollPos = pos;
57         p = me.scrollPos + pos_x - me.keepspaceLeft;
58         me.cursorPos = draw_TextLengthUpToWidth(me.text, p, 0, me.realFontSize);
59         me.lastChangeTime = time;
60         return 1;
61 }
62
63 float InputBox_mousePress(entity me, vector pos)
64 {
65         me.dragScrollTimer = time;
66         me.pressed = 1;
67         return InputBox_mouseDrag(me, pos);
68 }
69
70 float InputBox_mouseRelease(entity me, vector pos)
71 {
72         me.pressed = 0;
73         return InputBox_mouseDrag(me, pos);
74 }
75
76 void InputBox_enterText(entity me, string ch)
77 {
78         float i;
79         for(i = 0; i < strlen(ch); ++i)
80                 if(strstrofs(me.forbiddenCharacters, substring(ch, i, 1), 0) > -1)
81                         return;
82         if(me.maxLength > 0)
83         {
84                 if(strlen(ch) + strlen(me.text) > me.maxLength)
85                         return;
86         }
87         else if(me.maxLength < 0)
88         {
89                 if(u8_strsize(ch) + u8_strsize(me.text) > -me.maxLength)
90                         return;
91         }
92         me.setText(me, strcat(substring(me.text, 0, me.cursorPos), ch, substring(me.text, me.cursorPos, strlen(me.text) - me.cursorPos)));
93         me.cursorPos += strlen(ch);
94 }
95
96 float InputBox_keyDown(entity me, float key, float ascii, float shift)
97 {
98         me.lastChangeTime = time;
99         me.dragScrollTimer = time;
100         if(ascii >= 32 && ascii != 127)
101         {
102                 me.enterText(me, chr(ascii));
103                 return 1;
104         }
105         switch(key)
106         {
107                 case K_KP_LEFTARROW:
108                 case K_LEFTARROW:
109                         me.cursorPos -= 1;
110                         return 1;
111                 case K_KP_RIGHTARROW:
112                 case K_RIGHTARROW:
113                         me.cursorPos += 1;
114                         return 1;
115                 case K_KP_HOME:
116                 case K_HOME:
117                         me.cursorPos = 0;
118                         return 1;
119                 case K_KP_END:
120                 case K_END:
121                         me.cursorPos = strlen(me.text);
122                         return 1;
123                 case K_BACKSPACE:
124                         if(me.cursorPos > 0)
125                         {
126                                 me.cursorPos -= 1;
127                                 me.setText(me, strcat(substring(me.text, 0, me.cursorPos), substring(me.text, me.cursorPos + 1, strlen(me.text) - me.cursorPos - 1)));
128                         }
129                         return 1;
130                 case K_KP_DEL:
131                 case K_DEL:
132                         if(shift & S_CTRL)
133                                 me.setText(me, "");
134                         else
135                                 me.setText(me, strcat(substring(me.text, 0, me.cursorPos), substring(me.text, me.cursorPos + 1, strlen(me.text) - me.cursorPos - 1)));
136                         return 1;
137         }
138         return 0;
139 }
140
141 void InputBox_draw(entity me)
142 {
143 #define CURSOR "_"
144         float cursorPosInWidths, totalSizeInWidths;
145
146         if(me.pressed)
147                 me.mouseDrag(me, me.dragScrollPos); // simulate mouseDrag event
148
149         me.focusable = !me.disabled;
150         if(me.disabled)
151                 draw_alpha *= me.disabledAlpha;
152
153         if(me.src)
154         {
155                 if(me.focused && !me.disabled)
156                         draw_ButtonPicture('0 0 0', strcat(me.src, "_f"), '1 1 0', me.colorF, 1);
157                 else
158                         draw_ButtonPicture('0 0 0', strcat(me.src, "_n"), '1 1 0', me.color, 1);
159         }
160
161         me.cursorPos = bound(0, me.cursorPos, strlen(me.text));
162         cursorPosInWidths = draw_TextWidth(substring(me.text, 0, me.cursorPos), 0, me.realFontSize);
163         totalSizeInWidths = draw_TextWidth(strcat(me.text, CURSOR), 0, me.realFontSize);
164
165         if(me.dragScrollTimer < time)
166         {
167                 float save;
168                 save = me.scrollPos;
169                 me.scrollPos = bound(cursorPosInWidths - (0.875 - me.keepspaceLeft - me.keepspaceRight), me.scrollPos, cursorPosInWidths - 0.125);
170                 if(me.scrollPos != save)
171                         me.dragScrollTimer = time + 0.2;
172         }
173         me.scrollPos = min(me.scrollPos, totalSizeInWidths - (1 - me.keepspaceRight - me.keepspaceLeft));
174         me.scrollPos = max(0, me.scrollPos);
175
176         draw_SetClipRect(eX * me.keepspaceLeft, eX * (1 - me.keepspaceLeft - me.keepspaceRight) + eY);
177         if(me.editColorCodes)
178         {
179                 string ch, ch2;
180                 float i, n;
181                 vector theColor;
182                 float theAlpha;    //float theVariableAlpha;
183                 vector p;
184                 vector theTempColor;
185                 float component;
186                 
187                 p = me.realOrigin - eX * me.scrollPos;
188                 theColor = '1 1 1';
189                 theAlpha = 1;    //theVariableAlpha = 1; // changes when ^ax found
190                 
191                 n = strlen(me.text);
192                 for(i = 0; i < n; ++i)
193                 {
194                         ch = substring(me.text, i, 1);
195                         if(ch == "^")
196                         {
197                                 float w;
198                                 ch2 = substring(me.text, i+1, 1);
199                                 w = draw_TextWidth(strcat(ch, ch2), 0, me.realFontSize);
200                                 if(ch2 == "^")
201                                 {
202                                         draw_Fill(p, eX * w + eY * me.realFontSize_y, '1 1 1', 0.5);
203                                         draw_Text(p + eX * 0.25 * w, "^", me.realFontSize, theColor, theAlpha, 0);
204                                 }
205                                 else if(ch2 == "0" || stof(ch2)) // digit?
206                                 {
207                                         switch(stof(ch2))
208                                         {
209                                                 case 0: theColor = '0 0 0'; theAlpha = 1; break;
210                                                 case 1: theColor = '1 0 0'; theAlpha = 1; break;
211                                                 case 2: theColor = '0 1 0'; theAlpha = 1; break;
212                                                 case 3: theColor = '1 1 0'; theAlpha = 1; break;
213                                                 case 4: theColor = '0 0 1'; theAlpha = 1; break;
214                                                 case 5: theColor = '0 1 1'; theAlpha = 1; break;
215                                                 case 6: theColor = '1 0 1'; theAlpha = 1; break;
216                                                 case 7: theColor = '1 1 1'; theAlpha = 1; break;
217                                                 case 8: theColor = '1 1 1'; theAlpha = 0.5; break;
218                                                 case 9: theColor = '0.5 0.5 0.5'; theAlpha = 1; break;
219                                         }
220                                         draw_Fill(p, eX * w + eY * me.realFontSize_y, '1 1 1', 0.5);
221                                         draw_Text(p, strcat(ch, ch2), me.realFontSize, theColor, theAlpha, 0);
222                                 }
223                                 else if(ch2 == "x") // ^x found
224                                 {
225                                         theColor = '1 1 1';
226                                         theTempColor = '0 0 0';
227                                         
228                                         component = HEXDIGIT_TO_DEC(substring(me.text, i+2, 1));
229                                         if (component >= 0) // ^xr found
230                                         {
231                                                 theTempColor_x = component/15;
232                                                 
233                                                 component = HEXDIGIT_TO_DEC(substring(me.text, i+3, 1));
234                                                 if (component >= 0) // ^xrg found
235                                                 {
236                                                         theTempColor_y = component/15;
237                                                         
238                                                         component = HEXDIGIT_TO_DEC(substring(me.text, i+4, 1));
239                                                         if (component >= 0) // ^xrgb found
240                                                         {
241                                                                 theTempColor_z = component/15;
242                                                                 theColor = theTempColor;
243                                                                 w = draw_TextWidth(substring(me.text, i, 5), 0, me.realFontSize);
244                                                                 
245                                                                 draw_Fill(p, eX * w + eY * me.realFontSize_y, '1 1 1', 0.5);
246                                                                 draw_Text(p, substring(me.text, i, 5), me.realFontSize, theColor, 1, 0);    // theVariableAlpha instead of 1 using alpha tags ^ax
247                                                                 i += 3;
248                                                         }
249                                                         else
250                                                         {
251                                                                 // blue missing
252                                                                 w = draw_TextWidth(substring(me.text, i, 4), 0, me.realFontSize);
253                                                                 draw_Fill(p, eX * w + eY * me.realFontSize_y, eZ, 0.5);
254                                                                 draw_Text(p, substring(me.text, i, 4), me.realFontSize, '1 1 1', theAlpha, 0);
255                                                                 i += 2;
256                                                         }
257                                                 }
258                                                 else
259                                                 {
260                                                         // green missing
261                                                         w = draw_TextWidth(substring(me.text, i, 3), 0, me.realFontSize);
262                                                         draw_Fill(p, eX * w + eY * me.realFontSize_y, eY, 0.5);
263                                                         draw_Text(p, substring(me.text, i, 3), me.realFontSize, '1 1 1', theAlpha, 0);
264                                                         i += 1;
265                                                 }
266                                         }
267                                         else
268                                         {
269                                                 // red missing
270                                                 //w = draw_TextWidth(substring(me.text, i, 2), 0) * me.realFontSize_x;
271                                                 draw_Fill(p, eX * w + eY * me.realFontSize_y, eX, 0.5);
272                                                 draw_Text(p, substring(me.text, i, 2), me.realFontSize, '1 1 1', theAlpha, 0);
273                                         }
274                                 }
275                                 /*else if(ch2 == "a") // ^a found
276                                 {
277                                         draw_Fill(p, eX * w + eY * me.realFontSize_y, '1 1 1', 0.5);
278                                         draw_Text(p, substring(me.text, i, 2), me.realFontSize, theColor, 0.8, 0);
279                                         
280                                         component = str2chr(me.text, i+2);
281                                         if (component >= '0' && component <= '9')
282                                                 component = component - '0';
283                                         else if (component >= 'a' && component <= 'f')
284                                                 component = component - 87;
285                                         else if (component >= 'A' && component <= 'F')
286                                                 component = component - 55;
287                                         else
288                                                 component = -1;
289                                         
290                                         if (component >= 0) // ^ah found
291                                         {
292                                                 // FIX ME: overflow here
293                                                 if (component == 20 && theVariableAlpha <= 0.97)
294                                                         theVariableAlpha = theVariableAlpha + 0.0625;
295                                                 else if (component == 30 && theVariableAlpha >= 0.03)
296                                                         theVariableAlpha = theVariableAlpha - 0.0625;
297                                                 else
298                                                         theVariableAlpha = component*0.0625;
299                                                 
300                                                 draw_Fill(p, eX * draw_TextWidth(substring(me.text, i, 3), 0, me.realFontSize) + eY * me.realFontSize_y, '0.8 0.8 0.8', 0.5);
301                                                 draw_Text(p, strcat(ch, ch2), me.realFontSize, theColor, 0.8, 0);
302                                         }
303                                 }*/
304                                 else
305                                 {
306                                         draw_Fill(p, eX * w + eY * me.realFontSize_y, '1 1 1', 0.5);
307                                         draw_Text(p, strcat(ch, ch2), me.realFontSize, theColor, theAlpha, 0);
308                                 }
309                                 p += w * eX;
310                                 ++i;
311                                 continue;
312                         }
313                         draw_Text(p, ch, me.realFontSize, theColor, theAlpha, 0); // TODO theVariableAlpha
314                         p += eX * draw_TextWidth(ch, 0, me.realFontSize);
315                 }
316         }
317         else
318                 draw_Text(me.realOrigin - eX * me.scrollPos, me.text, me.realFontSize, '1 1 1', 1, 0);
319                 // skipping SUPER(InputBox).draw(me);
320         if(!me.focused || (time - me.lastChangeTime) < floor(time - me.lastChangeTime) + 0.5)
321                 draw_Text(me.realOrigin + eX * (cursorPosInWidths - me.scrollPos), CURSOR, me.realFontSize, '1 1 1', 1, 0);
322
323         draw_ClearClip();
324 }
325
326 void InputBox_showNotify(entity me)
327 {
328         me.focusable = !me.disabled;
329 }
330 #endif