1 //
2 // "$Id: demo.cxx 8252 2011-01-11 10:36:44Z manolo $"
3 //
4 // Main demo program for the Fast Light Tool Kit (FLTK).
5 //
6 // Copyright 1998-2010 by Bill Spitzak and others.
7 //
8 // This library is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU Library General Public
10 // License as published by the Free Software Foundation; either
11 // version 2 of the License, or (at your option) any later version.
12 //
13 // This library is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 // Library General Public License for more details.
17 //
18 // You should have received a copy of the GNU Library General Public
19 // License along with this library; if not, write to the Free Software
20 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21 // USA.
22 //
23 // Please report all bugs and problems on the following page:
24 //
25 //     http://www.fltk.org/str.php
26 //
27 
28 #include <stdio.h>
29 #include <string.h>
30 #include <stdlib.h>
31 #if defined(WIN32) && !defined(__CYGWIN__)
32 #  include <direct.h>
33 #  ifndef __WATCOMC__
34 // Visual C++ 2005 incorrectly displays a warning about the use of POSIX APIs
35 // on Windows, which is supposed to be POSIX compliant...
36 #    define chdir _chdir
37 #    define putenv _putenv
38 #  endif // !__WATCOMC__
39 #elif defined USING_XCODE
40 #include <ApplicationServices/ApplicationServices.h>
41 #include <unistd.h> // for chdir()
42 #include <stdio.h>
43 #include <stdlib.h> // for system()
44 #include <string.h>
45 #else
46 #  include <unistd.h>
47 #endif
48 #include <FL/Fl.H>
49 #include <FL/Fl_Double_Window.H>
50 #include <FL/Fl_Box.H>
51 #include <FL/Fl_Button.H>
52 #include <FL/Fl_Choice.H>
53 #include <FL/filename.H>
54 #include <FL/x.H>
55 
56 /* The form description */
57 
58 void doexit(Fl_Widget *, void *);
59 void doback(Fl_Widget *, void *);
60 void dobut(Fl_Widget *, long);
doscheme(Fl_Choice * c,void *)61 void doscheme(Fl_Choice *c, void *) {
62   Fl::scheme(c->text(c->value()));
63 }
64 
65 Fl_Double_Window *form;
66 Fl_Button *but[9];
67 
create_the_forms()68 void create_the_forms() {
69   Fl_Widget *obj;
70   form = new Fl_Double_Window(350, 440);
71   obj = new Fl_Box(FL_FRAME_BOX,10,15,330,40,"FLTK Demonstration");
72   obj->color(FL_GRAY-4);
73   obj->labelsize(24);
74   obj->labelfont(FL_BOLD);
75   obj->labeltype(FL_ENGRAVED_LABEL);
76   obj = new Fl_Box(FL_FRAME_BOX,10,65,330,330,0);
77   obj->color(FL_GRAY-8);
78   obj = new Fl_Button(280,405,60,25,"Exit");
79   obj->callback(doexit);
80   Fl_Choice *choice = new Fl_Choice(75, 405, 100, 25, "Scheme:");
81   choice->labelfont(FL_HELVETICA_BOLD);
82   choice->add("none");
83   choice->add("gtk+");
84   choice->add("plastic");
85   choice->callback((Fl_Callback *)doscheme);
86   Fl::scheme(NULL);
87   if (!Fl::scheme()) choice->value(0);
88   else if (!strcmp(Fl::scheme(), "gtk+")) choice->value(1);
89   else choice->value(2);
90   obj = new Fl_Button(10,15,330,380); obj->type(FL_HIDDEN_BUTTON);
91   obj->callback(doback);
92   obj = but[0] = new Fl_Button( 30, 85,90,90);
93   obj = but[1] = new Fl_Button(130, 85,90,90);
94   obj = but[2] = new Fl_Button(230, 85,90,90);
95   obj = but[3] = new Fl_Button( 30,185,90,90);
96   obj = but[4] = new Fl_Button(130,185,90,90);
97   obj = but[5] = new Fl_Button(230,185,90,90);
98   obj = but[6] = new Fl_Button( 30,285,90,90);
99   obj = but[7] = new Fl_Button(130,285,90,90);
100   obj = but[8] = new Fl_Button(230,285,90,90);
101   for (int i=0; i<9; i++) {
102     but[i]->align(FL_ALIGN_WRAP);
103     but[i]->callback(dobut, i);
104   }
105   form->end();
106 }
107 
108 /* Maintaining and building up the menus. */
109 
110 typedef struct {
111   char name[64];
112   int numb;
113   char iname[9][64];
114   char icommand[9][64];
115 } MENU;
116 
117 #define MAXMENU	32
118 
119 MENU menus[MAXMENU];
120 int mennumb = 0;
121 
find_menu(const char * nnn)122 int find_menu(const char* nnn)
123 /* Returns the number of a given menu name. */
124 {
125   int i;
126   for (i=0; i<mennumb; i++)
127     if (strcmp(menus[i].name,nnn) == 0) return i;
128   return -1;
129 }
130 
create_menu(const char * nnn)131 void create_menu(const char* nnn)
132 /* Creates a new menu with name nnn */
133 {
134   if (mennumb == MAXMENU -1) return;
135   strcpy(menus[mennumb].name,nnn);
136   menus[mennumb].numb = 0;
137   mennumb++;
138 }
139 
addto_menu(const char * men,const char * item,const char * comm)140 void addto_menu(const char* men, const char* item, const char* comm)
141 /* Adds an item to a menu */
142 {
143   int n = find_menu(men);
144   if (n<0) { create_menu(men); n = find_menu(men); }
145   if (menus[n].numb == 9) return;
146   strcpy(menus[n].iname[menus[n].numb],item);
147   strcpy(menus[n].icommand[menus[n].numb],comm);
148   menus[n].numb++;
149 }
150 
151 /* Button to Item conversion and back. */
152 
153 int b2n[][9] = {
154 	{ -1, -1, -1, -1,  0, -1, -1, -1, -1},
155 	{ -1, -1, -1,  0, -1,  1, -1, -1, -1},
156 	{  0, -1, -1, -1,  1, -1, -1, -1,  2},
157 	{  0, -1,  1, -1, -1, -1,  2, -1,  3},
158 	{  0, -1,  1, -1,  2, -1,  3, -1,  4},
159 	{  0, -1,  1,  2, -1,  3,  4, -1,  5},
160 	{  0, -1,  1,  2,  3,  4,  5, -1,  6},
161 	{  0,  1,  2,  3, -1,  4,  5,  6,  7},
162 	{  0,  1,  2,  3,  4,  5,  6,  7,  8}
163 };
164 int n2b[][9] = {
165 	{  4, -1, -1, -1, -1, -1, -1, -1, -1},
166 	{  3,  5, -1, -1, -1, -1, -1, -1, -1},
167 	{  0,  4,  8, -1, -1, -1, -1, -1, -1},
168 	{  0,  2,  6,  8, -1, -1, -1, -1, -1},
169 	{  0,  2,  4,  6,  8, -1, -1, -1, -1},
170 	{  0,  2,  3,  5,  6,  8, -1, -1, -1},
171 	{  0,  2,  3,  4,  5,  6,  8, -1, -1},
172 	{  0,  1,  2,  3,  5,  6,  7,  8, -1},
173 	{  0,  1,  2,  3,  4,  5,  6,  7,  8}
174 };
175 
but2numb(int bnumb,int maxnumb)176 int but2numb(int bnumb, int maxnumb)
177 /* Transforms a button number to an item number when there are
178  maxnumb items in total. -1 if the button should not exist. */
179 { return b2n[maxnumb][bnumb]; }
180 
numb2but(int inumb,int maxnumb)181 int numb2but(int inumb, int maxnumb)
182 /* Transforms an item number to a button number when there are
183  maxnumb items in total. -1 if the item should not exist. */
184 { return n2b[maxnumb][inumb]; }
185 
186 /* Pushing and Popping menus */
187 
188 char stack[64][32];
189 int stsize = 0;
190 
push_menu(const char * nnn)191 void push_menu(const char* nnn)
192 /* Pushes a menu to be visible */
193 {
194   int n,i,bn;
195   int men = find_menu(nnn);
196   if (men < 0) return;
197   n = menus[men].numb;
198   for (i=0; i<9; i++) but[i]->hide();
199   for (i=0; i<n; i++)
200   {
201     bn = numb2but(i,n-1);
202     but[bn]->show();
203     but[bn]->label(menus[men].iname[i]);
204     if (menus[men].icommand[i][0] != '@') but[bn]->tooltip(menus[men].icommand[i]);
205     else but[bn]->tooltip(0);
206   }
207   if (stack[stsize]!=nnn)
208     strcpy(stack[stsize],nnn);
209   stsize++;
210 }
211 
pop_menu()212 void pop_menu()
213 /* Pops a menu */
214 {
215   if (stsize<=1) return;
216   stsize -= 2;
217   push_menu(stack[stsize]);
218 }
219 
220 /* The callback Routines */
221 
dobut(Fl_Widget *,long arg)222 void dobut(Fl_Widget *, long arg)
223 /* handles a button push */
224 {
225   int men = find_menu(stack[stsize-1]);
226   int n = menus[men].numb;
227   int bn = but2numb( (int) arg, n-1);
228   if (menus[men].icommand[bn][0] == '@')
229     push_menu(menus[men].icommand[bn]);
230   else {
231 
232 #ifdef WIN32
233     STARTUPINFO		suInfo;		// Process startup information
234     PROCESS_INFORMATION	prInfo;		// Process information
235 
236     memset(&suInfo, 0, sizeof(suInfo));
237     suInfo.cb = sizeof(suInfo);
238 
239     int icommand_length = strlen(menus[men].icommand[bn]);
240 
241     char* copy_of_icommand = new char[icommand_length+1];
242     strcpy(copy_of_icommand,menus[men].icommand[bn]);
243 
244     // On WIN32 the .exe suffix needs to be appended to the command
245     // whilst leaving any additional parameters unchanged - this
246     // is required to handle the correct conversion of cases such as :
247     // `../fluid/fluid valuators.fl' to '../fluid/fluid.exe valuators.fl'.
248 
249     // skip leading spaces.
250     char* start_command = copy_of_icommand;
251     while(*start_command == ' ') ++start_command;
252 
253     // find the space between the command and parameters if one exists.
254     char* start_parameters = strchr(start_command,' ');
255 
256     char* command = new char[icommand_length+6]; // 6 for extra 'd.exe\0'
257 
258     if (start_parameters==NULL) { // no parameters required.
259 #  ifdef _DEBUG
260       sprintf(command, "%sd.exe", start_command);
261 #  else
262       sprintf(command, "%s.exe", start_command);
263 #  endif // _DEBUG
264     } else { // parameters required.
265       // break the start_command at the intermediate space between
266       // start_command and start_parameters.
267       *start_parameters = 0;
268       // move start_paremeters to skip over the intermediate space.
269       ++start_parameters;
270 
271 #  ifdef _DEBUG
272       sprintf(command, "%sd.exe %s", start_command, start_parameters);
273 #  else
274       sprintf(command, "%s.exe %s", start_command, start_parameters);
275 #  endif // _DEBUG
276     }
277 
278     CreateProcess(NULL, command, NULL, NULL, FALSE,
279                   NORMAL_PRIORITY_CLASS, NULL, NULL, &suInfo, &prInfo);
280 
281     delete[] command;
282     delete[] copy_of_icommand;
283 
284 #elif defined USING_XCODE
285     char *cmd = strdup(menus[men].icommand[bn]);
286     char *arg = strchr(cmd, ' ');
287 
288     char command[2048], path[2048], app_path[2048];
289 
290     // this neat litle block of code ensures that the current directory is set
291     // to the location of the Demo application.
292     CFBundleRef app = CFBundleGetMainBundle();
293     CFURLRef url = CFBundleCopyBundleURL(app);
294     CFStringRef cc_app_path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
295     CFStringGetCString(cc_app_path, app_path, 2048, kCFStringEncodingUTF8);
296     if (*app_path) {
297       char *n = strrchr(app_path, '/');
298       if (n) {
299         *n = 0;
300         chdir(app_path);
301       }
302     }
303 
304     if (arg) {
305       *arg = 0;
306       if (strcmp(cmd, "../fluid/fluid")==0) {
307         fl_filename_absolute(path, 2048, "../../../../test/");
308 	sprintf(command, "open Fluid.app --args %s%s", path, arg+1);
309       } else {
310         fl_filename_absolute(path, 2048, "../../../../test/");
311 	sprintf(command, "open %s.app --args %s%s", cmd, path, arg+1);
312       }
313     } else {
314       sprintf(command, "open %s.app", cmd);
315     }
316 //    puts(command);
317     system(command);
318 
319     free(cmd);
320 #else // NON WIN32 systems.
321 
322     int icommand_length = strlen(menus[men].icommand[bn]);
323     char* command = new char[icommand_length+5]; // 5 for extra './' and ' &\0'
324 
325     sprintf(command, "./%s &", menus[men].icommand[bn]);
326     if (system(command)==-1) { /* ignore */ }
327 
328     delete[] command;
329 #endif // WIN32
330   }
331 }
332 
doback(Fl_Widget *,void *)333 void doback(Fl_Widget *, void *) {pop_menu();}
334 
doexit(Fl_Widget *,void *)335 void doexit(Fl_Widget *, void *) {exit(0);}
336 
load_the_menu(const char * fname)337 int load_the_menu(const char* fname)
338 /* Loads the menu file. Returns whether successful. */
339 {
340   FILE *fin = 0;
341   char line[256], mname[64],iname[64],cname[64];
342   int i, j;
343   fin = fl_fopen(fname,"r");
344 #if defined ( USING_XCODE )
345   if (fin == NULL) {
346     // mac os bundle menu detection:
347     char* pos = strrchr(fname,'/');
348     if (!pos) return 0;
349     *pos='\0';
350     pos = strrchr(fname,'/');
351     if (!pos) return 0;
352     strcpy(pos,"/Resources/demo.menu");
353     fin  = fl_fopen(fname,"r");
354   }
355 #endif
356   if (fin == NULL) {
357     return 0;
358   }
359   for (;;) {
360     if (fgets(line,256,fin) == NULL) break;
361     // remove all carriage returns that Cygwin may have inserted
362     char *s = line, *d = line;
363     for (;;++d) {
364       while (*s=='\r') s++;
365       *d = *s++;
366       if (!*d) break;
367     }
368     // interprete the line
369     j = 0; i = 0;
370     while (line[i] == ' ' || line[i] == '\t') i++;
371     if (line[i] == '\n') continue;
372     if (line[i] == '#') continue;
373     while (line[i] != ':' && line[i] != '\n') mname[j++] = line[i++];
374     mname[j] = '\0';
375     if (line[i] == ':') i++;
376     j = 0;
377     while (line[i] != ':' && line[i] != '\n')
378     {
379       if (line[i] == '\\') {
380         i++;
381         if (line[i] == 'n') iname[j++] = '\n';
382         else iname[j++] = line[i];
383         i++;
384       } else
385         iname[j++] = line[i++];
386     }
387     iname[j] = '\0';
388     if (line[i] == ':') i++;
389     j = 0;
390     while (line[i] != ':' && line[i] != '\n') cname[j++] = line[i++];
391     cname[j] = '\0';
392     addto_menu(mname,iname,cname);
393   }
394   fclose(fin);
395   return 1;
396 }
397 
main(int argc,char ** argv)398 int main(int argc, char **argv) {
399   putenv((char *)"FLTK_DOCDIR=../documentation/html");
400   char buf[FL_PATH_MAX];
401   strcpy(buf, argv[0]);
402 #if ( defined _MSC_VER || defined __MWERKS__ ) && defined _DEBUG
403   // MS_VisualC appends a 'd' to debugging executables. remove it.
404   fl_filename_setext( buf, "" );
405   buf[ strlen(buf)-1 ] = 0;
406 #endif
407   fl_filename_setext(buf,".menu");
408   const char *fname = buf;
409   int i = 0;
410   if (!Fl::args(argc,argv,i) || i < argc-1)
411     Fl::fatal("Usage: %s <switches> <menufile>\n%s",argv[0],Fl::help);
412   if (i < argc) fname = argv[i];
413 
414   create_the_forms();
415 
416   if (!load_the_menu(fname)) Fl::fatal("Can't open %s",fname);
417   if (buf!=fname)
418     strcpy(buf,fname);
419   const char *c = fl_filename_name(buf);
420   if (c > buf) {
421     buf[c-buf] = 0;
422     if (chdir(buf)==-1) { /* ignore */ }
423   }
424   push_menu("@main");
425   form->show(argc,argv);
426   Fl::run();
427   return 0;
428 }
429 
430 //
431 // End of "$Id: demo.cxx 8252 2011-01-11 10:36:44Z manolo $".
432 //
433 
434