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, ¶->onChanged,
407 NULL, ¶->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], ¶->onChanged,
429 &options[variableIdx], ¶->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