1 /*
2 * $Id: helperFuncs.c,v 1.11 2005/01/01 15:27:54 baum Exp $
3 *
4 * This file implements some helper functions
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: removed gnoclGetWidgetOptions func, moved to parseOptions.c
16 2013-06: added str_replace
17 2012-03: added trim
18 2010-10: added stringtype
19 2010-07: added cmds2list
20 2009-01: added getIdx
21 2009-01: added gnoclGetWigdetGeometry
22 05: added gnoclPosOffset from text.c
23 2003-04: added gnoclPixbufFromObj
24 2002-12: removed gnoclEventToString
25 joined with convert.c
26 09: gnoclFindLabel, gnoclLabelParseULine
27 2001-07: Begin of developement
28 */
29
30 #include "gnocl.h"
31 #include <gdk-pixbuf/gdk-pixbuf.h>
32
33 typedef struct
34 {
35 GtkWidget *widget;
36 GtkType type;
37 } FindWidgetStruct;
38
39 /**
40 Remove white spaces on both sides of a string.
41 **/
42
trim(char * s)43 char *trim ( char *s )
44 {
45 char *ptr;
46
47 if ( !s )
48 {
49 return NULL; // handle NULL string
50 }
51
52 if ( !*s )
53 {
54 return s; // handle empty string
55 }
56
57 for ( ptr = s + strlen ( s ) - 1; ( ptr >= s ) && isspace ( *ptr ); --ptr );
58
59 ptr[1] = '\0';
60 return s;
61 }
62
63
64 /**
65 \brief Write fucntion and step to stdout.
66 **/
debugStep(gchar * str,gdouble i)67 void debugStep ( gchar *str, gdouble i )
68 {
69 g_print ( "%s %2.01f\n", str, i );
70 }
71
72 /**
73 \brief Obtain the height and width of a pango string in pixels.
74 **/
getTextWidth(GtkWidget * widget,char * family,int ptsize,int weight,int normalstyle,char * stringtomeasure,int * wdret,int * htret)75 void getTextWidth ( GtkWidget *widget, char * family , int ptsize , int weight , int normalstyle ,
76 char * stringtomeasure ,
77 int * wdret , int * htret )
78 {
79 PangoFontDescription * fd = pango_font_description_new ( );
80
81 pango_font_description_set_family ( fd, family );
82 pango_font_description_set_style ( fd, normalstyle ? PANGO_STYLE_NORMAL : PANGO_STYLE_ITALIC );
83 pango_font_description_set_variant ( fd, PANGO_VARIANT_NORMAL );
84 pango_font_description_set_weight ( fd, ( PangoWeight ) weight );
85 pango_font_description_set_stretch ( fd, PANGO_STRETCH_NORMAL );
86 pango_font_description_set_size ( fd, ptsize * PANGO_SCALE );
87
88 PangoContext * context = gtk_widget_get_pango_context ( widget ) ;
89
90 PangoLayout * layout = pango_layout_new ( context );
91 pango_layout_set_text ( layout, stringtomeasure, -1 );
92 pango_layout_set_font_description ( layout, fd );
93 pango_layout_get_pixel_size ( layout, wdret , htret );
94 g_object_unref ( layout );
95 }
96
97
98 /**
99 \brief Return Units
100 **/
101
getUnits(gchar * str)102 gchar * getUnits ( gchar *str )
103 {
104
105 gint ret = 0;
106
107 static const char *units[] =
108 {
109 "pixel", "points", "inch", "mm",
110 NULL
111 };
112
113 enum unitIdx
114 {
115 PixelIdx, PointsIdx, InchIdx, MmIdx
116 };
117
118 getIdx ( units, str, &ret );
119
120 if ( ret )
121 {
122 return str;
123 }
124
125 else
126 {
127 return NULL;
128 }
129
130 }
131
132 /**
133 \brief Return the number of items in a space separated list.
134 **/
listLength(char * str)135 int listLength ( char *str )
136 {
137
138 int len;
139
140 char * pch;
141 len = 0;
142
143 pch = strtok ( str, " " );
144
145 while ( pch != NULL )
146 {
147 pch = strtok ( NULL, " " );
148 len++;
149 }
150
151 return len;
152 }
153
154 /**
155 \brief Return substring of range idx to len from string str.
156 **/
substring(char * str,int idx,int len)157 char *substring ( char *str, int idx, int len )
158 {
159
160 int i;
161 char *to;
162
163 i = strlen ( str ) ;
164 to = ( char* ) malloc ( i );
165
166 strncpy ( to, str + idx, len );
167 return to;
168
169 }
170
171 /**
172 \brief Programming utility function that lists parameters.
173 **/
listParameters(int objc,Tcl_Obj * const objv[],char * str)174 void listParameters ( int objc, Tcl_Obj * const objv[], char *str )
175 {
176 gint i = 0;
177
178 g_print ( "---------------\n" );
179 printf ( "%s\n", str );
180
181 while ( i < objc )
182 {
183 g_print ( " %d = %s\n", i, Tcl_GetString ( objv[i] ) );
184 i++;
185 }
186
187 }
188
189 /**
190 \brief Return the number of items in a CSV data string.
191 **/
getSize(char * str1,char * sep)192 int getSize ( char *str1, char *sep )
193 {
194 char *pch;
195 int i;
196 char str2[256];
197
198 /* get a copy of the data string */
199 sprintf ( str2, "%s", str1 );
200
201 i = 0;
202 pch = strtok ( str2, sep );
203
204 while ( pch != NULL )
205 {
206 pch = strtok ( NULL, sep );
207 i++;
208 }
209
210 return i;
211 }
212
213 /**
214 /brief Convert a string of CSV decimal numbers into an array of doubles.
215 **/
getdoubles(char * str1,gdouble myFloats[])216 int getdoubles ( char *str1, gdouble myFloats[] )
217 {
218 char * pch;
219 int i;
220 char str2[strlen ( str1 ) ];
221
222 /* get a copy of the data string */
223 sprintf ( str2, "%s", str1 );
224
225 i = 0;
226 pch = strtok ( str2, "," );
227
228 while ( pch != NULL )
229 {
230 myFloats[i] = atof ( pch );
231 pch = strtok ( NULL, "," );
232 i++;
233 }
234
235 return i;
236
237 }
238
239 /**
240 \brief Compare string with list of acceptable choices. Return index of any match.
241 \note For use in conjuction with switch to determine action based upon one of a range of choices given choices.
242 \see getIDx
243 **/
compare(char * str,char * choices[])244 int compare ( char *str, char *choices[] )
245 {
246
247 int i;
248
249 for ( i = 0; choices[i] != NULL ; i++ )
250 {
251 if ( strcmp ( str, choices[i] ) == 0 )
252 {
253 return i;
254 }
255 }
256 }
257
258 /**
259 \brief Return a NULL terminated string array as a list.
260 **/
cmds2list(gchar * arr[])261 gchar * cmds2list ( gchar *arr[] )
262 {
263
264 gchar buffer[512];
265 char *ptr;
266 gint len = 0;
267
268 sprintf ( buffer, "%s", "" );
269
270 while ( ptr != NULL )
271 {
272 sprintf ( buffer, "%s %s", buffer, arr[len] );
273 ptr = arr[++len];
274 }
275
276 return buffer;
277 }
278
279 /**
280 \brief A programming utility function, it returns the type of option string received.
281 **/
stringtype(int type)282 gchar *stringtype ( int type )
283 {
284 switch ( type )
285 {
286 case GNOCL_STR_EMPTY:
287 {
288 return "empty";
289 }
290 case GNOCL_STR_STR:
291 {
292 return "string";
293 }
294 case GNOCL_STR_STOCK:
295 {
296 return "stockItem";
297 }
298 case GNOCL_STR_FILE:
299 {
300 return "file";
301 }
302 case GNOCL_STR_TRANSLATE:
303 {
304 return "translate";
305 }
306 case GNOCL_STR_UNDERLINE:
307 {
308 return "underline";
309 }
310 case GNOCL_STR_MARKUP:
311 {
312 return "markup";
313 }
314 case GNOCL_STR_BUFFER:
315 {
316 return "pixBuf";
317 }
318 }
319
320 return "unknown";
321
322 }
323
324 /**
325 \brief append to string
326 **/
str_append(const char * s1,const char * s2)327 char *str_append ( const char *s1, const char *s2 )
328 {
329 char *s0 = malloc ( strlen ( s1 ) + strlen ( s2 ) + 1 );
330 strcpy ( s0, s1 );
331 strcat ( s0, s2 );
332 return s0;
333 }
334
335 /**
336 \brief prepend to string
337 **/
str_prepend(const char * s1,const char * s2)338 char *str_prepend ( const char *s1, const char *s2 )
339 {
340 char *s0 = malloc ( strlen ( s1 ) + strlen ( s2 ) + 1 );
341 strcpy ( s0, s2 );
342 strcat ( s0, s1 );
343 return s0;
344 }
345
346
347 /**
348 \brief replace all occurances of substring.
349 **/
str_replace(const char * string,const char * substr,const char * replacement)350 char *str_replace ( const char *string, const char *substr, const char *replacement )
351 {
352 char *tok = NULL;
353 char *newstr = NULL;
354 char *oldstr = NULL;
355 char *head = NULL;
356
357 /* if either substr or replacement is NULL, duplicate string a let caller handle it */
358 if ( substr == NULL || replacement == NULL ) return strdup ( string );
359
360 newstr = strdup ( string );
361 head = newstr;
362
363 while ( ( tok = strstr ( head, substr ) ) )
364 {
365 oldstr = newstr;
366 newstr = malloc ( strlen ( oldstr ) - strlen ( substr ) + strlen ( replacement ) + 1 );
367
368 /*failed to alloc mem, free old string and return NULL */
369 if ( newstr == NULL )
370 {
371 free ( oldstr );
372 return NULL;
373 }
374
375 memcpy ( newstr, oldstr, tok - oldstr );
376 memcpy ( newstr + ( tok - oldstr ), replacement, strlen ( replacement ) );
377 memcpy ( newstr + ( tok - oldstr ) + strlen ( replacement ), tok + strlen ( substr ), strlen ( oldstr ) - strlen ( substr ) - ( tok - oldstr ) );
378 memset ( newstr + strlen ( oldstr ) - strlen ( substr ) + strlen ( replacement ) , 0, 1 );
379 /* move back head right after the last replacement */
380 head = newstr + ( tok - oldstr ) + strlen ( replacement );
381 free ( oldstr );
382 }
383
384 return newstr;
385 }
386
387 /**
388 \brief Get index of matched string in an NULL terminated array of strings.
389 \author William J Giddings
390 \date 05/05/09
391 \param gchar *opts[] Pointer the array containing keywords
392 \param gchar *str Pointer to the string to match
393 \param gint *idx Pointer to int which contains the matched index
394 \return boolean, returns 0 is match found else -1
395 \note Useful for making choices from a list and processing with switch.
396 **/
getIdx(gchar * opts[],gchar * str,gint * idx)397 int getIdx ( gchar *opts[], gchar *str, gint *idx )
398 {
399 #ifdef DEBUG_HELPERFUNCS
400 g_print ( "helperFuncs getIdx\n" );
401 g_printf ( "\topts = %s\n", opts );
402 g_printf ( "\tstr = %s\n", str );
403 g_printf ( "\tidx = %s\n", *idx );
404 #endif
405
406 int i = 0;
407
408 while ( opts[i] != NULL ) /* go through array until NULL encountered */
409 {
410
411 if ( strcmp ( str , opts[i] ) == 0 )
412 {
413 *idx = i;
414 return 0;
415 }
416
417 i++;
418 }
419
420 /* must be an error here! */
421 return -1;
422 }
423
424
425 /**
426 \author William J Giddings
427 \date 15/01/09
428 **/
gnoclGetWidgetGeometry(GtkWidget * widget)429 char *gnoclGetWidgetGeometry ( GtkWidget *widget )
430 {
431 gint x, y;
432 gint w, h;
433 char txt[500];
434
435 x = widget->allocation.x;
436 y = widget->allocation.y;
437 w = widget->allocation.width;
438 h = widget->allocation.height;
439
440 sprintf ( txt, "%d %d %d %d", x, y, w, h );
441
442 return txt;
443 }
444
445
446 /**
447 \brief Find the "internal children" of a container widget.
448 **/
findChildIntern(GtkWidget * widget,gpointer data)449 static void findChildIntern ( GtkWidget *widget, gpointer data )
450 {
451 FindWidgetStruct *fw = ( FindWidgetStruct * ) data;
452
453 if ( fw->widget == NULL )
454 {
455 if ( GTK_CHECK_TYPE ( widget, fw->type ) )
456 {
457 fw->widget = widget;
458 }
459
460 else if ( GTK_IS_CONTAINER ( widget ) )
461 {
462 gtk_container_foreach ( GTK_CONTAINER ( widget ), findChildIntern, data );
463 }
464 }
465 }
466
467 /**
468 \brief
469 **/
gnoclFindChild(GtkWidget * widget,GtkType type)470 GtkWidget *gnoclFindChild ( GtkWidget *widget, GtkType type )
471 {
472 FindWidgetStruct fw;
473 fw.widget = NULL;
474 fw.type = type;
475 findChildIntern ( widget, &fw );
476 return fw.widget;
477 }
478
479
480 /**
481 **/
gnoclPosOffset(Tcl_Interp * interp,const char * txt,int * offset)482 int gnoclPosOffset ( Tcl_Interp *interp, const char *txt, int *offset )
483 {
484 *offset = 0;
485 /* pos[+-]offset */
486
487 if ( *txt == '+' || *txt == '-' )
488 {
489 if ( sscanf ( txt + 1, "%d", offset ) != 1 )
490 {
491 Tcl_AppendResult ( interp, "invalid offset \"", txt + 1, "\"", NULL );
492 return TCL_ERROR;
493 }
494
495 if ( *txt == '-' )
496 *offset *= -1;
497
498 for ( ++txt; isdigit ( *txt ); ++txt )
499 ;
500 }
501
502 if ( *txt )
503 {
504 Tcl_AppendResult ( interp, "invalid appendix \"", txt, "\"", NULL );
505 return TCL_ERROR;
506 }
507
508 return TCL_OK;
509 }
510
511 /**
512 \brief Substitute percentage marker with values and then execute script.
513
514 **/
gnoclPercentSubstAndEval(Tcl_Interp * interp,GnoclPercSubst * ps,const char * orig_script,int background)515 int gnoclPercentSubstAndEval ( Tcl_Interp *interp, GnoclPercSubst *ps, const char *orig_script, int background )
516 {
517
518 #ifdef DEBUG_HELPERFUNCS
519 g_print ( "gnoclPercentSubstAndEval\n" );
520 #endif
521
522 int len = strlen ( orig_script );
523 const char *old_perc = orig_script;
524 const char *perc;
525 GString *script = g_string_sized_new ( len + 20 );
526 int ret;
527
528 for ( ; ( perc = strchr ( old_perc, '%' ) ) != NULL; old_perc = perc + 2 )
529 {
530 g_string_sprintfa ( script, "%.*s", perc - old_perc, old_perc );
531
532 #ifdef DEBUG_HELPERFUNCS
533 printf ( "\t1) script: \"%s\"\n", script->str );
534 #endif
535
536 if ( perc[1] == '%' )
537 g_string_append_c ( script, '%' );
538 else
539 {
540 int k = 0;
541
542 while ( ps[k].c && ps[k].c != perc[1] )
543 ++k;
544
545 if ( ps[k].c == 0 )
546 {
547 #ifdef DEBUG_HELPERFUNCS
548 printf ( "\t2) DEBUG: unknown percent substitution %c\n", perc[1] );
549 #endif
550 /*
551 Tcl_AppendResult( interp, "unknown percent substitution" ,
552 (char *)NULL );
553 g_string_free( script, 1 );
554 return TCL_ERROR;
555 */
556 g_string_append_c ( script, '%' );
557 g_string_append_c ( script, perc[1] );
558 }
559
560 else
561 {
562 switch ( ps[k].type )
563 {
564 case GNOCL_STRING:
565 /* FIXME: escape special characters: ' ', '\n', '\\' ...
566 or use Tcl_EvalObj? */
567
568 if ( ps[k].val.str != NULL )
569 {
570 /* handle special characters correctly
571 TODO: would it be better to escape
572 special characters?
573 */
574 char *txt = Tcl_Merge ( 1, &ps[k].val.str );
575 g_string_append ( script, txt );
576 #ifdef DEBUG_HELPERFUNCS
577 printf ( "\t3) percent string: \"%s\" -> \"%s\"\n", ps[k].val.str, txt );
578 #endif
579 Tcl_Free ( txt );
580 //g_string_free (txt,1);
581 }
582
583 else
584 g_string_append ( script, "{}" );
585
586 break;
587
588 case GNOCL_OBJ:
589
590 if ( ps[k].val.obj != NULL )
591 {
592 /* embedden 0s should be UTF encoded. Should
593 therefor also work. */
594 /*
595 g_string_sprintfa( script, "%s",
596 Tcl_GetString( ps[k].val.obj ) );
597 */
598 const char *argv[2] = { NULL, NULL };
599 char *txt;
600 argv[0] = Tcl_GetString ( ps[k].val.obj );
601 txt = Tcl_Merge ( 1, argv );
602 g_string_append ( script, txt );
603 Tcl_Free ( txt );
604
605 }
606
607 else
608 g_string_append ( script, "{}" );
609
610 break;
611
612 case GNOCL_INT:
613 g_string_sprintfa ( script, "%d", ps[k].val.i );
614
615 break;
616
617 case GNOCL_BOOL:
618 g_string_sprintfa ( script, "%d", ps[k].val.b != 0 );
619
620 break;
621
622 case GNOCL_DOUBLE:
623 g_string_sprintfa ( script, "%f", ps[k].val.d );
624
625 break;
626
627 default:
628 assert ( 0 );
629
630 break;
631 }
632 }
633 }
634 }
635
636 g_string_append ( script, old_perc );
637
638 /* Tcl_EvalObj would be faster and more elegant, but incompatible: eg. two consecutive percent substitutions without space */
639 ret = Tcl_EvalEx ( interp, script->str, -1, TCL_EVAL_GLOBAL | TCL_EVAL_DIRECT );
640
641 #ifdef DEBUG_HELPERFUNCS
642 printf ( "\t4) DEBUG: script in percEval: %s -> %d %s\n", script->str, ret, Tcl_GetString ( Tcl_GetObjResult ( interp ) ) );
643 #endif
644
645 g_string_free ( script, 1 );
646
647 if ( background && ret != TCL_OK )
648 {
649 Tcl_BackgroundError ( interp );
650 }
651
652 return ret;
653 }
654
655 /**
656 \brief
657 **/
gnoclAttachVariable(GnoclOption * newVar,char ** oldVar,const char * signal,GObject * obj,GCallback gtkFunc,Tcl_Interp * interp,Tcl_VarTraceProc tclFunc,gpointer data)658 int gnoclAttachVariable ( GnoclOption *newVar, char **oldVar, const char *signal, GObject *obj,
659 GCallback gtkFunc, Tcl_Interp *interp, Tcl_VarTraceProc tclFunc, gpointer data )
660 {
661 if ( *oldVar && ( newVar == NULL || newVar->status == GNOCL_STATUS_CHANGED ) )
662 Tcl_UntraceVar ( interp, *oldVar, TCL_TRACE_WRITES | TCL_GLOBAL_ONLY,
663 tclFunc, data );
664
665 if ( newVar == NULL || newVar->status != GNOCL_STATUS_CHANGED
666 || newVar->val.str[0] == 0 )
667 {
668 /* no new variable -> delete all */
669 if ( *oldVar )
670 {
671 g_signal_handlers_disconnect_matched ( obj,
672 G_SIGNAL_MATCH_FUNC, 0, 0, NULL, ( gpointer * ) gtkFunc, NULL );
673 g_free ( *oldVar );
674 *oldVar = NULL;
675 }
676 }
677
678 else
679 {
680 if ( *oldVar == NULL ) /* new variable but old didn't exist */
681 g_signal_connect ( obj, signal, gtkFunc, data );
682 else /* new variable and old did exist */
683 g_free ( *oldVar );
684
685 *oldVar = newVar->val.str; /* transfer ownership */
686
687 newVar->val.str = NULL;
688
689 Tcl_TraceVar ( interp, *oldVar, TCL_TRACE_WRITES | TCL_GLOBAL_ONLY,
690 tclFunc, data );
691 }
692
693 return TCL_OK;
694 }
695
696 /**
697 \brief Provides tracer function on variables
698 */
gnoclAttachOptCmdAndVar(GnoclOption * newCmd,char ** oldCmd,GnoclOption * newVar,char ** oldVar,const char * signal,GObject * obj,GCallback gtkFunc,Tcl_Interp * interp,Tcl_VarTraceProc tclFunc,gpointer data)699 int gnoclAttachOptCmdAndVar ( GnoclOption *newCmd, char **oldCmd, GnoclOption *newVar, char **oldVar,
700 const char *signal, GObject *obj, GCallback gtkFunc, Tcl_Interp *interp,
701 Tcl_VarTraceProc tclFunc, gpointer data )
702 {
703 const int wasConnected = *oldVar != NULL || *oldCmd != NULL;
704
705 /* handle variable */
706
707 if ( newVar == NULL || newVar->status == GNOCL_STATUS_CHANGED )
708 {
709 if ( *oldVar )
710 {
711 Tcl_UntraceVar ( interp, *oldVar, TCL_TRACE_WRITES | TCL_GLOBAL_ONLY, tclFunc, data );
712 g_free ( *oldVar );
713 *oldVar = NULL;
714 }
715 }
716
717 if ( newVar && newVar->status == GNOCL_STATUS_CHANGED && *newVar->val.str != '\0' )
718 {
719 *oldVar = g_strdup ( newVar->val.str );
720 Tcl_TraceVar ( interp, *oldVar, TCL_TRACE_WRITES | TCL_GLOBAL_ONLY, tclFunc, data );
721 }
722
723 /* handle command */
724
725 if ( newCmd == NULL || newCmd->status == GNOCL_STATUS_CHANGED )
726 {
727 if ( *oldCmd )
728 {
729 g_free ( *oldCmd );
730 *oldCmd = NULL;
731 }
732 }
733
734 if ( newCmd && newCmd->status == GNOCL_STATUS_CHANGED && *newCmd->val.str != '\0' )
735 {
736 *oldCmd = g_strdup ( newCmd->val.str );
737 }
738
739 /* if cmd or var is set, we need the gtkFunc */
740
741 if ( *oldVar || *oldCmd )
742 {
743 if ( wasConnected == 0 )
744 {
745 g_signal_connect ( G_OBJECT ( obj ), signal, gtkFunc, data );
746 }
747 }
748
749 else if ( wasConnected )
750 {
751 g_signal_handlers_disconnect_matched ( G_OBJECT ( obj ), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, ( gpointer * ) gtkFunc, NULL );
752 }
753
754 return TCL_OK;
755 }
756
757
758
759 /**
760 **/
gnoclGet2Boolean(Tcl_Interp * interp,Tcl_Obj * obj,int * b1,int * b2)761 int gnoclGet2Boolean ( Tcl_Interp *interp, Tcl_Obj *obj, int *b1, int *b2 )
762 {
763 int no;
764
765 if ( Tcl_ListObjLength ( interp, obj, &no ) == TCL_OK
766 && ( no == 2 || no == 1 ) )
767 {
768 if ( no == 1 )
769 {
770 if ( Tcl_GetBooleanFromObj ( interp, obj, b1 ) != TCL_OK )
771 return TCL_ERROR;
772
773 *b2 = *b1;
774
775 return TCL_OK;
776 }
777
778 else
779 {
780 Tcl_Obj *tp;
781
782 if ( Tcl_ListObjIndex ( interp, obj, 0, &tp ) == TCL_OK )
783 {
784 if ( Tcl_GetBooleanFromObj ( interp, tp, b1 ) != TCL_OK )
785 return TCL_ERROR;
786
787 if ( Tcl_ListObjIndex ( interp, obj, 1, &tp ) == TCL_OK )
788 {
789 if ( Tcl_GetBooleanFromObj ( interp, tp, b2 ) != TCL_OK )
790 return TCL_ERROR;
791 }
792
793 return TCL_OK;
794 }
795 }
796 }
797
798 Tcl_AppendResult ( interp, "Expected boolean value or list of "
799
800 "two boolean values but got \"", Tcl_GetString ( obj ), "\"", NULL );
801
802 return TCL_ERROR;
803 }
804
805 /**
806 **/
gnoclGet2Int(Tcl_Interp * interp,Tcl_Obj * obj,int * b1,int * b2)807 int gnoclGet2Int ( Tcl_Interp *interp, Tcl_Obj *obj, int *b1, int *b2 )
808 {
809 int no;
810
811 if ( Tcl_ListObjLength ( interp, obj, &no ) == TCL_OK
812 && ( no == 2 || no == 1 ) )
813 {
814 if ( no == 1 )
815 {
816 if ( Tcl_GetIntFromObj ( interp, obj, b1 ) != TCL_OK )
817 return TCL_ERROR;
818
819 *b2 = *b1;
820
821 return TCL_OK;
822 }
823
824 else
825 {
826 Tcl_Obj *tp;
827
828 if ( Tcl_ListObjIndex ( interp, obj, 0, &tp ) == TCL_OK )
829 {
830 if ( Tcl_GetIntFromObj ( interp, tp, b1 ) != TCL_OK )
831 return TCL_ERROR;
832
833 if ( Tcl_ListObjIndex ( interp, obj, 1, &tp ) == TCL_OK )
834 {
835 if ( Tcl_GetIntFromObj ( interp, tp, b2 ) != TCL_OK )
836 return TCL_ERROR;
837 }
838
839 return TCL_OK;
840 }
841 }
842 }
843
844 Tcl_AppendResult ( interp, "Expected integer value or list of "
845 "two integer values but got \"", Tcl_GetString ( obj ), "\"", NULL );
846
847 return TCL_ERROR;
848 }
849
850 /**
851 **/
gnoclGet2Double(Tcl_Interp * interp,Tcl_Obj * obj,double * b1,double * b2)852 int gnoclGet2Double ( Tcl_Interp *interp, Tcl_Obj *obj, double *b1, double *b2 )
853 {
854 int no;
855
856 if ( Tcl_ListObjLength ( interp, obj, &no ) == TCL_OK
857 && ( no == 2 || no == 1 ) )
858 {
859 if ( no == 1 )
860 {
861 if ( Tcl_GetDoubleFromObj ( interp, obj, b1 ) != TCL_OK )
862 {
863 return TCL_ERROR;
864 }
865
866 *b2 = *b1;
867
868 return TCL_OK;
869 }
870
871 else
872 {
873 Tcl_Obj *tp;
874
875 if ( Tcl_ListObjIndex ( interp, obj, 0, &tp ) == TCL_OK )
876 {
877 if ( Tcl_GetDoubleFromObj ( interp, tp, b1 ) != TCL_OK )
878 {
879 return TCL_ERROR;
880 }
881
882 if ( Tcl_ListObjIndex ( interp, obj, 1, &tp ) == TCL_OK )
883 {
884 if ( Tcl_GetDoubleFromObj ( interp, tp, b2 ) != TCL_OK )
885 {
886 return TCL_ERROR;
887 }
888 }
889
890 return TCL_OK;
891 }
892 }
893 }
894
895 Tcl_AppendResult ( interp, "Expected float value or list of "
896
897 "two float values but got \"", Tcl_GetString ( obj ), "\"", NULL );
898
899 return TCL_ERROR;
900 }
901
902
903
904 /**
905 */
getScrollbarPolicy(Tcl_Interp * interp,Tcl_Obj * obj,GtkPolicyType * pol)906 static int getScrollbarPolicy ( Tcl_Interp *interp, Tcl_Obj *obj, GtkPolicyType *pol )
907 {
908 const char *txt[] = { "always", "never", "automatic", NULL };
909 GtkPolicyType policies[] =
910 {
911 GTK_POLICY_ALWAYS, GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC
912 };
913 int on;
914
915 if ( Tcl_GetBooleanFromObj ( NULL, obj, &on ) == TCL_OK )
916 {
917 *pol = on ? GTK_POLICY_ALWAYS : GTK_POLICY_NEVER;
918 }
919
920 else
921 {
922 int idx;
923
924 if ( Tcl_GetIndexFromObj ( interp, obj, txt, "scrollbar policy", TCL_EXACT, &idx ) != TCL_OK )
925 {
926 return TCL_ERROR;
927 }
928
929 *pol = policies[idx];
930 }
931
932 return TCL_OK;
933 }
934
935
936
937 /**
938 */
gnoclGetScrollbarPolicy(Tcl_Interp * interp,Tcl_Obj * obj,GtkPolicyType * hor,GtkPolicyType * vert)939 int gnoclGetScrollbarPolicy ( Tcl_Interp *interp, Tcl_Obj *obj, GtkPolicyType *hor, GtkPolicyType *vert )
940 {
941 int no;
942
943 if ( Tcl_ListObjLength ( interp, obj, &no ) != TCL_OK || no > 2 )
944 {
945 Tcl_SetResult ( interp, "policy must be either a single value "
946 "or a list with two elements.", TCL_STATIC );
947 return TCL_ERROR;
948 }
949
950 if ( no == 1 )
951 {
952 if ( getScrollbarPolicy ( interp, obj, hor ) != TCL_OK )
953 return TCL_ERROR;
954
955 *vert = *hor;
956 }
957
958 else
959 {
960 Tcl_Obj *tp;
961
962 if ( Tcl_ListObjIndex ( interp, obj, 0, &tp ) != TCL_OK )
963 return TCL_ERROR;
964
965 if ( getScrollbarPolicy ( interp, tp, hor ) != TCL_OK )
966 return TCL_ERROR;
967
968 if ( Tcl_ListObjIndex ( interp, obj, 1, &tp ) != TCL_OK )
969 return TCL_ERROR;
970
971 if ( getScrollbarPolicy ( interp, tp, vert ) != TCL_OK )
972 return TCL_ERROR;
973 }
974
975 return TCL_OK;
976 }
977
978
979
980 /**
981 */
gnoclGetSelectionMode(Tcl_Interp * interp,Tcl_Obj * obj,GtkSelectionMode * selection)982 int gnoclGetSelectionMode ( Tcl_Interp *interp, Tcl_Obj *obj, GtkSelectionMode *selection )
983 {
984 const char *txt[] = { "single", "browse", "multiple", "extended", NULL };
985 GtkSelectionMode modes[] = { GTK_SELECTION_SINGLE, GTK_SELECTION_BROWSE, GTK_SELECTION_MULTIPLE, GTK_SELECTION_EXTENDED };
986
987 int idx;
988
989 if ( Tcl_GetIndexFromObj ( interp, obj, txt, "selection modes",
990 TCL_EXACT, &idx ) != TCL_OK )
991 return TCL_ERROR;
992
993 *selection = modes[idx];
994
995 return TCL_OK;
996 }
997
998
999
1000 /**
1001 */
gnoclGetOrientationType(Tcl_Interp * interp,Tcl_Obj * obj,GtkOrientation * orient)1002 int gnoclGetOrientationType ( Tcl_Interp *interp, Tcl_Obj *obj, GtkOrientation *orient )
1003 {
1004 const char *txt[] = { "horizontal", "vertical", NULL };
1005 GtkOrientation types[] = { GTK_ORIENTATION_HORIZONTAL, GTK_ORIENTATION_VERTICAL };
1006
1007 int idx;
1008
1009 if ( Tcl_GetIndexFromObj ( interp, obj, txt, "orientation", TCL_EXACT, &idx ) != TCL_OK )
1010 {
1011 return TCL_ERROR;
1012 }
1013
1014 *orient = types[idx];
1015
1016 return TCL_OK;
1017 }
1018
1019
1020 /**
1021 */
gnoclGetWindowType(Tcl_Interp * interp,Tcl_Obj * obj,GtkWindowType * type)1022 int gnoclGetWindowType ( Tcl_Interp *interp, Tcl_Obj *obj, GtkWindowType *type )
1023 {
1024 const char *txt[] = { "popup", "toplevel", NULL };
1025
1026 GtkWindowType types[] = { GTK_WINDOW_POPUP, GTK_WINDOW_TOPLEVEL };
1027
1028 int idx;
1029
1030 if ( Tcl_GetIndexFromObj ( interp, obj, txt, "types", TCL_EXACT, &idx ) != TCL_OK )
1031 {
1032 return TCL_ERROR;
1033 }
1034
1035 *type = types[idx];
1036
1037 return TCL_OK;
1038 }
1039
1040
1041 /**
1042 \brief This function simply loads a single file from disk into memory.
1043 **/
gnoclPixbufFromObj(Tcl_Interp * interp,GnoclOption * opt)1044 GdkPixbuf *gnoclPixbufFromObj ( Tcl_Interp *interp, GnoclOption *opt )
1045 {
1046 char *txt = gnoclGetString ( opt->val.obj );
1047 GError *error = NULL;
1048 GdkPixbuf *pix = gdk_pixbuf_new_from_file ( txt, &error );
1049
1050 assert ( gnoclGetStringType ( opt->val.obj ) == GNOCL_STR_FILE );
1051
1052 if ( pix == NULL )
1053 {
1054 Tcl_SetResult ( interp, error->message, TCL_VOLATILE );
1055 g_error_free ( error );
1056 return NULL;
1057 }
1058
1059 return pix;
1060 }
1061
1062 /**
1063 \brief Read in a list of images and bitmasks, composite them to a single
1064 pixbuf and then return a pointer to the pixbuf to the calling function
1065 \note This assumes that the images to be composite and the masks are ALL of
1066 matching sizes. There is no attempt to reposition or resize graphics.
1067 Key Library Functions
1068 GtkWidget *gtk_image_new_from_file (const gchar *filename);
1069 GtkWidget *gtk_image_new_from_pixbuf (GdkPixbuf *pixbuf);
1070 void gtk_image_get_image (GtkImage *image, GdkImage **gdk_image, GdkBitmap **mask);
1071 GtkWidget *gtk_image_new_from_image (GdkImage *image, GdkBitmap *mask);
1072 GdkPixbuf *gtk_image_get_pixbuf (GtkImage *image);
1073 void gdk_pixbuf_render_threshold_alpha (GdkPixbuf *pixbuf,GdkBitmap *bitmap, int src_x,
1074 int src_y, int dest_x, int dest_y, int width, int height, int alpha_threshold);
1075 ie. gdk_pixbuf_render_threshold_alpha (pb,mp,0,0,0,0,-1,-1,128);
1076 */
gnoclBlendPixbufFromObj(Tcl_Interp * interp,GnoclOption * opt)1077 GdkPixbuf *gnoclBlendPixbufFromObj ( Tcl_Interp *interp, GnoclOption *opt )
1078 {
1079
1080 GdkPixbuf *pixbuf = NULL;
1081 GError *err = NULL;
1082 GtkWidget *gtk_image = NULL;
1083 GtkWidget *gtk_image_blend = NULL;
1084 GdkImage *gdk_image = NULL;
1085 GdkBitmap *gdk_bitmap = NULL;
1086
1087 char * pch;
1088
1089 printf ( "helperFuncs/gnoclBlendPixbufFromObj pixbuf %s\n", Tcl_GetString ( opt->val.obj ) );
1090
1091 pch = strtok ( Tcl_GetString ( opt->val.obj ), " " );
1092 int aa = 0;
1093 int bb = 0;
1094
1095 while ( pch != NULL )
1096 {
1097 switch ( aa )
1098 {
1099 case 0:
1100 {
1101 g_print ( "pch = %s\n", pch );
1102 pixbuf = gdk_pixbuf_new_from_file ( pch , &err );
1103
1104 if ( err != NULL )
1105 {
1106 g_warning ( "%s", err->message );
1107 g_error_free ( err );
1108 return NULL;
1109 }
1110
1111 /* error checking over, create the image */
1112 gtk_image = gtk_image_new_from_pixbuf ( pixbuf );
1113
1114 /* create a gdk_image from this, dump any alpha channel */
1115
1116 if ( gdk_image == NULL )
1117 {
1118
1119 /* get the size of the pixbuf */
1120
1121 g_print ( "make a new gdk_image\n" );
1122 gdk_image = gdk_image_new (
1123 GDK_IMAGE_FASTEST,
1124 gdk_visual_get_system(),
1125 gdk_pixbuf_get_width ( pixbuf ),
1126 gdk_pixbuf_get_height ( pixbuf ) );
1127 }
1128
1129 g_print ( "AAA\n" );
1130 gtk_image_get_image ( GTK_IMAGE ( gtk_image ), &gdk_image, NULL );
1131 g_print ( "BBB\n" );
1132
1133 }
1134
1135 break;
1136 case 1:
1137 {
1138
1139 pixbuf = gdk_pixbuf_new_from_file ( pch, &err );
1140
1141 if ( err != NULL )
1142 {
1143 g_warning ( "%s", err->message );
1144 g_error_free ( err );
1145 return NULL;
1146 }
1147
1148 /* error checking over, create the clipping mask */
1149 gdk_pixbuf_render_threshold_alpha ( pixbuf, gdk_bitmap, 0, 0, 0, 0, -1, -1, 1 );
1150 }
1151
1152 break;
1153 }
1154
1155 if ( aa < 3 )
1156 {
1157 aa++;
1158 }
1159
1160 else
1161 {
1162 aa = 0;
1163 }
1164
1165 pch = strtok ( NULL, " " );
1166
1167 /* do the actual compositing onto the buffer background */
1168
1169 gtk_image_blend = gtk_image_new_from_image ( gdk_image, gdk_bitmap );
1170
1171 g_print ( "composite images now!\n" );
1172
1173
1174 }
1175
1176 if ( 0 )
1177 {
1178 return gtk_image_get_pixbuf ( gtk_image_blend );
1179 }
1180
1181 else
1182 {
1183 return pixbuf;
1184 }
1185 }
1186
1187 /* reverse: reverse string s in place */
reverse(char s[])1188 void reverse ( char s[] )
1189 {
1190 int i, j;
1191 char c;
1192
1193 for ( i = 0, j = strlen ( s ) - 1; i < j; i++, j-- )
1194 {
1195 c = s[i];
1196 s[i] = s[j];
1197 s[j] = c;
1198 }
1199 }
1200
1201
1202 /**
1203 \brief convert n to characters in s
1204 **/
itoa(int n,char s[])1205 void itoa ( int n, char s[] )
1206 {
1207 int i, sign;
1208
1209 if ( ( sign = n ) < 0 ) /* record sign */
1210 n = -n; /* make n positive */
1211
1212 i = 0;
1213
1214 do /* generate digits in reverse order */
1215 {
1216 s[i++] = n % 10 + '0'; /* get next digit */
1217 }
1218 while ( ( n /= 10 ) > 0 ); /* delete it */
1219
1220 if ( sign < 0 )
1221 s[i++] = '-';
1222
1223 s[i] = '\0';
1224 reverse ( s );
1225 }
1226
1227 /**
1228 \brief Simple check to see if a file exists.
1229 **/
exists(const char * fname)1230 int exists ( const char *fname )
1231 {
1232 FILE *file;
1233
1234 if ( file = fopen ( fname, "r" ) )
1235 {
1236 fclose ( file );
1237 return 1;
1238 }
1239
1240 return 0;
1241 }
1242