1 /*
2  * $Id: entry.c,v 1.11 2005/01/01 15:27:54 baum Exp $
3  *
4  * This file implements the entry widget
5  *
6  * Copyright (c) 2001 - 2005 Peter G. Baum  http://www.dr-baum.net
7  *
8  * See the file "license.terms" for information on usage and redistribution
9  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
10  *
11  */
12 
13 /*
14    History:
15    2013-07:	added commands, options, commands
16    2012-10-15: added -onDestroy
17    2012-08-23: added substitution parameter %d
18    2012-01-03: added options
19 					-focusIn -focusOut
20    2011-07-03: cget -data now works properly
21    2011-06-30: added options
22    					-dropTargets, -dragTargets, -onDropData, -onDragData
23    2011-04-03: added options
24    					-active -buffer -capsLockWarning -cursorPos -hasFrame
25 					-inputMethod -innerBorder -invisibleChar -setInvisibleChar -overwriteMode
26 					-activatePrimaryIcon -pulseStep -scrollOffset
27 					-activateSecondaryIcon -selectionBound -shadow -text -textLength -truncate
28 					-primaryIconSensitive -secondaryIconSensitive
29 				added commands
30 					pulse
31 					progress <val>
32    2011-04-02: added options -primaryIcon -secondaryIcon -onIconPress -onIconRelease
33    2010-05-25: added command wordList
34    2009-06-13: added -align
35    2009-04-27: added command setPosition
36    2009-04-26: added -onInsertText -onKeyPress -onKeyRelease
37    2009-03-06: added commands clear, get and set
38    2008-11: added -baseFont
39    2008-10: added command, class
40    2004-02: added -data
41         09: added cget
42             added -widthChars
43             removed getValue
44    2003-01: fixed uninitialized variables
45         12: added -value and -onChanged
46         08: switched from GnoclWidgetOptions to GnoclOption
47             gtk+ 2.0 related cleanups
48    2002-04: updates for gtk 2.0
49         09: added GnomeEntry, GnomeFileEntry, GnomeNumberEntry,
50             GnomePixmapEntry and GnomeIconEntry
51    2001-03: Begin of developement
52 */
53 
54 /**
55 \page page_entry gnocl::entry
56 \htmlinclude entry.html
57 **/
58 
59 #include "gnocl.h"
60 #include "gnoclparams.h"
61 
62 /* function declarations */
63 static int gnoclOptCompletion ( Tcl_Interp *interp, GnoclOption *opt, GObject *obj, Tcl_Obj **ret );
64 static int gnoclOptOnActivate ( Tcl_Interp *interp, GnoclOption *opt, GObject *obj, Tcl_Obj **ret );
65 
66 /**
67 \brief
68 */
69 static const int variableIdx      = 0;
70 static const int onChangedIdx     = 1;
71 static const int valueIdx         = 2;
72 static const int cursorIdx        = 3;
73 static const int primaryIconIdx   = 4;
74 static const int secondaryIconIdx = 5;
75 static const int cursorPosIdx     = 6;
76 static const int dataIdx          = 7;
77 
78 
79 static GnoclOption entryOptions[] =
80 {
81 	/* gnocl unique and complex options handled through configure */
82 	{ "-variable", GNOCL_STRING, NULL },      /* 0 */
83 	{ "-onChanged", GNOCL_STRING, NULL },     /* 1 */
84 	{ "-value", GNOCL_STRING, NULL },         /* 2 */
85 	{ "-showCursor", GNOCL_BOOL, NULL},       /* 3 */
86 	{ "-primaryIcon", GNOCL_OBJ, NULL },      /* 4 */
87 	{ "-secondaryIcon", GNOCL_OBJ, NULL },    /* 5 */
88 	{ "-cursorPos", GNOCL_STRING, NULL },     /* 6 */
89 	{ "-data", GNOCL_OBJ, "", gnoclOptData }, /* 7 */
90 	{ "-name", GNOCL_STRING, "name" },
91 	{ "-hasFocus", GNOCL_BOOL, "has-focus" },
92 	{ "-heightGroup", GNOCL_OBJ, "h", gnoclOptSizeGroup },
93 	{ "-onRealize", GNOCL_OBJ, "realize", gnoclOptCommand },
94 	{ "-onShowHelp", GNOCL_OBJ, "", gnoclOptOnShowHelp },
95 	{ "-sensitive", GNOCL_BOOL, "sensitive" },
96 	{ "-sizeGroup", GNOCL_OBJ, "s", gnoclOptSizeGroup },
97 	{ "-tooltip", GNOCL_OBJ, "", gnoclOptTooltip },
98 	{ "-visible", GNOCL_BOOL, "visible" },
99 	{ "-widthGroup", GNOCL_OBJ, "w", gnoclOptSizeGroup },
100 	{ "-baseFont", GNOCL_OBJ, "Sans 14", gnoclOptGdkBaseFont },
101 	{ "-baseColor", GNOCL_OBJ, "normal", gnoclOptGdkColorBase },
102 
103 	/* other entry properties Gtk+ 2.24 */
104 	{ "-activate", GNOCL_BOOL, "activates-default" },
105 	{ "-buffer", GNOCL_OBJ, "", NULL }, 						/* to be implemented */
106 	{ "-capsLockWarning", GNOCL_BOOL, "caps-lock-warning" },
107 	{ "-editable", GNOCL_BOOL, "editable" },
108 	{ "-activate", GNOCL_BOOL, "activates-default" },
109 	{ "-hasFrame", GNOCL_BOOL, "has-frame" },
110 	{ "-inputMethod", GNOCL_OBJ, "im-module", NULL }, 			/* to be implemented */
111 	{ "-innerBorder", GNOCL_OBJ, "inner-border", NULL }, 		/* to be implemented */
112 	{ "-invisibleChar", GNOCL_INT, "invisible-char"}, 			/* to be implemented */
113 	{ "-setInvisibleChar", GNOCL_BOOL,  "invisible-char-set" },
114 	{ "-maxLength", GNOCL_INT, "max-length" },
115 	{ "-overwriteMode", GNOCL_BOOL, "overwrite-mode" },
116 	{ "-activatePrimaryIcon", GNOCL_BOOL, "primary-icon-activatable" },
117 	{ "-primaryIconSensitive", GNOCL_BOOL, "primary-icon-sensitive" },
118 	{ "-progressFraction", GNOCL_DOUBLE, "progress-fraction" },
119 	{ "-pulseStep", GNOCL_DOUBLE, "progress-pulse-step" },
120 	{ "-scrollOffset", GNOCL_INT, "scroll-offset" },
121 	{ "-activateSecondaryIcon", GNOCL_BOOL, "secondary-icon-activatable" },
122 	{ "-secondaryIconSensitive", GNOCL_BOOL, "secondary-icon-sensitive" },
123 	{ "-selectionBound", GNOCL_INT, "selection-bound" },
124 	{ "-shadow", GNOCL_OBJ, "shadow-type", gnoclOptShadow },
125 	{ "-text", GNOCL_STRING, "text"},
126 	{ "-textLength", GNOCL_INT, "text-length"},
127 	{ "-truncate", GNOCL_BOOL, "truncate-multiline"},
128 	{ "-textVisible", GNOCL_BOOL, "visibility" },
129 	{ "-widthChars", GNOCL_INT, "width-chars" },
130 	{ "-align", GNOCL_DOUBLE, "xalign" },
131 	{ "-primaryIconTooltip", GNOCL_OBJ, "P", gnoclOptIconTooltip },
132 	{ "-secondaryIconTooltip", GNOCL_OBJ, "S", gnoclOptIconTooltip },
133 	{ "-completion", GNOCL_OBJ, "", gnoclOptCompletion },
134 
135 	/* GtkEntry Signals upto Gtk+ 2.24*/
136 	/* use the following for -onInsert for validation testing, implemented in Tcl */
137 	{ "-onActivate", GNOCL_OBJ, "activate", gnoclOptOnActivate },
138 	{ "-onBackSpace", GNOCL_OBJ, "backspace", gnoclOptOnBackspace },
139 	{ "-onCopy", GNOCL_OBJ, "C", gnoclOptOnClipboard },
140 	{ "-onCut", GNOCL_OBJ, "X", gnoclOptOnClipboard },
141 	{ "-onDel", GNOCL_OBJ, "delete-from-cursor", gnoclOptOnDeleteFromCursor},
142 	{ "-onIconPress", GNOCL_OBJ, "P", gnoclOptOnIconPress },
143 	{ "-onIconRelease", GNOCL_OBJ, "R", gnoclOptOnIconPress },
144 	{ "-onInsert", GNOCL_OBJ, "", gnoclOptOnInsertAtCursor},
145 	{ "-onCursor", GNOCL_OBJ, "move-cursor", gnoclOptOnMoveCursor},
146 	{ "-onPaste", GNOCL_OBJ, "V", gnoclOptOnClipboard},
147 	{ "-onPopulatePopup", GNOCL_OBJ, "populate-popup", gnoclOptOnPopulatePopup},
148 	{ "-onOverwrite", GNOCL_OBJ, "toggle-overwrite", gnoclOptOnToggleOverwrite},
149 	{ "-onPreeditChanged", GNOCL_OBJ, "preedit-changed", gnoclOptOnPreEditChanged },
150 
151 	/* GtkEditable Signals */
152 	{ "-onKeyPress", GNOCL_OBJ, "", gnoclOptOnKeyPress },
153 	{ "-onKeyRelease", GNOCL_OBJ, "", gnoclOptOnKeyRelease },
154 	{ "-onFocusIn", GNOCL_OBJ, "I", gnoclOptOnFocus },
155 	{ "-onFocusOut", GNOCL_OBJ, "O", gnoclOptOnFocus },
156 
157 	/* drag-n-drop */
158 	{ "-dropTargets", GNOCL_LIST, "t", gnoclOptDnDTargets },
159 	{ "-dragTargets", GNOCL_LIST, "s", gnoclOptDnDTargets },
160 	{ "-onDropData", GNOCL_OBJ, "", gnoclOptOnDropData },
161 	{ "-onDragData", GNOCL_OBJ, "", gnoclOptOnDragData },
162 	{ "-onFocusIn", GNOCL_OBJ, "I", gnoclOptOnFocus },
163 	{ "-onFocusOut", GNOCL_OBJ, "O", gnoclOptOnFocus },
164 
165 	/* respond to widget destruction */
166 	{ "-onDestroy", GNOCL_OBJ, "destroy", gnoclOptCommand },
167 	{ NULL }
168 };
169 
170 /**
171 \brief
172 */
173 
174 /* moved to gnocl.h */
175 /*
176 typedef struct
177 {
178     GtkEntry    *entry;
179     Tcl_Interp  *interp;
180     char        *name;
181     char        *variable;
182     char        *onChanged;
183     int         inSetVar;
184 } EntryParams;
185 */
186 
187 /* function declarations */
188 static int setVal ( GtkEntry *entry, const char *txt );
189 static void changedFunc ( GtkWidget *widget, gpointer data );
190 
191 
192 /**
193 \brief     Handles the 'activate' signal.
194 \author    William J Giddings
195 \date      25/04/2010
196 \since     0.9.95
197 \note      Used by: gnome::entry
198 \**/
doOnActivate(GtkEntry * entry,gpointer user_data)199 static void doOnActivate (   GtkEntry *entry, gpointer user_data )
200 {
201 
202 
203 	GnoclCommandData *cs = ( GnoclCommandData * ) user_data;
204 	GtkTextIter *iter;
205 
206 	GnoclPercSubst ps[] =
207 	{
208 		{ 'w', GNOCL_STRING },  /* widget name */
209 		{ 't', GNOCL_STRING },  /* text content */
210 		{ 'd', GNOCL_STRING },  /* widget data */
211 		{ 0 }
212 	};
213 
214 	ps[0].val.str = gnoclGetNameFromWidget ( entry );;
215 	ps[1].val.str = gtk_entry_get_text ( entry );
216 	ps[2].val.str = g_object_get_data ( G_OBJECT ( entry ), "gnocl::data" );
217 
218 	gnoclPercentSubstAndEval ( cs->interp, ps, cs->command, 1 );
219 }
220 
221 /**
222 \brief    Implements the 'activate' signal.
223 \author   William J Giddings
224 \date     25/04/2010
225 \since    0.9.95
226 **/
gnoclOptOnActivate(Tcl_Interp * interp,GnoclOption * opt,GObject * obj,Tcl_Obj ** ret)227 static int gnoclOptOnActivate ( Tcl_Interp *interp, GnoclOption *opt, GObject *obj, Tcl_Obj **ret )
228 {
229 
230 	/* check the name of the signal is correct for this function */
231 	assert ( strcmp ( opt->optName, "-onActivate" ) == 0 );
232 
233 	/* connect the signal with its callback function */
234 	return gnoclConnectOptCmd ( interp, obj, "activate", G_CALLBACK ( doOnActivate ), opt, NULL, ret );
235 }
236 
237 
238 /**
239 \brief
240 **/
241 //GtkEntryCompletion *create_completion(void)
gnoclOptCompletion(Tcl_Interp * interp,GnoclOption * opt,GObject * obj,Tcl_Obj ** ret)242 int gnoclOptCompletion ( Tcl_Interp *interp, GnoclOption *opt, GObject *obj, Tcl_Obj **ret )
243 {
244 	assert ( strcmp ( opt->optName, "-completion" ) == 0 );
245 
246 	GtkEntryCompletion *completion;
247 	GtkListStore *model;
248 	GtkTreeIter iter;
249 
250 	const gchar *text[] =
251 	{
252 		"how", "now", "brown", "cow",
253 		"she", "sells", "sea", "shells", "by", "the", "shore",
254 		NULL,
255 	};
256 	gint i;
257 
258 	/* Create a new completion... */
259 	completion = gtk_entry_completion_new();
260 
261 	/* ...and set things up for the first column */
262 	gtk_entry_completion_set_text_column ( completion, 0 );
263 
264 	/* Create a list store with one string column... */
265 	model = gtk_list_store_new ( 1, G_TYPE_STRING );
266 
267 	/* ...and set it as the completion's model... */
268 	gtk_entry_completion_set_model ( completion, GTK_TREE_MODEL ( model ) );
269 
270 	/* ...and drop our reference to the model */
271 	g_object_unref ( model );
272 
273 	/* Add some text to be matched */
274 	for ( i = 0; text[i] != NULL; i++ )
275 	{
276 		gtk_list_store_append ( model, &iter );
277 		gtk_list_store_set ( model, &iter, 0, text[i], -1 );
278 	}
279 
280 	gtk_entry_set_completion ( GTK_ENTRY ( obj ), completion );
281 
282 	return TCL_OK;
283 }
284 
285 
286 /**
287 \brief
288 **/
doCommand(EntryParams * para,const char * val,int background)289 static int doCommand ( EntryParams *para, const char *val, int background )
290 {
291 	if ( para->onChanged )
292 	{
293 		GnoclPercSubst ps[] =
294 		{
295 			{ 'w', GNOCL_STRING },  /* widget */
296 			{ 'v', GNOCL_STRING },  /* value */
297 			{ 0 }
298 		};
299 
300 		ps[0].val.str = para->name;
301 		ps[1].val.str = val;
302 
303 		return gnoclPercentSubstAndEval ( para->interp, ps, para->onChanged, background );
304 	}
305 
306 	return TCL_OK;
307 }
308 
309 /**
310 \brief
311 **/
setVal(GtkEntry * entry,const char * txt)312 static int setVal ( GtkEntry *entry, const char *txt )
313 {
314 #ifdef DEBUG_ENTRY
315 	printf ( "entry/staticFuncs/setVal\n" );
316 #endif
317 
318 	int blocked = g_signal_handlers_block_matched (
319 					  G_OBJECT ( entry ), G_SIGNAL_MATCH_FUNC,
320 					  0, 0, NULL, ( gpointer * ) changedFunc, NULL );
321 	gtk_entry_set_text ( entry, txt );
322 
323 	if ( blocked )
324 		g_signal_handlers_unblock_matched (
325 			G_OBJECT ( entry ), G_SIGNAL_MATCH_FUNC,
326 			0, 0, NULL, ( gpointer * ) changedFunc, NULL );
327 
328 	return TCL_OK;
329 }
330 
331 /**
332 \brief
333 **/
traceFunc(ClientData data,Tcl_Interp * interp,const char * name1,const char * name2,int flags)334 static char *traceFunc ( ClientData data, Tcl_Interp *interp,   const char *name1,  const char *name2, int flags )
335 {
336 	EntryParams *para = ( EntryParams * ) data;
337 
338 	if ( para->inSetVar == 0 && name1 )
339 	{
340 		const char *txt = name1 ? Tcl_GetVar2 ( interp, name1, name2, 0 ) : NULL;
341 
342 		if ( txt )
343 		{
344 			setVal ( para->entry, txt );
345 			doCommand ( para, txt, 1 );
346 		}
347 	}
348 
349 	return NULL;
350 }
351 
352 /**
353 \brief
354 **/
setVariable(EntryParams * para,const char * val)355 static int setVariable ( EntryParams *para, const char *val )
356 {
357 #ifdef DEBUG_ENTRY
358 	printf ( "entry/staticFuncs/setVariable\n" );
359 #endif
360 
361 	if ( para->variable && para->inSetVar == 0 )
362 	{
363 		const char *ret;
364 		para->inSetVar = 1;
365 		ret = Tcl_SetVar ( para->interp, para->variable, val, TCL_GLOBAL_ONLY );
366 		para->inSetVar = 0;
367 		return ret == NULL ? TCL_ERROR : TCL_OK;
368 	}
369 
370 	return TCL_OK;
371 }
372 
373 /**
374 \brief
375     Function associated with the widget.
376 */
changedFunc(GtkWidget * widget,gpointer data)377 static void changedFunc ( GtkWidget *widget, gpointer data )
378 {
379 #ifdef DEBUG_ENTRY
380 	printf ( "entry/staticFuncs/changedFunc\n" );
381 #endif
382 
383 	EntryParams *para = ( EntryParams * ) data;
384 	const char *val = gtk_entry_get_text ( para->entry );
385 	setVariable ( para, val );
386 	doCommand ( para, val, 1 );
387 }
388 
389 /**
390 \brief
391 **/
destroyFunc(GtkWidget * widget,gpointer data)392 static void destroyFunc (
393 	GtkWidget *widget,
394 	gpointer data )
395 {
396 #ifdef DEBUG_ENTRY
397 	printf ( "entry/staticFuncs/destroyFunc\n" );
398 #endif
399 
400 	EntryParams *para = ( EntryParams * ) data;
401 
402 	gnoclForgetWidgetFromName ( para->name );
403 	Tcl_DeleteCommand ( para->interp, para->name );
404 
405 	gnoclAttachOptCmdAndVar (
406 		NULL, &para->onChanged,
407 		NULL, &para->variable,
408 		"changed", G_OBJECT ( para->entry ),
409 		G_CALLBACK ( changedFunc ), para->interp, traceFunc, para );
410 
411 	g_free ( para->variable );
412 	g_free ( para->name );
413 	g_free ( para );
414 }
415 
416 /**
417 \brief
418 **/
configure(Tcl_Interp * interp,EntryParams * para,GnoclOption options[])419 static int configure (	Tcl_Interp *interp,	EntryParams *para,	GnoclOption options[] )
420 {
421 
422 #ifdef DEBUG_ENTRY
423 	printf ( "entry/staticFuncs/configure\n" );
424 #endif
425 
426 
427 	gnoclAttachOptCmdAndVar (
428 		&options[onChangedIdx], &para->onChanged,
429 		&options[variableIdx], &para->variable,
430 		"changed", G_OBJECT ( para->entry ),
431 		G_CALLBACK ( changedFunc ), interp, traceFunc, para );
432 
433 	if ( options[variableIdx].status == GNOCL_STATUS_CHANGED
434 			&& options[valueIdx].status == 0  /* value is handled below */
435 			&& para->variable != NULL )
436 	{
437 		/* if variable does not exist -> set it, else set widget state */
438 		const char *val = Tcl_GetVar ( interp, para->variable, TCL_GLOBAL_ONLY );
439 
440 		if ( val == NULL )
441 		{
442 			val = gtk_entry_get_text ( para->entry );
443 			setVariable ( para, val );
444 		}
445 
446 		else
447 		{
448 			setVal ( para->entry, val );
449 		}
450 	}
451 
452 	if ( options[valueIdx].status == GNOCL_STATUS_CHANGED )
453 	{
454 		char *str = options[valueIdx].val.str;
455 		setVal ( para->entry, str );
456 		setVariable ( para, str );
457 	}
458 
459 	if ( options[cursorIdx].status == GNOCL_STATUS_CHANGED )
460 	{
461 
462 		gint *bool = options[cursorIdx].val.i;
463 		gdk_window_set_cursor ( GTK_WIDGET ( para->entry )->window, bool );
464 
465 	}
466 
467 	if ( options[cursorPosIdx].status == GNOCL_STATUS_CHANGED )
468 	{
469 		char *str = options[cursorPosIdx].val.str;
470 
471 		gint len = strlen ( gtk_editable_get_chars ( para->entry, 0, -1 ) );
472 		gint pos = atoi ( str );
473 
474 
475 		if ( strcmp ( str, "end" ) == 0 )
476 		{
477 			gtk_editable_set_position ( para->entry, -1 );
478 			return TCL_OK;
479 
480 		}
481 
482 		else if ( pos == -1 )
483 		{
484 			gtk_editable_set_position ( para->entry, -1 );
485 		}
486 
487 		else if ( pos <= len )
488 		{
489 			gtk_editable_set_position ( para->entry, pos );
490 		}
491 
492 		else
493 		{
494 			gtk_editable_set_position ( para->entry, -1 );
495 		}
496 
497 		return TCL_OK;
498 
499 		//setVal ( para->entry, str );
500 		//setVariable ( para, str );
501 	}
502 
503 	/* set entry icon */
504 	if ( options[primaryIconIdx].status == GNOCL_STATUS_CHANGED )
505 	{
506 		GnoclStringType type = gnoclGetStringType ( options[primaryIconIdx].val.obj );
507 
508 		if ( type == GNOCL_STR_EMPTY )
509 		{
510 
511 		}
512 
513 		else
514 		{
515 			GtkWidget *image = gnoclFindChild ( GTK_WIDGET ( para->entry ), GTK_TYPE_IMAGE );
516 
517 
518 			if ( ( type & ( GNOCL_STR_STOCK | GNOCL_STR_FILE ) ) == 0 )
519 			{
520 				Tcl_AppendResult ( interp, "Unknown type for \"",
521 								   Tcl_GetString ( options[primaryIconIdx].val.obj ),
522 								   "\" must be of type FILE (%/) or STOCK (%#)", NULL );
523 				return TCL_ERROR;
524 
525 			}
526 
527 			if ( image == NULL )
528 			{
529 
530 			}
531 
532 			if ( type & GNOCL_STR_STOCK )
533 			{
534 				GtkStockItem item;
535 
536 				if ( gnoclGetStockItem ( options[primaryIconIdx].val.obj, interp, &item ) != TCL_OK )
537 				{
538 					return TCL_ERROR;
539 				}
540 
541 				//gtk_image_set_from_stock ( GTK_IMAGE ( image ), item.stock_id, GTK_ICON_SIZE_BUTTON );
542 				gtk_entry_set_icon_from_stock ( para->entry, GTK_ENTRY_ICON_PRIMARY, item.stock_id );
543 
544 			}
545 
546 			else if ( type & GNOCL_STR_FILE )
547 			{
548 				GdkPixbuf *pix = gnoclPixbufFromObj ( interp, options + primaryIconIdx );
549 
550 				if ( pix == NULL )
551 				{
552 					return TCL_ERROR;
553 				}
554 
555 				gtk_entry_set_icon_from_pixbuf ( para->entry, GTK_ENTRY_ICON_PRIMARY, pix );
556 			}
557 		}
558 	}
559 
560 	/* set secondary icon */
561 	if ( options[secondaryIconIdx].status == GNOCL_STATUS_CHANGED )
562 	{
563 		GnoclStringType type = gnoclGetStringType ( options[secondaryIconIdx].val.obj );
564 
565 		if ( type == GNOCL_STR_EMPTY )
566 		{
567 
568 		}
569 
570 		else
571 		{
572 			GtkWidget *image = gnoclFindChild ( GTK_WIDGET ( para->entry ), GTK_TYPE_IMAGE );
573 
574 
575 			if ( ( type & ( GNOCL_STR_STOCK | GNOCL_STR_FILE ) ) == 0 )
576 			{
577 				Tcl_AppendResult ( interp, "Unknown type for \"",
578 								   Tcl_GetString ( options[secondaryIconIdx].val.obj ),
579 								   "\" must be of type FILE (%/) or STOCK (%#)", NULL );
580 				return TCL_ERROR;
581 
582 			}
583 
584 			if ( image == NULL )
585 			{
586 
587 			}
588 
589 			if ( type & GNOCL_STR_STOCK )
590 			{
591 				GtkStockItem item;
592 
593 				if ( gnoclGetStockItem ( options[secondaryIconIdx].val.obj, interp, &item ) != TCL_OK )
594 				{
595 					return TCL_ERROR;
596 				}
597 
598 				//gtk_image_set_from_stock ( GTK_IMAGE ( image ), item.stock_id, GTK_ICON_SIZE_BUTTON );
599 				gtk_entry_set_icon_from_stock ( para->entry, GTK_ENTRY_ICON_SECONDARY, item.stock_id );
600 
601 			}
602 
603 			else if ( type & GNOCL_STR_FILE )
604 			{
605 				GdkPixbuf *pix = gnoclPixbufFromObj ( interp, options + secondaryIconIdx );
606 
607 				if ( pix == NULL )
608 				{
609 					return TCL_ERROR;
610 				}
611 
612 				gtk_entry_set_icon_from_pixbuf ( para->entry, GTK_ENTRY_ICON_SECONDARY, pix );
613 			}
614 		}
615 	}
616 
617 	return TCL_OK;
618 }
619 
620 /**
621 \brief
622 **/
cget(Tcl_Interp * interp,EntryParams * para,GnoclOption options[],int idx)623 static int cget ( Tcl_Interp *interp, EntryParams *para, GnoclOption options[], int idx )
624 {
625 #ifdef DEBUG_ENTRY
626 	printf ( "entry/staticFuncs/cget\n" );
627 #endif
628 
629 	Tcl_Obj *obj = NULL;
630 
631 	if ( idx == dataIdx )
632 	{
633 		obj = Tcl_NewStringObj ( g_object_get_data ( para->entry, "gnocl::data" ), -1 );
634 	}
635 
636 	else if ( idx == variableIdx )
637 	{
638 		obj = Tcl_NewStringObj ( para->variable, -1 );
639 	}
640 
641 	else if ( idx == onChangedIdx )
642 	{
643 		obj = Tcl_NewStringObj ( para->onChanged ? para->onChanged : "", -1 );
644 	}
645 
646 	else if ( idx == valueIdx )
647 	{
648 		obj = Tcl_NewStringObj ( gtk_entry_get_text ( para->entry ), -1 );
649 	}
650 
651 	if ( obj != NULL )
652 	{
653 		Tcl_SetObjResult ( interp, obj );
654 		return TCL_OK;
655 	}
656 
657 	return gnoclCgetNotImplemented ( interp, options + idx );
658 }
659 static const char *cmds[] =
660 {
661 	"delete", "configure", "cget", "onChanged",
662 	"class", "get", "clear", "set",  "setPosition",
663 	"wordList", "popup", "progress", "pulse",
664 	NULL
665 };
666 /**
667 \brief
668 **/
entryFunc(ClientData data,Tcl_Interp * interp,int objc,Tcl_Obj * const objv[])669 int entryFunc ( ClientData data, Tcl_Interp *interp, int objc, Tcl_Obj * const objv[] )
670 {
671 
672 #ifdef DEBUG_ENTRY
673 	debugStep ( __FUNCTION__, 1 );
674 #endif
675 
676 
677 
678 
679 	enum cmdIdx
680 	{
681 		DeleteIdx, ConfigureIdx, CgetIdx, OnChangedIdx,
682 		ClassIdx, GetIdx, ClearIdx, SetIdx, SetPositionIdx,
683 		WordListIdx, PopupIdx, ProgressIdx, PulseIdx
684 	};
685 
686 	EntryParams *para = ( EntryParams * ) data;
687 
688 	int idx;
689 
690 	if ( objc < 2 )
691 	{
692 		Tcl_WrongNumArgs ( interp, 1, objv, "command" );
693 		return TCL_ERROR;
694 	}
695 
696 	if ( Tcl_GetIndexFromObj ( interp, objv[1], cmds, "command", TCL_EXACT, &idx ) != TCL_OK )
697 	{
698 		return TCL_ERROR;
699 	}
700 
701 	switch ( idx )
702 	{
703 
704 		case PulseIdx:
705 			{
706 				gtk_entry_progress_pulse ( GTK_WIDGET ( para->entry ) );
707 
708 				//gnoclUpdateCmd ( data, interp, objc, objv);
709 
710 			}
711 			break;
712 		case ProgressIdx:
713 			{
714 				gdouble fraction;
715 
716 				Tcl_GetDoubleFromObj ( NULL, objv[2], &fraction );
717 
718 				g_print ( "PROGRESS %f\n", fraction );
719 
720 				gtk_entry_set_progress_fraction ( GTK_WIDGET ( para->entry ), fraction );
721 
722 				//gnoclUpdateCmd ( data, interp, objc, objv);
723 
724 			}
725 			break;
726 		case PopupIdx:
727 			{
728 				// 0   1     2       3       4
729 				// $id popup item    <path>
730 				// $id popup subMenu <path1> <path2>
731 				g_print ( "PopupIdx %s\n", Tcl_GetString ( objv[1] ) );
732 				g_print ( "PopupIdx %s\n", Tcl_GetString ( objv[2] ) );
733 				g_print ( "PopupIdx %s\n", Tcl_GetString ( objv[3] ) );
734 
735 				static char *popupOptions[] =
736 				{
737 					"item", "subMenu", "separator",
738 					NULL
739 				};
740 
741 				static enum  popupOptionsIdx
742 				{
743 					ItemIdx, SubMenuIdx, SeparatorIdx
744 				};
745 
746 				gint idx;
747 
748 				getIdx ( popupOptions,  Tcl_GetString ( objv[2] ), &idx );
749 
750 				switch ( idx )
751 				{
752 					case SeparatorIdx:
753 						{
754 							gnoclPopupMenuAddSeparator ( interp );
755 						}
756 						break;
757 					case ItemIdx:
758 						{
759 							gnoclPopupMenuAddItem ( interp, Tcl_GetString ( objv[3] ) );
760 						} break;
761 					case SubMenuIdx:
762 						{
763 							gnoclPopupMenuAddSubMenu ( interp, Tcl_GetString ( objv[3] ),  Tcl_GetString ( objv[4] ) );
764 						} break;
765 					default: {}
766 				}
767 
768 
769 			}
770 
771 			break;
772 
773 			/* manipulate completion word list */
774 		case WordListIdx:
775 			{
776 				static const char *subCmds[] =
777 				{
778 					"add", "clear", "delete", "list",
779 					NULL
780 				};
781 
782 				enum subCmdIdx
783 				{
784 					AddIdx, ClearIdx, DeleteIdx, ListIdx
785 				};
786 
787 				int subIdx;
788 
789 				if ( Tcl_GetIndexFromObj ( interp, objv[2], subCmds, "command", TCL_EXACT, &subIdx ) != TCL_OK )
790 				{
791 					return TCL_ERROR;
792 				}
793 
794 				switch ( subIdx )
795 				{
796 					case AddIdx:
797 						{
798 
799 							gchar **words;
800 							gint i;
801 
802 							GtkTreeModel *model;
803 							GtkTreeIter iter;
804 
805 							model = gtk_entry_completion_get_model ( para->completion );
806 
807 							/* split a list into its parts */
808 							words = g_strsplit ( Tcl_GetString ( objv[3] ), " ", -1 );
809 
810 							for ( i = 0; words[i] != NULL; i++ )
811 							{
812 
813 								gtk_list_store_append ( model, &iter );
814 								gtk_list_store_set ( model, &iter, 0, words[i], -1 );
815 
816 							}
817 
818 							g_strfreev ( words );
819 
820 						} break;
821 					case ClearIdx: {} break;
822 					case DeleteIdx: {} break;
823 					case ListIdx: {} break;
824 					default:
825 						{
826 							return TCL_ERROR;
827 						}
828 				}
829 
830 			}
831 			break;
832 		case SetPositionIdx:
833 			{
834 
835 
836 				if ( 1 )
837 				{
838 					gtk_entry_set_position ( GTK_WIDGET ( para->entry ) , Tcl_GetString ( objv[2] ) );
839 				}
840 
841 				else
842 				{
843 					gtk_editable_set_position ( GTK_EDITABLE ( GTK_WIDGET ( para->entry ) ) , Tcl_GetString ( objv[2] ) );
844 				}
845 			}
846 
847 			break;
848 		case SetIdx:
849 			{
850 				/* simply set the text to nothing */
851 				gtk_entry_set_text ( para->entry, Tcl_GetString ( objv[2] ) );
852 			}
853 
854 			break;
855 		case GetIdx:
856 			{
857 				/* equivalent to widget cget -value */
858 				Tcl_Obj *obj = NULL;
859 
860 				obj = Tcl_NewStringObj ( gtk_entry_get_text ( para->entry  ), -1 );
861 
862 				if ( obj != NULL )
863 				{
864 					Tcl_SetObjResult ( interp, obj );
865 					return TCL_OK;
866 				}
867 			}
868 
869 			break;
870 		case ClearIdx:
871 			{
872 				/* simply set the text to nothing */
873 				gtk_entry_set_text ( para->entry, "" );
874 			}
875 
876 			break;
877 		case ClassIdx:
878 			{
879 
880 				Tcl_SetObjResult ( interp, Tcl_NewStringObj ( "entry", -1 ) );
881 			}
882 			break;
883 		case DeleteIdx:
884 			{
885 				return gnoclDelete ( interp, GTK_WIDGET ( para->entry ), objc, objv );
886 			}
887 		case ConfigureIdx:
888 			{
889 #ifdef DEBUG_ENTRY
890 				g_print ( "entryFunc ConfigureIdx\n" );
891 #endif
892 				int ret = TCL_ERROR;
893 
894 				if ( gnoclParseAndSetOptions ( interp, objc - 1, objv + 1,
895 											   entryOptions, G_OBJECT ( para->entry ) ) == TCL_OK )
896 				{
897 					ret = configure ( interp, para, entryOptions );
898 				}
899 
900 				gnoclClearOptions ( entryOptions );
901 
902 				return ret;
903 			}
904 
905 			break;
906 
907 		case CgetIdx:
908 			{
909 				int     idx;
910 
911 				switch ( gnoclCget ( interp, objc, objv, G_OBJECT ( para->entry ), entryOptions, &idx ) )
912 				{
913 					case GNOCL_CGET_ERROR:
914 						return TCL_ERROR;
915 					case GNOCL_CGET_HANDLED:
916 						return TCL_OK;
917 					case GNOCL_CGET_NOTHANDLED:
918 						return cget ( interp, para, entryOptions, idx );
919 				}
920 			}
921 			break;
922 		case OnChangedIdx:
923 			{
924 				const char *txt = gtk_entry_get_text ( para->entry );
925 
926 				if ( objc != 2 )
927 				{
928 					Tcl_WrongNumArgs ( interp, 2, objv, NULL );
929 					return TCL_ERROR;
930 				}
931 
932 				return doCommand ( para, txt, 0 );
933 			}
934 	}
935 
936 	return TCL_OK;
937 }
938 
939 /**
940 \brief
941 **/
gnoclEntryCmd(ClientData data,Tcl_Interp * interp,int objc,Tcl_Obj * const objv[])942 int gnoclEntryCmd (	ClientData data, Tcl_Interp *interp, int objc, Tcl_Obj * const objv[] )
943 {
944 
945 	if ( gnoclGetCmdsAndOpts ( interp, cmds, entryOptions, objv, objc ) == TCL_OK )
946 	{
947 		return TCL_OK;
948 	}
949 
950 #ifdef DEBUG_ENTRY
951 	printf ( "$s", __FUNCTION__ );
952 #endif
953 
954 	EntryParams *para;
955 	int ret;
956 
957 	if ( gnoclParseOptions ( interp, objc, objv, entryOptions ) != TCL_OK )
958 	{
959 		gnoclClearOptions ( entryOptions );
960 		return TCL_ERROR;
961 	}
962 
963 	para = g_new ( EntryParams, 1 );
964 	para->entry = GTK_ENTRY ( gtk_entry_new( ) );
965 	//para->entry = GTK_ENTRY ( gtk_undo_entry_new ( NULL ) );
966 
967 	para->interp = interp;
968 	para->variable = NULL;
969 	para->onChanged = NULL;
970 	para->inSetVar = 0;
971 
972 	gtk_entry_set_activates_default ( para->entry, TRUE );
973 	gtk_widget_show ( GTK_WIDGET ( para->entry ) );
974 
975 	/* add completion */
976 
977 	//GtkEntryCompletion *completion;
978 	GtkListStore *model;
979 	GtkTreeIter iter;
980 	gint i;
981 
982 	const gchar *text[] =
983 	{
984 		NULL,
985 	};
986 
987 	/* Create a new completion... */
988 	para->completion = gtk_entry_completion_new();
989 
990 	/* ...and set things up for the first column */
991 	gtk_entry_completion_set_text_column ( para->completion, 0 );
992 
993 	/* Create a list store with one string column... */
994 	model = gtk_list_store_new ( 1, G_TYPE_STRING );
995 
996 	/* ...and set it as the completion's model... */
997 	gtk_entry_completion_set_model ( para->completion, GTK_TREE_MODEL ( model ) );
998 
999 	/* ...and drop our reference to the model */
1000 	g_object_unref ( model );
1001 
1002 	/* Add some text to be matched */
1003 	for ( i = 0; text[i] != NULL; i++ )
1004 	{
1005 		gtk_list_store_append ( model, &iter );
1006 		gtk_list_store_set ( model, &iter, 0, text[i], -1 );
1007 	}
1008 
1009 	gtk_entry_set_completion ( GTK_ENTRY ( para->entry ), para->completion );
1010 
1011 	/* set options */
1012 	ret = gnoclSetOptions ( interp, entryOptions, G_OBJECT ( para->entry ), -1 );
1013 
1014 	/* apply custom settigs */
1015 	if ( ret == TCL_OK )
1016 	{
1017 		ret = configure ( interp, para, entryOptions );
1018 	}
1019 
1020 	gnoclClearOptions ( entryOptions );
1021 
1022 	/* set cleanup handler */
1023 	if ( ret != TCL_OK )
1024 	{
1025 		gtk_widget_destroy ( GTK_WIDGET ( para->entry ) );
1026 		g_free ( para );
1027 		return TCL_ERROR;
1028 	}
1029 
1030 	/* register the new widget */
1031 	para->name = gnoclGetAutoWidgetId();
1032 
1033 	g_signal_connect ( G_OBJECT ( para->entry ), "destroy", G_CALLBACK ( destroyFunc ), para );
1034 
1035 	gnoclMemNameAndWidget ( para->name, GTK_WIDGET ( para->entry ) );
1036 
1037 	Tcl_CreateObjCommand ( interp, para->name, entryFunc, para, NULL );
1038 
1039 	Tcl_SetObjResult ( interp, Tcl_NewStringObj ( para->name, -1 ) );
1040 
1041 	return TCL_OK;
1042 }
1043 
1044