You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

434 lines
12KB

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