1 /***************************************************************************
2 
3     file                 : guiedit.cpp
4     created              : Mon Apr 24 10:23:28 CEST 2000
5     copyright            : (C) 2000-2014 by Eric Espie, Bernhard Wymann
6     email                : torcs@free.fr
7     version              : $Id: guiedit.cpp,v 1.2.2.6 2014/04/28 10:29:39 berniw Exp $
8 
9  ***************************************************************************/
10 
11 /***************************************************************************
12  *                                                                         *
13  *   This program is free software; you can redistribute it and/or modify  *
14  *   it under the terms of the GNU General Public License as published by  *
15  *   the Free Software Foundation; either version 2 of the License, or     *
16  *   (at your option) any later version.                                   *
17  *                                                                         *
18  ***************************************************************************/
19 
20 /** @file
21     		GUI Edit Box Management.
22     @author	<a href=mailto:torcs@free.fr>Eric Espie</a>
23     @version	$Id: guiedit.cpp,v 1.2.2.6 2014/04/28 10:29:39 berniw Exp $
24     @ingroup	gui
25 */
26 
27 #include <stdlib.h>
28 #ifdef WIN32
29 #include <windows.h>
30 #endif
31 #include <tgfclient.h>
32 #include "gui.h"
33 #include "guifont.h"
34 
35 void
gfuiEditboxInit(void)36 gfuiEditboxInit(void)
37 {
38 }
39 
40 /** Add a editbox to a screen.
41     @ingroup	gui
42     @param	scr		Screen
43     @param	text		Editbox start text
44     @param	font		Font id
45     @param	x		X position on screen
46     @param	y		Y position on screen (0 = bottom)
47     @param	width		width of the editbox (0 = text size)
48     @param	maxlen		Max lenght of text (0 = text size)
49     @param	userDataOnFocus	Parameter to the Focus (and lost) callback
50     @param	onFocus		Focus callback function
51     @param	onFocusLost	Focus Lost callback function
52     @param	margin		Margin adjustment, default is 10 pixels
53     @return	Editbox Id
54 		<br>-1 Error
55  */
56 int
GfuiEditboxCreate(void * scr,const char * text,int font,int x,int y,int width,int maxlen,void * userDataOnFocus,tfuiCallback onFocus,tfuiCallback onFocusLost,int margin)57 GfuiEditboxCreate(void *scr, const char *text, int font, int x, int y, int width, int maxlen,
58 		  void *userDataOnFocus, tfuiCallback onFocus, tfuiCallback onFocusLost, int margin)
59 {
60 	tGfuiEditbox *editbox;
61 	tGfuiLabel *label;
62 	tGfuiObject *object;
63 	tGfuiScreen *screen = (tGfuiScreen*)scr;
64 
65 
66 	object = (tGfuiObject*)calloc(1, sizeof(tGfuiObject));
67 	object->widget = GFUI_EDITBOX;
68 	object->focusMode = GFUI_FOCUS_MOUSE_CLICK;
69 	object->id = screen->curId++;
70 	object->visible = 1;
71 
72 	editbox = &(object->u.editbox);
73 	editbox->state = GFUI_BTN_RELEASED;
74 	editbox->userDataOnFocus = userDataOnFocus;
75 	editbox->onFocus = onFocus;
76 	editbox->onFocusLost = onFocusLost;
77 
78 	editbox->bgColor[0] = &(GfuiColor[GFUI_BGBTNDISABLED][0]);
79 	editbox->bgColor[1] = &(GfuiColor[GFUI_BGBTNENABLED][0]);
80 	editbox->bgColor[2] = &(GfuiColor[GFUI_BGBTNCLICK][0]);
81 	editbox->bgFocusColor[0] = &(GfuiColor[GFUI_BGBTNDISABLED][0]);
82 	editbox->bgFocusColor[1] = &(GfuiColor[GFUI_BGBTNFOCUS][0]);
83 	editbox->bgFocusColor[2] = &(GfuiColor[GFUI_BGBTNCLICK][0]);
84 	editbox->fgColor[0] = &(GfuiColor[GFUI_BTNDISABLED][0]);
85 	editbox->fgColor[1] = &(GfuiColor[GFUI_BTNENABLED][0]);
86 	editbox->fgColor[2] = &(GfuiColor[GFUI_BTNCLICK][0]);
87 	editbox->fgFocusColor[0] = &(GfuiColor[GFUI_BTNDISABLED][0]);
88 	editbox->fgFocusColor[1] = &(GfuiColor[GFUI_BTNFOCUS][0]);
89 	editbox->fgFocusColor[2] = &(GfuiColor[GFUI_BTNCLICK][0]);
90 	editbox->cursorColor[0] = &(GfuiColor[GFUI_EDITCURSORCLR][0]);
91 	editbox->cursorColor[1] = &(GfuiColor[GFUI_EDITCURSORCLR][1]);
92 	editbox->cursorColor[2] = &(GfuiColor[GFUI_EDITCURSORCLR][2]);
93 
94 
95 	label = &(editbox->label);
96 	if (maxlen == 0) maxlen = strlen(text);
97 	label->text = (char*)calloc(1, maxlen+1);
98 	strncpy(label->text, text, maxlen);
99 	label->text[maxlen] = '\0';
100 	label->font = gfuiFont[font];
101 	label->maxlen = maxlen;
102 
103 	if (width == 0) {
104 		char *buf;
105 		int  i;
106 		buf = (char*)malloc(maxlen+1);
107 		if (buf == NULL) return -1;	// Memory leak does not matter, this must not happen
108 		for (i = 0; i < maxlen; i++) buf[i] = 'W';
109 		buf[i] = '\0';
110 		width = gfuiFont[font]->getWidth((const char *)buf);
111 		free(buf);
112 	}
113 
114 	label->align = GFUI_ALIGN_HL_VC;
115 	label->x = object->xmin = x;
116 	label->y = y - 2 * gfuiFont[font]->getDescender();
117 	object->ymin = y;
118 	object->xmax = x + width;
119 	object->ymax = y + gfuiFont[font]->getHeight() - gfuiFont[font]->getDescender();
120 	editbox->cursory1 = object->ymin + 2;
121 	editbox->cursory2 = object->ymax - 2;
122 	editbox->cursorx = label->x;
123 
124 	object->xmin -= margin;
125 	object->xmax += margin;
126 
127 	gfuiAddObject(screen, object);
128 	return object->id;
129 }
130 
131 
132 /** Get the Id of the editbox focused in the current screen.
133     @ingroup	gui
134     @return	Editbox Id
135 		<br>-1 if no editbox or no screen or the focus is not on a editbox
136  */
137 int
GfuiEditboxGetFocused(void)138 GfuiEditboxGetFocused(void)
139 {
140     tGfuiObject *curObject;
141 
142     if (GfuiScreen != NULL) {
143 	curObject = GfuiScreen->objects;
144 	if (curObject != NULL) {
145 	    do {
146 		curObject = curObject->next;
147 		if (curObject->focus) {
148 		    if (curObject->widget == GFUI_EDITBOX) {
149 			return curObject->id;
150 		    }
151 		    return -1;
152 		}
153 	    } while (curObject != GfuiScreen->objects);
154 	}
155     }
156     return -1;
157 }
158 
159 
160 void
gfuiDrawEditbox(tGfuiObject * obj)161 gfuiDrawEditbox(tGfuiObject *obj)
162 {
163     tGfuiLabel		*label;
164     tGfuiEditbox	*editbox;
165     float		*fgColor;
166     float		*bgColor;
167 
168     editbox = &(obj->u.editbox);
169     if (obj->state == GFUI_DISABLE) {
170 	editbox->state = GFUI_BTN_DISABLE;
171     } else {
172 	editbox->state = GFUI_BTN_RELEASED;
173     }
174     if (obj->focus) {
175 	fgColor = editbox->fgFocusColor[editbox->state];
176 	bgColor = editbox->bgFocusColor[editbox->state];
177     } else {
178 	fgColor = editbox->fgColor[editbox->state];
179 	bgColor = editbox->bgColor[editbox->state];
180     }
181 
182     glColor4fv(bgColor);
183     glBegin(GL_QUADS);
184     glVertex2i(obj->xmin, obj->ymin);
185     glVertex2i(obj->xmin, obj->ymax);
186     glVertex2i(obj->xmax, obj->ymax);
187     glVertex2i(obj->xmax, obj->ymin);
188     glEnd();
189 
190     glColor4fv(fgColor);
191     glBegin(GL_LINE_STRIP);
192     glVertex2i(obj->xmin, obj->ymin);
193     glVertex2i(obj->xmin, obj->ymax);
194     glVertex2i(obj->xmax, obj->ymax);
195     glVertex2i(obj->xmax, obj->ymin);
196     glVertex2i(obj->xmin, obj->ymin);
197     glEnd();
198 
199     label = &(editbox->label);
200     glColor4fv(fgColor);
201     gfuiPrintString(label->x, label->y, label->font, label->text);
202 
203     if ((obj->state != GFUI_DISABLE) && (obj->focus)) {
204 	/* draw cursor */
205 	glColor3fv(editbox->cursorColor[editbox->state]);
206 	glBegin(GL_LINES);
207 	glVertex2i(editbox->cursorx, editbox->cursory1);
208 	glVertex2i(editbox->cursorx, editbox->cursory2);
209 	glEnd();
210     }
211 }
212 
213 
214 void
gfuiEditboxAction(int mouse)215 gfuiEditboxAction(int mouse)
216 {
217     tGfuiObject		*object;
218     tGfuiLabel		*label;
219     tGfuiEditbox	*editbox;
220     int			relX;
221     char		buf[256];
222     uint		i;
223 
224     object = GfuiScreen->hasFocus;
225     if (object->state == GFUI_DISABLE) {
226 	return;
227     }
228 
229     if (mouse == 2) { /* enter key */
230 	gfuiSelectNext(GfuiScreen);
231     } else if (mouse == 0) { /* mouse down */
232 	editbox = &(object->u.editbox);
233 	label = &(editbox->label);
234 	/* Set the cursor position */
235 	relX = GfuiMouse.X - label->x;
236 	for (i = 0; i < strlen(label->text); i++){
237 	    buf[i] = label->text[i];
238 	    buf[i+1] = '\0';
239 	    if (relX < label->font->getWidth((const char *)buf)) {
240 		break;
241 	    }
242 	}
243 	editbox->cursorIdx = i;
244 	if (i == 0) {
245 	    editbox->cursorx = label->x;
246 	} else {
247 	    buf[i] = '\0';
248 	    editbox->cursorx = label->x + label->font->getWidth((const char *)buf);
249 	}
250     }
251 }
252 
253 /* recalc cursorx with cursorIdx */
254 static void
gfuiEditboxRecalcCursor(tGfuiObject * obj)255 gfuiEditboxRecalcCursor(tGfuiObject *obj)
256 {
257     char		buf[256];
258     tGfuiEditbox	*editbox;
259     tGfuiLabel		*label;
260 
261     editbox = &(obj->u.editbox);
262     label = &(editbox->label);
263     strncpy(buf, label->text, editbox->cursorIdx);
264     buf[editbox->cursorIdx] = '\0';
265     editbox->cursorx = label->x + label->font->getWidth((const char *)buf);
266 }
267 
268 
269 void
gfuiEditboxKey(tGfuiObject * obj,int key,int modifier)270 gfuiEditboxKey(tGfuiObject *obj, int key, int modifier)
271 {
272     tGfuiEditbox	*editbox;
273     tGfuiLabel		*label;
274     char		*p1, *p2;
275     int			i1, i2;
276 
277     if (obj->state == GFUI_DISABLE) {
278 	return;
279     }
280 
281     editbox = &(obj->u.editbox);
282     label = &(editbox->label);
283 
284     switch (modifier) {
285     case 0:
286     case GLUT_ACTIVE_SHIFT:
287 	switch (key) {
288 	case 256 + GLUT_KEY_RIGHT:
289 	    editbox->cursorIdx++;
290 	    if (editbox->cursorIdx > (int)strlen(label->text)) {
291 		editbox->cursorIdx--;
292 	    }
293 	    break;
294 	case 256 + GLUT_KEY_LEFT:
295 	    editbox->cursorIdx--;
296 	    if (editbox->cursorIdx < 0) {
297 		editbox->cursorIdx = 0;
298 	    }
299 	    break;
300 	case 256 + GLUT_KEY_HOME:
301 	    editbox->cursorIdx = 0;
302 	    break;
303 	case 256 + GLUT_KEY_END:
304 	    editbox->cursorIdx = (int)strlen(label->text);
305 	    break;
306 	case 0x7F : /* DEL */
307 	    if (editbox->cursorIdx < (int)strlen(label->text)) {
308 		p1 = &(label->text[editbox->cursorIdx]);
309 		p2 = &(label->text[editbox->cursorIdx+1]);
310 		while ( *p1 != '\0' ) {
311 		    *p1++ = *p2++;
312 		}
313 	    }
314 	    break;
315 	case '\b' : /* Backspace */
316 	    if (editbox->cursorIdx > 0) {
317 		p1 = &(label->text[editbox->cursorIdx-1]);
318 		p2 = &(label->text[editbox->cursorIdx]);
319 		while ( *p1 != '\0' ) {
320 		    *p1++ = *p2++;
321 		}
322 		editbox->cursorIdx--;
323 	    }
324 	    break;
325 	}
326 	if (key >= ' ' && key < 127) {
327 	    if ((int)strlen(label->text) < label->maxlen) {
328 		i2 = (int)strlen(label->text) + 1;
329 		i1 = i2 - 1;
330 		while (i2 > editbox->cursorIdx) {
331 		    label->text[i2] = label->text[i1];
332 		    i1--;
333 		    i2--;
334 		}
335 		label->text[editbox->cursorIdx] = key;
336 		editbox->cursorIdx++;
337 	    }
338 	}
339 	break;
340 
341     case GLUT_ACTIVE_CTRL:
342 	break;
343 
344     case GLUT_ACTIVE_ALT:
345 	break;
346     }
347 
348     gfuiEditboxRecalcCursor(obj);
349 }
350 
351 /** Get the string
352     @ingroup	gui
353      @param	scr		Screen
354     @param	id		Edit box Id
355     @return	Corresponding string.
356  */
357 char *
GfuiEditboxGetString(void * scr,int id)358 GfuiEditboxGetString(void *scr, int id)
359 {
360     tGfuiObject		*curObject;
361     tGfuiEditbox	*editbox;
362     tGfuiLabel		*label;
363 
364     curObject = gfuiGetObject(scr, id);
365 
366     if ((curObject == NULL) || (curObject->widget != GFUI_EDITBOX)) {
367 	return (char*)NULL;
368     }
369 
370     editbox = &(curObject->u.editbox);
371     label = &(editbox->label);
372 
373     return label->text;
374 }
375 
376 /** Set a new string.
377     @ingroup	gui
378     @param	scr		Screen
379     @param	id		Edit box Id
380     @param	text		text to set
381     @return	none
382  */
GfuiEditboxSetString(void * scr,int id,const char * text)383 void GfuiEditboxSetString(void *scr, int id, const char *text)
384 {
385 	tGfuiObject *curObject;
386 	tGfuiEditbox *editbox;
387 	tGfuiLabel *label;
388 
389 	curObject = gfuiGetObject(scr, id);
390 
391 	if ((curObject == NULL) || (curObject->widget != GFUI_EDITBOX)) {
392 		return;
393 	}
394 
395 	editbox = &(curObject->u.editbox);
396 	label = &(editbox->label);
397 
398 	strncpy(label->text, text, label->maxlen);
399 	label->text[label->maxlen] = '\0';
400 }
401 
402 
403 void
gfuiReleaseEditbox(tGfuiObject * curObject)404 gfuiReleaseEditbox(tGfuiObject *curObject)
405 {
406     tGfuiEditbox	*editbox;
407     tGfuiLabel		*label;
408 
409     editbox = &(curObject->u.editbox);
410     label = &(editbox->label);
411     free(label->text);
412     free(curObject);
413 }
414 
415