Finished up the map-gen functionality. Added a converter functionallity to convert...
[agi-studio-improvements:agi-studio-improvements.git] / trunk / agistudio / src / menu.cpp
1 /*
2  *  QT AGI Studio :: Copyright (C) 2000 Helen Zommer
3  *
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  *
19  */
20
21 #include "menu.h"
22 #include "game.h"
23 #include "wordsedit.h"
24 #include "objedit.h"
25 #include "viewedit.h"
26 #include "logedit.h"
27 #include "resources.h"
28 #include "wutil.h"
29 #include "preview.h"
30 #include "picedit.h"
31 #include "dir.h"
32 #include "options.h"
33 #include "helpwindow.h"
34
35 #include <stdio.h>
36 #ifdef _WIN32
37   #include <direct.h>
38   #include <process.h>
39   #include <windows.h>
40   #define TEXT 6
41 #else
42   #include <unistd.h>
43 #endif
44 #include <sys/stat.h>
45 #include <stdlib.h>
46 #include <string.h>
47
48 #include <qapplication.h>
49 #include <qpixmap.h>
50 #include <qtoolbar.h>
51 #include <qtoolbutton.h>
52 #include <qtooltip.h>
53 #ifdef IMGEXT
54   #include <qimageio.h>
55 #endif
56 #include <qstylesheet.h>
57
58 #include "toolbar_open.xpm"
59 #include "toolbar_close.xpm"
60 #include "toolbar_run.xpm"
61 #include "toolbar_viewedit.xpm"
62 #include "toolbar_logedit.xpm"
63 #include "toolbar_picedit.xpm"
64 #include "toolbar_wordsedit.xpm"
65 #include "toolbar_objedit.xpm"
66 #include "toolbar_textedit.xpm"
67 #include "logo.xpm"
68 #include "app_icon.xpm"
69
70 // Added by William Heineman
71 #include <iostream>
72 #include <fstream>
73 #include <sstream>
74 #include <cstdio>
75 #include <cstdlib>
76
77 extern char tmp[];
78 Menu *menu;
79 WindowList *window_list;
80 static About *about;
81 WinList winlist[MAXWIN];  //list of all open resource editor windows
82
83 //*************************************************
84 Menu::Menu( QWidget *parent, const char *name )
85     : QMainWindow( parent, name )
86 {
87   int n=0;
88
89   setCaption("AGI Studio");
90   setIcon((const char**)app_icon);
91
92   QPopupMenu *new_game = new QPopupMenu( this );
93   CHECK_PTR( new_game );
94
95   new_game->insertItem ( "From &Template", this, SLOT(from_template()) );
96   new_game->insertItem ( "&Blank", this, SLOT(blank()) );
97
98   QPopupMenu *game = new QPopupMenu( this );
99   CHECK_PTR( game );
100
101   game->insertItem ( "&New", new_game );
102   game->insertItem ( "&Open", this, SLOT(open_game()) );
103   id[n++] = game->insertItem ( "&Close", this, SLOT(close_game()) );
104   id[n++] = game->insertItem ( "&Run", this, SLOT(run_game()), CTRL+Key_R );
105   game->insertSeparator();
106   game->insertItem ( "&Settings", this, SLOT(settings()) );
107   game->insertSeparator();
108   game->insertItem( "E&xit",  this, SLOT(quit_cb()), CTRL+Key_Q );
109
110   QPopupMenu *resource = new QPopupMenu( this );
111   CHECK_PTR( resource );
112
113   id[n++] = resource->insertItem ("New window", this, SLOT(new_resource_window()));
114   resource->insertSeparator();
115   n_res=n;
116   id[n++] = resource->insertItem ( "&Add", this, SLOT(add_resource()) );
117   id[n++] = resource->insertItem ( "&Extract", this, SLOT(extract_resource()) );
118   id[n++] = resource->insertItem ( "&Delete", this, SLOT(delete_resource()) );
119   id[n++] = resource->insertItem ( "&Renumber", this, SLOT(renumber_resource()) );
120   resource->insertSeparator();
121   id[n++] = resource->insertItem ( "Re&build VOL files", this, SLOT(rebuild_vol()) );
122   id[n++] = resource->insertItem ( "Recompile all", this, SLOT(recompile_all()) );
123
124
125   QPopupMenu *tools = new QPopupMenu( this );
126   CHECK_PTR( tools );
127
128   id[n++] = tools->insertItem ( "&View Editor", this, SLOT(view_editor()) );
129   id[n++] = tools->insertItem ( "&Logic Editor", this, SLOT(logic_editor()) );
130   id[n++] = tools->insertItem ( "&Text Editor", this, SLOT(text_editor()) );
131   id[n++] = tools->insertItem ( "&Object Editor", this, SLOT(object_editor()) );
132   id[n++] = tools->insertItem ( "&Words.tok Editor", this, SLOT(words_editor()) );
133   id[n++] = tools->insertItem ( "&Picture Editor", this, SLOT(picture_editor()) );
134   id[n++] = tools->insertItem ( "&Sound Player", this, SLOT(sound_player()) );
135
136   QPopupMenu *help = new QPopupMenu( this );
137   CHECK_PTR( help );
138
139   help->insertItem ( "&Contents", this, SLOT(help_contents()) );
140   help->insertItem ( "&Index", this, SLOT(help_index()), Key_F1);
141   help->insertSeparator();
142   help->insertItem ( "About", this, SLOT(about_it()) );
143   help->insertItem ( "About QT", this, SLOT(about_qt()) );
144
145         // Added by William Heineman
146         QPopupMenu *will = new QPopupMenu( this );
147         CHECK_PTR( will );
148
149         id[n++] = will->insertItem("Gen. Map", this, SLOT(gen_Map()) );
150         id[n++] = will->insertItem("Converter", this, SLOT(convert()) );
151         // End
152
153   QPopupMenu *window = new QPopupMenu( this );
154   CHECK_PTR( window );
155
156   window->insertItem ( "Save all", this, SLOT(save_all()) );
157   window->insertItem ( "Save all and run", this, SLOT(save_and_run()) );
158   window->insertItem ( "Window list", this, SLOT(window_list_cb()) );
159
160   menubar = new QMenuBar(this);
161   CHECK_PTR( menubar );
162   menubar->insertItem( "&Game", game );
163   menubar->insertItem( "&Resource", resource );
164   menubar->insertItem( "&Tools", tools );
165   menubar->insertItem( "Window", window );
166   menubar->insertItem( "Will", will ); // Added by William Heineman
167   menubar->insertSeparator();
168   menubar->insertItem( "&Help", help );
169   menubar->setSeparator( QMenuBar::InWindowsStyle );
170
171
172   QToolBar *toolbar = new QToolBar(this);
173   open = new QPushButton(toolbar);
174   open->setPixmap((const char**)toolbar_open);
175   connect( open, SIGNAL(clicked()), SLOT(open_game()) );
176   QToolTip::add( open, "Open game" );
177
178   close_ = new QPushButton(toolbar);
179   close_->setPixmap((const char**)toolbar_close);
180   connect( close_, SIGNAL(clicked()), SLOT(close_game()) );
181   QToolTip::add( close_, "Close game" );
182
183   run = new QPushButton(toolbar);
184   run->setPixmap((const char**)toolbar_run);
185   connect( run, SIGNAL(clicked()), SLOT(run_game()) );
186   QToolTip::add( run, "Run game" );
187
188   view = new QPushButton(toolbar);
189   view->setPixmap((const char**)toolbar_viewedit);
190   connect( view, SIGNAL(clicked()), SLOT(view_editor()) );
191   QToolTip::add( view, "View editor" );
192
193   logic = new QPushButton(toolbar);
194   logic->setPixmap((const char**)toolbar_logedit);
195   connect( logic, SIGNAL(clicked()), SLOT(logic_editor()) );
196   QToolTip::add( logic, "Logic editor" );
197
198   text = new QPushButton(toolbar);
199   text->setPixmap((const char**)toolbar_textedit);
200   connect( text, SIGNAL(clicked()), SLOT(text_editor()) );
201   QToolTip::add( text, "Text editor" );
202
203   obj = new QPushButton(toolbar);
204   obj->setPixmap((const char**)toolbar_objedit);
205   connect( obj, SIGNAL(clicked()), SLOT(object_editor()) );
206   QToolTip::add( obj, "Object editor" );
207
208   words = new QPushButton(toolbar);
209   words->setPixmap((const char**)toolbar_wordsedit);
210   connect( words, SIGNAL(clicked()), SLOT(words_editor()) );
211   QToolTip::add( words, "WORDS.TOK editor" );
212
213   pic = new QPushButton(toolbar);
214   pic->setPixmap((const char**)toolbar_picedit);
215   connect( pic, SIGNAL(clicked()), SLOT(picture_editor()) );
216   QToolTip::add( pic, "Picture editor" );
217
218         // Added by William Heineman
219         wil = new QPushButton(toolbar);
220         wil->setPixmap((const char**)toolbar_picedit);
221         connect( wil, SIGNAL(clicked()), SLOT(gen_Map()) );
222         QToolTip::add( wil, "Generate Map" );
223
224         con = new QPushButton(toolbar);
225         con->setPixmap((const char**)toolbar_objedit);
226         connect (con, SIGNAL(clicked()), SLOT(convert()) );
227         QToolTip::add( con, "Convert to standard format" );
228
229   toolbar->adjustSize();
230   toolbar->show();
231
232   status = new QStatusBar(this);
233   QLabel *msg = new QLabel( status, "message" );
234   status->addWidget( msg, 4 );
235   status->setSizeGripEnabled(false);
236
237   err = new QMessageBox(NULL, "AGI Studio");
238   err->setIcon(QMessageBox::Critical);
239   err->hide();
240
241   warn = new QMessageBox(NULL, "AGI Studio");
242   warn->setIcon(QMessageBox::Warning);
243   warn->hide();
244
245   max_disabled = n;
246   disable();
247
248   adjustSize();
249   setFixedSize(400,100);
250   setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ));
251
252   for(int i=0;i<MAXWIN;i++){
253     winlist[i].type=-1;
254   }
255   make_egacolors();
256 #ifdef IMGEXT
257   imgext=false;
258 #endif
259   dir_new=dir_open=NULL;
260   window_list=NULL;
261   resources_win=NULL;
262   num_res=0;
263 }
264
265 //**********************************************
266 int get_win()
267 {
268   int n;
269
270   for(n=0;n<MAXWIN;n++){
271     if(winlist[n].type==-1)break;
272   }
273   if(n==MAXWIN){
274     menu->errmes("Too many open windows !");
275     return -1;
276   }
277   return n;
278 }
279
280 //**********************************************
281 void Menu::disable()
282 {
283
284   for(int i=0;i<max_disabled;i++){
285     menubar->setItemEnabled( id[i], FALSE );
286   }
287   close_->setEnabled(false);
288   run->setEnabled(false);
289   view->setEnabled(false);
290   logic->setEnabled(false);
291   obj->setEnabled(false);
292   words->setEnabled(false);
293   pic->setEnabled(false);
294         wil->setEnabled(false); // Added by William Heineman
295         con->setEnabled(false);
296 }
297
298 //**********************************************
299 void Menu::enable()
300 {
301
302   for(int i=0;i<max_disabled;i++){
303     menubar->setItemEnabled( id[i], TRUE );
304   }
305   close_->setEnabled(true);
306   run->setEnabled(true);
307   view->setEnabled(true);
308   logic->setEnabled(true);
309   obj->setEnabled(true);
310   words->setEnabled(true);
311   pic->setEnabled(true);
312         wil->setEnabled(true); // Added by William Heineman
313         con->setEnabled(true);
314 }
315
316 //**********************************************
317 void Menu::open_game()
318 {
319
320   if(dir_open==NULL)dir_open=new Dir(0,0,false);
321   dir_open->open();
322
323 }
324
325 //**********************************************
326 void Menu::show_resources()
327 {
328
329   if(resources_win==NULL){
330     int n;
331     if((n=get_win())==-1)return;
332     resources_win = new ResourcesWin(NULL,"Resources",n);
333     winlist[n].type=RESOURCES;
334     winlist[n].w.r=resources_win;
335     inc_res(resources_win);
336   }
337   resources_win->select_resource_type(game->res_default);
338   resources_win->show();
339   enable();
340
341
342 }
343 //**********************************************
344 void Menu::inc_res(ResourcesWin *res)
345 {
346
347   num_res++;
348   if(num_res==1){
349     resources_win=res;
350     enable_resources();
351   }
352   else{
353     resources_win=NULL;
354     disable_resources();
355   }
356
357 }
358 //**********************************************
359 void Menu::dec_res()
360 {
361
362   num_res--;
363   if(num_res==1){
364     for(int i=0;i<MAXWIN;i++){
365       if(winlist[i].type==RESOURCES){
366         resources_win=winlist[i].w.r;
367         break;
368       }
369     }
370     enable_resources();
371   }
372   else{
373     resources_win=NULL;
374     disable_resources();
375   }
376
377 }
378 //**********************************************
379 void Menu::enable_resources()
380 {
381   for(int i=n_res;i<n_res+4;i++){
382     menubar->setItemEnabled( id[i], TRUE );
383   }
384
385
386 }
387 //**********************************************
388 void Menu::disable_resources()
389 {
390
391   for(int i=n_res;i<n_res+4;i++){
392     menubar->setItemEnabled( id[i], FALSE );
393   }
394
395 }
396 //**********************************************
397 // Added by William Heineman
398 void Menu::will_1()
399 {
400         close();
401 }
402
403 // Added by William Heineman
404 void Menu::gen_Map()
405 {
406         string line;
407         string log = "/src/logic1.txt";
408         string dir;
409         string file;
410
411         // Finds the path to the game directory which was stored in a file
412         //      dir.txt when the game was opened.
413         ifstream path("dir.txt");
414         path >> dir;
415         path.close();
416
417         int tracker = 1;
418         ifstream myfile;
419         while(1)
420         {
421                 file = dir + log;
422                 //cout << file << endl;
423                 myfile.open(file.c_str());
424
425                 if(myfile.is_open())
426                 {
427                         while(myfile.good())
428                         {
429                                 getline (myfile,line);
430                                 int loc = line.find("new.room");
431                                 if(loc != -1)
432                                 {
433                                         int neww = line[loc + 9] - 48;
434
435                                         //cout << line << endl;
436                                         //cout << line[loc + 9] << endl;
437                                         //cout << "Room " << tracker;
438                                         //cout << " has access to room ";
439                                         //cout << line[loc + 9] << endl;
440
441                                         // Adding nodes to diGraph
442                                         if(!(network.containsNode(tracker)))
443                                         {
444                                                 // Dummy value in the node
445                                                 network.addNode(tracker, 'n');
446                                         }
447                                         if(!(network.containsNode(neww)))
448                                         {
449                                                 // Dummy value in the node
450                                                 network.addNode(neww, 'n');
451                                         }
452                                         
453                                         // Adding edge to diGraph
454                                         network.setEdge(tracker, neww, 1, 'e');
455                                 }
456                                 loc = line.find("prev_room_no");
457                                 if(loc != -1)
458                                 {
459                                         int neww = line[loc + 16] - 48;
460
461                                         //cout << "Room " << tracker;
462                                         //cout << " is accessable from room ";
463                                         //cout << line[loc + 16] << endl;
464
465                                         // Adding nodes to diGraph
466                                         if(!(network.containsNode(tracker)))
467                                         {
468                                                 // Dummy value in the node
469                                                 network.addNode(tracker, 'n');
470                                         }
471                                         if(!(network.containsNode(neww)))
472                                         {
473                                                 // Dummy value in the node
474                                                 network.addNode(neww, 'n');
475                                         }
476                                         
477                                         // Adding edge to diGraph
478                                         network.setEdge(neww, tracker, 2, 'e');
479                                 }
480                         }
481
482                         myfile.close();
483                 }
484                 else
485                 {
486                         //cout << "ERROR: File not found" << endl;
487
488                         // Deals with different naming for logic files
489                         if(tracker == 1)
490                         {
491                                 if(log[5] == 'l')
492                                 {
493                                         log.replace(5,1,"L");
494                                         tracker--;
495                                 }
496                                 else
497                                 {
498                                         break;
499                                 }
500                         }
501                         else
502                         {
503                                 break;
504                         }
505                 }
506
507                 tracker++;
508                 stringstream out;
509                 out << tracker;
510                 string rep =  out.str();
511                 log.replace(10, 1, rep);
512         }
513
514         // Check graph
515         //test();
516
517         map_write();
518
519         //close();
520 }
521
522 // Prints graph
523 void Menu::test()
524 {
525         deque<int> nIndx(network.getNodeIndices());
526         deque<pair <int, int> > eIndx(network.getEdgeIndices());
527
528         cout << "The Node Indices" << endl;
529
530         for(unsigned int i = 0; i < nIndx.size(); i++)
531         {
532                 cout << nIndx[i] << endl;
533         }
534
535         cout << endl;
536
537         cout << "The Edge Indices" << endl;
538
539         for(unsigned int j = 0; j < eIndx.size(); j++)
540         {
541                 cout << eIndx[j].first << " " << eIndx[j].second << endl;
542         }
543 }
544
545 // Makes the map files
546 void Menu::map_write()
547 {
548         deque<int> nIndx(network.getNodeIndices());
549         deque<pair <int, int> > eIndx(network.getEdgeIndices());
550         string dir;
551
552         // Finds the path to the game directory which was stored in a file
553         //      dir.txt when the game was opened.
554         ifstream path("dir.txt");
555         path >> dir;
556         path.close();
557
558         dir += "/src/map.txt";
559
560         char *p = const_cast<char*> ( dir.c_str() );
561
562         ofstream myfile(p);
563
564         myfile << "NOTE:\n";
565         myfile << "This file is purly a reference file, any changes made to it will not \naffect the game in any way.\n\n";
566
567         myfile << "There are " << nIndx.size() << " rooms in this game." << endl;
568         myfile << "They are:" << endl;
569
570         for(unsigned int i = 2; i < nIndx.size(); i++)
571         {
572                 myfile << "Room number " << nIndx[i] << endl;
573         }
574
575         myfile << endl;
576
577         myfile << "There are " << eIndx.size() << " connections in this game." << endl;
578         myfile << "They are:" << endl;
579
580         for(unsigned int j = 0; j < eIndx.size(); j++)
581         {
582                 myfile << "From Room "<< eIndx[j].first << " to Room " << eIndx[j].second << endl;
583         }
584
585         myfile.close();
586
587         map_editor();
588 }
589
590 // Shows the map file
591 void Menu::map_editor()
592 {
593         int n;
594         string dir;
595
596         // Finds the path to the game directory which was stored in a file
597         //      dir.txt when the game was opened.
598         ifstream path("dir.txt");
599         path >> dir;
600         path.close();
601
602         dir += "/src/map.txt";
603
604         if((n=get_win())==-1)return;
605         winlist[n].w.t = new TextEdit(NULL,NULL,n);
606         winlist[n].type=TEXT;
607
608         char *p = const_cast<char*> (dir.c_str() );
609
610         winlist[n].w.t->open(p);
611 }
612
613 // Converts logic files into expected format
614 void Menu::convert()
615 {
616         string line;
617         string log = "/src/logic1.txt";
618         string log2 = log + "c";
619         string dir;
620         string file;
621         string file2;
622         string test;
623         int start, end, val;
624
625         // Finds the path to the game directory which was stored in a file
626         //      dir.txt when the game was opened.
627         ifstream path("dir.txt");
628         path >> dir;
629         path.close();
630
631         int tracker = 1;
632         ifstream myfile;
633         ofstream outfile;
634         while(1)
635         {
636                 file = dir + log;
637                 //cout << file << endl;
638                 myfile.open(file.c_str());
639                 file2 = dir + log2;
640                 outfile.open(file2.c_str());
641
642                 if(myfile.is_open())
643                 {
644                         while(myfile.good())
645                         {
646                                 getline (myfile,line);
647                                 int loc = line.find("new.room");
648                                 if(loc != -1)
649                                 {       
650                                         // Finds the name of the next room
651                                         start = line.find_first_of('(') + 1;
652                                         end = line.find_first_of(')', start);
653                                         test = line.substr(start, end - start);
654                                         //cout << test << "\t";
655
656                                         // Gets the int value of the next room
657                                         val = value(test);
658                                         //cout << val << endl;
659
660                                         stringstream out;
661                                         out << val;
662                                         string rep =  out.str();
663
664                                         line.replace(start, end - start, rep);
665                                 }
666
667                                 loc = 0;
668                                 while(loc != -1)
669                                 {
670                                         loc = line.find("prev_room_no", loc);
671                                         if(loc != -1)
672                                         {
673                                                 start = line.find("==", loc) + 3;
674                                                 end = line.find_first_not_of("abcdefghijklmnopqrstuvwxyz1234567890_", start);
675                                                 test = line.substr(start, end - start);
676                                                 //cout << test << "\t";
677
678                                                 // Gets the int value of prev. 
679                                                 // room
680                                                 val = value(test);
681                                                 //cout << val << endl;
682
683                                                 stringstream out;
684                                                 out << val;
685                                                 string rep =  out.str();
686
687                                                 line.replace(start, end - start, rep);
688
689                                                 // Updates loc
690                                                 loc += 1;
691                                         }
692                                 }
693
694                                 outfile << line << endl;
695                         }
696
697                         outfile << "\n";
698
699                         myfile.close();
700                         outfile.close();
701
702                         remove(file.c_str());
703                         rename(file2.c_str(), file.c_str());
704                 }
705                 else
706                 {
707                         outfile.close();
708                         remove(file2.c_str());
709
710                         // Deals with different naming for logic files
711                         if(tracker == 1)
712                         {
713                                 if(log[5] == 'l')
714                                 {
715                                         log.replace(5,1,"L");
716                                         tracker--;
717                                 }
718                                 else
719                                 {
720                                         break;
721                                 }
722                         }
723                         else
724                         {
725                                 break;
726                         }
727                 }
728
729                 tracker++;
730                 stringstream out;
731                 out << tracker;
732                 string rep =  out.str();
733                 log.replace(10, 1, rep);
734                 log2.replace(10, 1, rep);
735         }
736 }
737
738 // Gets the value of a string. If it is an int, returns that value
739 // If it is a defined value, returns that (from defines.txt)
740 // Returns -1 if conversion failed
741 int Menu::value(string str)
742 {
743         int val;
744         string dir;
745         string line;
746
747         // If the string is "0", it will mess with the operations,
748         //      handeling immediately
749         if((str[0] == 0) && (str.length() == 1))
750         {
751                 return 0;
752         }
753
754         // Attempts to convert directly to int
755         val = atoi(str.c_str());
756
757         // If the given string is not an int
758         if(val == 0)
759         {
760                 // Finds the path to the game directory which was stored in a 
761                 // file dir.txt when the game was opened.
762                 ifstream path("dir.txt");
763                 path >> dir;
764                 path.close();
765                 string def = "/src/defines.txt";
766
767                 while(1)
768                 {
769                         string file = dir + def;
770                         char *p = const_cast<char*> (file.c_str() );
771                         ifstream myfile (p);
772                         if(myfile.is_open())
773                         {
774                                 while(myfile.good() )
775                                 {
776                                         getline (myfile, line);
777                                         int loc = line.find(str);
778                                         if(loc != -1)
779                                         {
780                                                 loc += str.length();
781                                                 val = atoi(line.substr(loc).c_str());
782                                                 return val;
783                                         }
784                                 }
785                                 myfile.close();
786
787                                 // Comversion has fatally failed
788                                 cout << str << " was not defined." << endl;
789                                 return -2;
790                         }
791                         else
792                         {
793                                 if(def[5] == 'd')
794                                 {
795                                         def.replace(5, 1, "D");
796                                 }
797                                 else
798                                 {
799                                         // Conversion has fatally failed
800                                         cout << "No Defines.txt or defines.txt found" << endl;
801                                         return -2;
802                                         break;
803                                 }
804                         }
805                 }
806         }
807         else
808         {
809                 // String was an int, no conversion necessary
810                 return val;
811         }
812
813         // Conversion failed
814         return -1;
815 }
816
817 //**********************************************
818 void Menu::quit_cb()
819 {
820
821   close();
822
823 }
824
825 //**********************************************
826 void Menu::closeEvent( QCloseEvent *e )
827 {
828
829   if(game->isOpen){
830     close_game();
831     if(game->isOpen){
832       e->ignore();
833       return;
834     }
835   }
836   e->accept();
837
838 }
839
840 //**********************************************
841 void Menu::close_game()
842 {
843   int i;
844
845   //close all open windows (they will ask to save if something was changed)
846   for(i=0;i<MAXWIN;i++){
847     if(winlist[i].type!=-1){
848       switch(winlist[i].type){
849       case LOGIC:
850         winlist[i].w.l->close();
851         break;
852       case PICTURE:
853         winlist[i].w.p->close();
854         break;
855       case VIEW:
856         winlist[i].w.v->close();
857         break;
858       case OBJECT:
859         winlist[i].w.o->close();
860         break;
861       case WORDS:
862         winlist[i].w.w->close();
863         break;
864       case TEXT:
865         winlist[i].w.t->close();
866         break;
867       }
868     }
869   }
870
871   int n;
872   for(i=0;i<MAXWIN;i++){
873     n=winlist[i].type;
874     if(n>=LOGIC&&n<=TEXT)
875       return ;  //some window was not closed
876   }
877
878
879   //ok to close
880   for(i=0;i<MAXWIN;i++){
881     if(winlist[i].type==RESOURCES){
882       winlist[i].w.r->close();
883     }
884   }
885
886   if(window_list)
887     window_list->hide();
888   disable();
889   game->isOpen=false;
890
891 }
892
893 //**********************************************
894 void Menu::run_game()
895 {
896
897 #ifdef _WIN32
898   int i;
899   _chdir(game->dir.c_str());
900 #else
901   int i=fork();
902   if(i==0){
903     chdir(game->dir.c_str());
904 #endif
905 #define MAX_ARG 32
906     char *argv[MAX_ARG];
907     strcpy(tmp,game->command.c_str());
908     argv[0]=strtok(tmp," ");
909     for(i=1;i<MAX_ARG;i++){
910       argv[i]=strtok(NULL," ");
911       if(argv[i]==NULL)break;
912     }
913     if(argv[MAX_ARG-1]!=NULL)argv[MAX_ARG-1]=NULL;
914 #ifdef _WIN32
915         STARTUPINFOA si;
916         PROCESS_INFORMATION pi;
917
918         ZeroMemory(&si,sizeof(si));
919         si.cb = sizeof(si);
920         ZeroMemory(&pi,sizeof(pi));
921
922     if(!CreateProcessA(NULL,tmp,NULL,NULL,false,0,NULL,NULL,&si,&pi)) {
923 #else
924     if(execvp(argv[0],argv)){
925 #endif
926       printf("Couldn't execute command %s !\n",game->command.c_str());
927     }
928 #ifdef _WIN32
929         CloseHandle(pi.hProcess);
930         CloseHandle(pi.hThread);
931 #else
932     exit(0);
933   }
934 #endif
935
936 }
937 //**********************************************
938 int Menu::save_all()
939 {
940
941   int ret,err=0;
942   for(int i=0;i<MAXWIN;i++){
943     switch(winlist[i].type){
944     case LOGIC:
945       ret=winlist[i].w.l->compile_logic();
946       if(ret)err=1;
947       break;
948     case PICTURE:
949       winlist[i].w.p->save_to_game();
950       break;
951     case VIEW:
952       winlist[i].w.v->save_to_game();
953       break;
954     }
955   }
956   return err;
957
958 }
959 //**********************************************
960 void Menu::save_and_run()
961 {
962   if(!save_all())
963     run_game();
964
965 }
966 //**********************************************
967 void Menu::window_list_cb()
968 {
969
970   if(window_list==NULL)window_list=new WindowList();
971   window_list->draw();
972
973 }
974 //**********************************************
975 void Menu::settings()
976 {
977
978   if(options==NULL)options = new Options();
979   options->show();
980
981 }
982
983 //**********************************************
984 void Menu::from_template()
985 {
986
987   menu->templ=true;
988   if(dir_new==NULL)dir_new =new Dir(0,0,true);
989   dir_new->open();
990
991 }
992
993 //**********************************************
994 void Menu::blank()
995 {
996
997   menu->templ=false;
998   if(dir_new==NULL)dir_new =new Dir(0,0,true);
999   dir_new->open();
1000
1001 }
1002
1003 //**********************************************
1004 void Menu::new_resource_window()
1005 {
1006
1007   int i,n;
1008   int sel[4]={0,0,0,0};
1009
1010   for(i=0;i<MAXWIN;i++){
1011     if(winlist[i].type==RESOURCES){
1012       sel[winlist[i].w.r->selected]=1;
1013     }
1014   }
1015
1016   if((n=get_win())==-1)return;
1017   ResourcesWin *resources_win = new ResourcesWin(NULL,"Resources",n);
1018   winlist[n].type=RESOURCES;
1019   winlist[n].w.r=resources_win;
1020   int res=game->res_default;
1021   for(i=0;i<4;i++){
1022     if(sel[i]==0){
1023       res=i;
1024       break;
1025     }
1026   }
1027   resources_win->select_resource_type(res);
1028   resources_win->show();
1029   num_res++;
1030   if(num_res>1)disable_resources();
1031
1032 }
1033
1034 //**********************************************
1035 void Menu::add_resource()
1036 {
1037
1038   resources_win->add_resource();
1039
1040 }
1041
1042 //**********************************************
1043 void Menu::extract_resource()
1044 {
1045
1046   resources_win->extract_resource();
1047
1048 }
1049
1050 //**********************************************
1051 void Menu::delete_resource()
1052 {
1053
1054   resources_win->delete_resource();
1055
1056 }
1057
1058 //**********************************************
1059 void Menu::renumber_resource()
1060 {
1061
1062   resources_win->renumber_resource();
1063
1064 }
1065
1066 //**********************************************
1067 void Menu::rebuild_vol()
1068 {
1069
1070   switch( QMessageBox::warning( this, "Rebuild VOL files", "Are you sure ?",
1071                                       "Yes", "No",
1072                                       0,      // Enter == button 0
1073                                       1 ) ) { // Escape == button 1
1074     case 0:
1075       game->RebuildVOLfiles();
1076       break;
1077     case 1:
1078       break;
1079     }
1080 }
1081
1082 //**********************************************
1083 void Menu::recompile_all()
1084 {
1085
1086   switch( QMessageBox::warning( this, "Recompile all", "Do you really want to recompile all logics ?",
1087                                       "Yes", "No",
1088                                       0,      // Enter == button 0
1089                                       1 ) ) { // Escape == button 1
1090     case 0:
1091       game->RecompileAll();
1092       break;
1093     case 1:
1094       break;
1095     }
1096 }
1097
1098 //**********************************************
1099 void Menu::view_editor()
1100 {
1101   int n;
1102   if((n=get_win())==-1)return;
1103   winlist[n].w.v = new ViewEdit(NULL,NULL,n,resources_win);
1104   winlist[n].type=VIEW;
1105   winlist[n].w.v->open();
1106
1107 }
1108
1109 //**********************************************
1110 void Menu::logic_editor()
1111 {
1112
1113   int n;
1114   if((n=get_win())==-1)return;
1115   winlist[n].w.l = new LogEdit(NULL,NULL,n,resources_win);
1116   winlist[n].type=LOGIC;
1117   winlist[n].w.l->open();
1118
1119 }
1120
1121 //**********************************************
1122 void Menu::text_editor()
1123 {
1124
1125   int n;
1126   if((n=get_win())==-1)return;
1127   winlist[n].w.t = new TextEdit(NULL,NULL,n);
1128   winlist[n].type=TEXT;
1129   winlist[n].w.t->new_text();
1130
1131 }
1132
1133 //**********************************************
1134 void Menu::object_editor()
1135 {
1136
1137   int n;
1138   if((n=get_win())==-1)return;
1139   winlist[n].w.o = new ObjEdit(NULL,NULL,n);
1140   winlist[n].type=OBJECT;
1141   winlist[n].w.o->open();
1142
1143 }
1144
1145 //**********************************************
1146 void Menu::words_editor()
1147 {
1148
1149   int n;
1150   if((n=get_win())==-1)return;
1151   winlist[n].w.w = new WordsEdit(NULL,NULL,n,resources_win);
1152   winlist[n].type=WORDS;
1153   winlist[n].w.w->open();
1154
1155 }
1156
1157 //**********************************************
1158 void Menu::picture_editor()
1159 {
1160
1161   int n;
1162   if((n=get_win())==-1)return;
1163   winlist[n].w.p = new PicEdit(NULL,NULL,n,resources_win);
1164   winlist[n].type=PICTURE;
1165   winlist[n].w.p->open();
1166
1167 }
1168
1169 //**********************************************
1170 void Menu::sound_player()
1171 {
1172   extern void play_sound (char *);
1173
1174   QFileDialog *f = new QFileDialog(0,"Play sound",true);
1175   const char *filters[] = {"sound*.*","All files (*)",NULL};
1176
1177   f->setFilters(filters);
1178   f->setCaption("Play sound");
1179   f->setMode(QFileDialog::ExistingFile);
1180   f->setDir(game->srcdir.c_str());
1181   if ( f->exec() == QDialog::Accepted ) {
1182     if ( !f->selectedFile().isEmpty() ){
1183       play_sound((char *)f->selectedFile().latin1());
1184     }
1185   }
1186
1187 }
1188
1189 //**********************************************
1190 void Menu::help_contents()
1191   //from QT examples (qbrowser)
1192 {
1193   sprintf(tmp,"%s/index.html",game->helpdir.c_str());
1194   if(helpwindow==NULL){
1195     int n;
1196     if((n=get_win())==-1)return;
1197     helpwindow = new HelpWindow(tmp,".");
1198     winlist[n].type=HELPWIN;
1199     winlist[n].w.h=helpwindow;
1200   }
1201   else helpwindow->setSource(tmp);
1202   helpwindow->show();
1203 }
1204
1205 //**********************************************
1206 bool Menu::help_topic( const QString& topic )
1207 {
1208   sprintf(tmp,"%s/%s.html",game->helpdir.c_str(),
1209     QString(topic).replace(".", "_").latin1());
1210
1211   if ( QFile( tmp ).exists())
1212   {
1213     if(helpwindow1==NULL){
1214       int n;
1215       if((n=get_win())==-1) return true;
1216       helpwindow1 = new HelpWindow(tmp,".");
1217       winlist[n].type=HELPWIN;
1218       winlist[n].w.h=helpwindow1;
1219     }
1220     else helpwindow1->setSource(tmp);
1221     helpwindow1->show();
1222     helpwindow1->raise();
1223     return true;
1224   }
1225   else
1226     return false;
1227 }
1228
1229 //**********************************************
1230 void Menu::help_index()
1231 {
1232   sprintf(tmp,"%s/indexabc.html",game->helpdir.c_str());
1233   if(helpwindow1==NULL){
1234     int n;
1235     if((n=get_win())==-1)return;
1236     helpwindow1 = new HelpWindow(tmp,".");
1237     winlist[n].type=HELPWIN;
1238     winlist[n].w.h=helpwindow1;
1239   }
1240   else helpwindow1->setSource(tmp);
1241   helpwindow1->show();
1242 }
1243
1244 //**********************************************
1245 void Menu::about_it()
1246 {
1247   if(about==NULL)about=new About();
1248   about->show();
1249 }
1250
1251 //**********************************************
1252 void Menu::about_qt()
1253 {
1254
1255   QMessageBox::aboutQt( this, "AGI studio" );
1256
1257 }
1258
1259 //**********************************************
1260 void Menu::errmes(const char *caption, const char *fmt, ...)
1261 {
1262   char tmp[512];
1263   va_list argp;
1264
1265   va_start(argp, fmt);
1266   vsprintf(tmp,fmt,argp);
1267   va_end(argp);
1268
1269   err->setText(QString(tmp));
1270   err->setCaption(caption);
1271   err->adjustSize();
1272   err->show();
1273
1274
1275 }
1276
1277 //*************************************************
1278 void Menu::errmes(const char *fmt, ...)
1279 {
1280   char tmp[512];
1281   va_list argp;
1282
1283   va_start(argp, fmt);
1284   vsprintf(tmp,fmt,argp);
1285   va_end(argp);
1286
1287   err->setText(QString(tmp));
1288   err->setCaption("AGI studio");
1289   err->adjustSize();
1290   err->show();
1291
1292 }
1293
1294
1295 //**********************************************
1296 void Menu::warnmes(const char *fmt, ...)
1297 {
1298   char tmp[512];
1299   va_list argp;
1300
1301   va_start(argp, fmt);
1302   vsprintf(tmp,fmt,argp);
1303   va_end(argp);
1304
1305   warn->setText(QString(tmp));
1306   warn->setCaption("AGI studio");
1307   warn->adjustSize();
1308   warn->show();
1309
1310 }
1311
1312
1313 //**********************************************
1314 #ifdef IMGEXT
1315 void Menu::load_imgext()
1316   //QT image extensions - to handle more image formats
1317   //currently it is only jpg and it doesn't work well anyway
1318 {
1319
1320   qInitImageIO() ;
1321   imgext = true;
1322
1323 }
1324 #endif
1325
1326 //**********************************************
1327
1328 About::About(QWidget *parent, const char *name )
1329     : QWidget( parent, name )
1330 {
1331   setCaption("About QT AGI Studio");
1332
1333   QBoxLayout *all = new QVBoxLayout(this,2);
1334
1335   QLabel *alogo = new QLabel(this);
1336   alogo->setPixmap(QPixmap(logo));
1337   alogo->setAlignment( Qt::AlignHCenter );
1338   alogo->setSizePolicy( QSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum ));
1339   all->addWidget(alogo);
1340
1341   QTextEdit* about = new QTextEdit(this);
1342   about->setTextFormat(Qt::RichText);
1343   about->setReadOnly(true);
1344   about->setText(
1345     "<center><b>QT AGI studio v. 1.2.4</b><br>"
1346     "http://agistudio.sourceforge.net/<br>"
1347     "<br>"
1348     "<b>Authors:</b><br>"
1349     "Helen Zommer (helen@cc.huji.ac.il)<br>"
1350     "Jarno Elonen (elonen@iki.fi)<br>"
1351     "<br>"
1352     "<b>and also:</b><br>"
1353     "Peter Kelly (pmk@post.com)<br>"
1354     "Lance Ewing (lance.e@ihug.co.nz)<br>"
1355     "Claudio Matsuoka (claudio@helllabs.org)<br>"
1356     "<br>"
1357     "<b>Windows port by:</b><br>"
1358     "Nat Budin (natb@brandeis.edu)"
1359     "<br><br></center>"
1360     "This program is free software; you can "
1361     "redistribute it and/or modify it under "
1362     "the terms of the GNU General Public "
1363     "License, version 2 or later, as published "
1364     "by the Free Software Foundation.");
1365   all->addWidget(about);
1366
1367   QPushButton *ok = new QPushButton(this);
1368   ok->setText("OK");
1369   ok->setMaximumSize(80,40);
1370   connect(ok, SIGNAL(clicked()), SLOT(hide()));
1371   all->addWidget(ok);
1372
1373
1374 }
1375
1376 //**********************************************
1377
1378 WindowList::WindowList(QWidget *parent, const char *name )
1379     : QWidget( parent, name )
1380 {
1381
1382   setCaption("Window list");
1383   QBoxLayout *l =  new QVBoxLayout(this,10);
1384
1385   win = new QListBox(this);
1386   win->setColumnMode (1);
1387   win->setMinimumSize(100,200);
1388   connect( win, SIGNAL(selected(int)), SLOT(select_cb(int)) );
1389   l->add(win);
1390
1391   QBoxLayout *l1 = new QHBoxLayout(l,10);
1392
1393   QPushButton *select = new QPushButton(this);
1394   select->setText("Select");
1395   connect( select, SIGNAL(clicked()), SLOT(select_ok()) );
1396   l1->addWidget(select);
1397   QPushButton *del = new QPushButton(this);
1398   del->setText("Delete");
1399   connect( del, SIGNAL(clicked()), SLOT(del_cb()) );
1400   l1->addWidget(del);
1401   QPushButton *close = new QPushButton(this);
1402   close->setText("Close list");
1403   connect( close, SIGNAL(clicked()), SLOT(hide()) );
1404   l1->addWidget(close);
1405
1406   adjustSize();
1407
1408 }
1409
1410 //**********************************************
1411
1412 void WindowList::draw()
1413 {
1414   QString caption;
1415
1416   win->clear();
1417   for(int i=0;i<MAXWIN;i++){
1418     if(winlist[i].type==-1)continue;
1419     //    printf("i=%d type=%d\n",i,winlist[i].type);
1420     switch(winlist[i].type){
1421     case LOGIC:
1422       caption = QString("Logic editor: ").append(winlist[i].w.l->caption());
1423       if(winlist[i].w.l->isMinimized())caption.insert(0,"(.) ");
1424       break;
1425     case PICTURE:
1426       caption = winlist[i].w.p->caption();
1427       if(winlist[i].w.p->isMinimized())caption.insert(0,"(.) ");
1428       break;
1429     case VIEW:
1430       caption = winlist[i].w.v->caption();
1431       if(winlist[i].w.v->isMinimized())caption.insert(0,"(.) ");
1432       break;
1433     case OBJECT:
1434       caption = winlist[i].w.o->caption();
1435       if(winlist[i].w.o->isMinimized())caption.insert(0,"(.) ");
1436       break;
1437     case WORDS:
1438       caption = winlist[i].w.w->caption();
1439       if(winlist[i].w.w->isMinimized())caption.insert(0,"(.) ");
1440       break;
1441     case TEXT:
1442       caption = winlist[i].w.t->caption();
1443       if(winlist[i].w.t->isMinimized())caption.insert(0,"(.) ");
1444       break;
1445     case RESOURCES:
1446       caption = winlist[i].w.r->caption();
1447       if(winlist[i].w.r->isMinimized())caption.insert(0,"(.) ");
1448       break;
1449     case HELPWIN:
1450       caption = QString("Help");
1451       if(winlist[i].w.h->isMinimized())caption.insert(0,"(.) ");
1452       else if(!winlist[i].w.h->isVisible())caption.insert(0,"(~) ");
1453       break;
1454     case PREVIEW:
1455       caption = winlist[i].w.pr->caption();
1456       if(winlist[i].w.pr->isMinimized())caption.insert(0,"(.) ");
1457       break;
1458     }
1459     win->insertItem(caption);
1460   }
1461
1462   show();
1463 }
1464
1465 //**********************************************
1466
1467 void WindowList::select_cb(int sel)
1468 {
1469   QString caption;
1470
1471   int n=0;
1472   for(int i=0;i<MAXWIN;i++){
1473     if(winlist[i].type==-1)continue;
1474     if(n==sel){
1475       switch(winlist[i].type){
1476       case LOGIC:
1477         if(winlist[i].w.l->isMinimized()){
1478           winlist[i].w.l->showNormal();
1479           caption = QString("Logic editor: ").append(winlist[i].w.l->caption());
1480           win->changeItem(caption,sel);
1481         }
1482         winlist[i].w.l->setActiveWindow();
1483         winlist[i].w.l->raise();
1484         break;
1485       case PICTURE:
1486         if(winlist[i].w.p->isMinimized()){
1487           winlist[i].w.p->showNormal();
1488            caption = winlist[i].w.p->caption();
1489            win->changeItem(caption,sel);
1490         }
1491         winlist[i].w.p->setActiveWindow();
1492         winlist[i].w.p->raise();
1493         break;
1494       case VIEW:
1495         if(winlist[i].w.v->isMinimized()){
1496           winlist[i].w.v->showNormal();
1497           caption = winlist[i].w.v->caption();
1498           win->changeItem(caption,sel);
1499         }
1500         winlist[i].w.v->setActiveWindow();
1501         winlist[i].w.v->raise();
1502         break;
1503       case TEXT:
1504         if(winlist[i].w.t->isMinimized()){
1505           winlist[i].w.t->showNormal();
1506           caption = winlist[i].w.t->caption();
1507           win->changeItem(caption,sel);
1508         }
1509         winlist[i].w.t->setActiveWindow();
1510         winlist[i].w.t->raise();
1511         break;
1512       case WORDS:
1513         if(winlist[i].w.w->isMinimized()){
1514           winlist[i].w.w->showNormal();
1515           caption = winlist[i].w.w->caption();
1516           win->changeItem(caption,sel);
1517         }
1518         winlist[i].w.w->setActiveWindow();
1519         winlist[i].w.w->raise();
1520         break;
1521       case OBJECT:
1522         if(winlist[i].w.o->isMinimized()){
1523           winlist[i].w.o->showNormal();
1524           caption = winlist[i].w.o->caption();
1525           win->changeItem(caption,sel);
1526         }
1527         winlist[i].w.o->setActiveWindow();
1528         winlist[i].w.o->raise();
1529         break;
1530       case RESOURCES:
1531         if(winlist[i].w.r->isMinimized()){
1532           winlist[i].w.r->showNormal();
1533           caption = winlist[i].w.r->caption();
1534           win->changeItem(caption,sel);
1535         }
1536         winlist[i].w.r->setActiveWindow();
1537         winlist[i].w.r->raise();
1538         break;
1539       case HELPWIN:
1540         if(winlist[i].w.h->isMinimized()){
1541           winlist[i].w.h->showNormal();
1542           caption = QString("Help");
1543           win->changeItem(caption,sel);
1544         }
1545         else if(!winlist[i].w.h->isVisible()){
1546           winlist[i].w.h->show();
1547           caption = winlist[i].w.h->caption();
1548           win->changeItem(caption,sel);
1549         }
1550         winlist[i].w.h->setActiveWindow();
1551         winlist[i].w.h->raise();
1552         break;
1553       case PREVIEW:
1554         if(winlist[i].w.pr->isMinimized()){
1555           winlist[i].w.pr->showNormal();
1556           caption = winlist[i].w.pr->caption();
1557           win->changeItem(caption,sel);
1558         }
1559         winlist[i].w.pr->setActiveWindow();
1560         winlist[i].w.pr->raise();
1561         break;
1562       }
1563       break;
1564     }
1565     n++;
1566   }
1567
1568 }
1569
1570 //**********************************************
1571
1572 void WindowList::select_ok()
1573 {
1574   if(win->currentItem()!=-1)
1575     select_cb(win->currentItem());
1576
1577 }
1578
1579 //**********************************************
1580
1581 void WindowList::del_cb()
1582 {
1583
1584   int sel = win->currentItem();
1585   if(sel==-1)return;
1586
1587   int n=0;
1588   for(int i=0;i<MAXWIN;i++){
1589     if(winlist[i].type==-1)continue;
1590     if(n==sel){
1591       switch(winlist[i].type){
1592       case LOGIC:
1593         winlist[i].w.l->close();
1594         break;
1595       case VIEW:
1596         winlist[i].w.v->close();
1597         break;
1598       case PICTURE:
1599         winlist[i].w.p->close();
1600         break;
1601       case TEXT:
1602         winlist[i].w.t->close();
1603         break;
1604       case WORDS:
1605         winlist[i].w.w->close();
1606         break;
1607       case OBJECT:
1608         winlist[i].w.o->close();
1609         break;
1610       case RESOURCES:
1611         winlist[i].w.r->close();
1612         break;
1613       case HELPWIN:
1614         winlist[i].w.h->hide();
1615         break;
1616       case PREVIEW:
1617         winlist[i].w.pr->close();
1618         break;
1619       }
1620       break;
1621     }
1622     n++;
1623   }
1624   draw();
1625
1626 }