1 //------------------------------------------------------------------------
2 // FILES : Unix/FLTK File boxes
3 //------------------------------------------------------------------------
4 //
5 // GL-Friendly Node Builder (C) 2000-2005 Andrew Apted
6 //
7 // Based on 'BSP 2.3' by Colin Reed, Lee Killough and others.
8 //
9 // This program is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU General Public License
11 // as published by the Free Software Foundation; either version 2
12 // of the License, or (at your option) any later version.
13 //
14 // This program is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 // GNU General Public License for more details.
18 //
19 //------------------------------------------------------------------------
20
21 // this includes everything we need
22 #include "local.h"
23
24
25 #define MY_GWA_COLOR \
26 fl_color_cube((FL_NUM_RED-1)*3/4, 0, 0)
27
28
file_box_inout_CB(Fl_Widget * w,void * data)29 static void file_box_inout_CB(Fl_Widget *w, void *data)
30 {
31 guix_win->files->WriteInfo();
32
33 // update output box in GWA mode
34 guix_win->files->InFileChanged();
35 }
36
37
file_in_browse_CB(Fl_Widget * w,void * data)38 static void file_in_browse_CB(Fl_Widget *w, void *data)
39 {
40 const char *name = fl_file_chooser("Select an input file",
41 "*.wad", guix_win->files->in_file->value());
42
43 // cancelled ?
44 if (! name)
45 return;
46
47 guix_win->files->in_file->value(name);
48 guix_win->files->in_file->redraw();
49 guix_win->files->WriteInfo();
50
51 guix_win->files->InFileChanged();
52 }
53
file_out_browse_CB(Fl_Widget * w,void * data)54 static void file_out_browse_CB(Fl_Widget *w, void *data)
55 {
56 const char *name = fl_file_chooser("Select an output file",
57 "*.wad", guix_win->files->out_file->value());
58
59 if (! name)
60 return;
61
62 guix_win->files->out_file->value(name);
63 guix_win->files->out_file->redraw();
64 guix_win->files->WriteInfo();
65 }
66
file_out_guess_CB(Fl_Widget * w,void * data)67 static void file_out_guess_CB(Fl_Widget *w, void *data)
68 {
69 guix_win->files->out_file->value(
70 HelperGuessOutput(guix_win->files->in_file->value()));
71
72 guix_win->files->out_file->redraw();
73 guix_win->files->WriteInfo();
74 }
75
76
77 //
78 // FileBox Constructor
79 //
Guix_FileBox(int x,int y,int w,int h)80 Guix_FileBox::Guix_FileBox(int x, int y, int w, int h) :
81 Fl_Group(x, y, w, h, "Files")
82 {
83 // cancel the automatic 'begin' in Fl_Group constructor
84 end();
85
86 box(FL_THIN_UP_BOX);
87
88 labelfont(FL_HELVETICA | FL_BOLD);
89 labeltype(FL_NORMAL_LABEL);
90 align(FL_ALIGN_INSIDE | FL_ALIGN_LEFT | FL_ALIGN_TOP);
91
92 // create the file group -- serves as the resizable
93 int len = w - 62 - 178;
94
95 file_group = new Fl_Group(x+62, y, len, h);
96 file_group->end();
97 add(file_group);
98
99 resizable(file_group);
100
101 // create input and output file widgets
102
103 int CX = x;
104 int CY = y+18;
105
106 in_label = new Fl_Box(CX, CY, 62, 26, "Input ");
107 in_label->align(FL_ALIGN_INSIDE | FL_ALIGN_RIGHT);
108 add(in_label);
109
110 CY += 30;
111
112 out_label = new Fl_Box(CX, CY, 62, 26, "Output ");
113 out_label->align(FL_ALIGN_INSIDE | FL_ALIGN_RIGHT);
114 add(out_label);
115
116 CX = x+62;
117 CY = y+18;
118
119 in_file = new Fl_Input(CX, CY, len, 26);
120 in_file->callback((Fl_Callback *) file_box_inout_CB);
121 in_file->when(FL_WHEN_CHANGED);
122 file_group->add(in_file);
123
124 CY += 30;
125
126 out_file = new Fl_Input(CX, CY, len, 26);
127 out_file->callback((Fl_Callback *) file_box_inout_CB);
128 out_file->when(FL_WHEN_CHANGED);
129 file_group->add(out_file);
130
131 // this widget is normally hidden. It occupies the same space as
132 // the out_file widget. When GWA mode is selected, the normal
133 // output box is hidden and this one is shown instead.
134
135 gwa_filename = GlbspStrDup("");
136 out_gwa_file = new Fl_Output(CX, CY, len, 26);
137 out_gwa_file->textcolor(MY_GWA_COLOR);
138 out_gwa_file->selection_color(FL_CYAN);
139 out_gwa_file->hide();
140 file_group->add(out_gwa_file);
141
142 CX = x+70+len;
143 CY = y+18;
144
145 in_browse = new Fl_Button(CX, CY, 80, 26, "Browse");
146 in_browse->align(FL_ALIGN_INSIDE);
147 in_browse->callback((Fl_Callback *) file_in_browse_CB, in_file);
148 add(in_browse);
149
150 CY += 30;
151
152 out_browse = new Fl_Button(CX, CY, 80, 26, "Browse");
153 out_browse->align(FL_ALIGN_INSIDE);
154 out_browse->callback((Fl_Callback *) file_out_browse_CB, out_file);
155 add(out_browse);
156
157 CX += 86;
158
159 out_guess = new Fl_Button(CX, CY, 70, 26, "Guess");
160 out_guess->align(FL_ALIGN_INSIDE);
161 out_guess->callback((Fl_Callback *) file_out_guess_CB, out_file);
162 add(out_guess);
163
164 ReadInfo();
165 }
166
167 //
168 // FileBox Destructor
169 //
~Guix_FileBox()170 Guix_FileBox::~Guix_FileBox()
171 {
172 WriteInfo();
173
174 GlbspFree(gwa_filename);
175 }
176
177
ReadInfo()178 void Guix_FileBox::ReadInfo()
179 {
180 in_file->value(guix_info.input_file);
181 in_file->redraw();
182
183 out_file->value(guix_info.output_file);
184 out_file->redraw();
185
186 InFileChanged();
187 GWA_Changed();
188 }
189
190
WriteInfo()191 void Guix_FileBox::WriteInfo()
192 {
193 GlbspFree(guix_info.input_file);
194 guix_info.input_file = NULL;
195
196 GlbspFree(guix_info.output_file);
197 guix_info.output_file = NULL;
198
199 // treat "" the same as a NULL string ptr
200 if (in_file->value() && strlen(in_file->value()) > 0)
201 guix_info.input_file = GlbspStrDup(in_file->value());
202
203 if (out_file->value() && strlen(out_file->value()) > 0)
204 guix_info.output_file = GlbspStrDup(out_file->value());
205 }
206
207
GWA_Changed()208 void Guix_FileBox::GWA_Changed()
209 {
210 if (guix_info.gwa_mode)
211 {
212 out_file->hide();
213 out_gwa_file->show();
214 out_browse->deactivate();
215 out_guess->deactivate();
216 }
217 else
218 {
219 out_gwa_file->hide();
220 out_file->show();
221 out_browse->activate();
222 out_guess->activate();
223 }
224 }
225
226
InFileChanged(void)227 void Guix_FileBox::InFileChanged(void)
228 {
229 GlbspFree(gwa_filename);
230
231 gwa_filename = GlbspStrDup(
232 HelperReplaceExt(guix_info.input_file, "gwa"));
233
234 out_gwa_file->value(gwa_filename);
235 out_gwa_file->redraw();
236 }
237
238
LockOut(boolean_g lock_it)239 void Guix_FileBox::LockOut(boolean_g lock_it)
240 {
241 if (lock_it)
242 {
243 in_file->set_output();
244 out_file->set_output();
245 out_gwa_file->set_output();
246
247 in_browse->set_output();
248 out_browse->set_output();
249 out_guess->set_output();
250 }
251 else
252 {
253 in_file->clear_output();
254 out_file->clear_output();
255 out_gwa_file->clear_output();
256
257 in_browse->clear_output();
258 out_browse->clear_output();
259 out_guess->clear_output();
260 }
261 }
262
263
264 //------------------------------------------------------------------------
265
266
267 //
268 // FactorBox Constructor
269 //
Guix_FactorBox(int x,int y,int w,int h)270 Guix_FactorBox::Guix_FactorBox(int x, int y, int w, int h) :
271 Fl_Group(x, y, w, h)
272 {
273 // cancel the automatic 'begin' in Fl_Group constructor
274 end();
275
276 box(FL_THIN_UP_BOX);
277 resizable(0); // no resizing the kiddies, please
278
279 // create factor input box
280
281 factor = new Fl_Counter(x+60, y+8, 100, 24, "Factor ");
282 factor->align(FL_ALIGN_LEFT);
283 factor->type(FL_SIMPLE_COUNTER);
284 factor->range(1, 32);
285 factor->step(1, 1);
286 add(factor);
287
288 ReadInfo();
289 }
290
291 //
292 // FactorBox Destructor
293 //
~Guix_FactorBox()294 Guix_FactorBox::~Guix_FactorBox()
295 {
296 WriteInfo();
297 }
298
299
ReadInfo()300 void Guix_FactorBox::ReadInfo()
301 {
302 factor->value(guix_info.factor);
303 }
304
305
WriteInfo()306 void Guix_FactorBox::WriteInfo()
307 {
308 guix_info.factor = (int) factor->value();
309 }
310
311
LockOut(boolean_g lock_it)312 void Guix_FactorBox::LockOut(boolean_g lock_it)
313 {
314 if (lock_it)
315 factor->set_output();
316 else
317 factor->clear_output();
318 }
319
320
321 //------------------------------------------------------------------------
322
BuildValidateOptions(void)323 static boolean_g BuildValidateOptions(void)
324 {
325 // This routine checks for all manners of nasty input/output file
326 // problems. Belt up, it's a bumpy ride !!
327
328 int choice;
329 char buffer[1024];
330
331 // a) Empty or invalid filenames
332
333 if (!guix_info.input_file || guix_info.input_file[0] == 0)
334 {
335 DialogShowAndGetChoice(ALERT_TXT, skull_image,
336 "Please choose an Input filename.");
337 return FALSE;
338 }
339
340 if (!guix_info.output_file || guix_info.output_file[0] == 0)
341 {
342 DialogShowAndGetChoice(ALERT_TXT, skull_image,
343 "Please choose an Output filename.");
344 return FALSE;
345 }
346
347 if (! HelperFilenameValid(guix_info.input_file))
348 {
349 sprintf(buffer,
350 "Invalid Input filename:\n"
351 "\n"
352 " %s\n"
353 "\n"
354 "Please check the filename and try again.",
355 guix_info.input_file);
356
357 DialogShowAndGetChoice(ALERT_TXT, skull_image, buffer);
358 return FALSE;
359 }
360
361 if (! HelperFilenameValid(guix_info.output_file))
362 {
363 sprintf(buffer,
364 "Invalid Output filename:\n"
365 "\n"
366 " %s\n"
367 "\n"
368 "Please check the filename and try again.",
369 guix_info.output_file);
370
371 DialogShowAndGetChoice(ALERT_TXT, skull_image, buffer);
372 return FALSE;
373 }
374
375
376 // b) Missing extensions
377
378 if (! HelperHasExt(guix_info.input_file))
379 {
380 if (guix_prefs.lack_ext_warn)
381 {
382 sprintf(buffer,
383 "The Input file you selected has no extension.\n"
384 "\n"
385 "Do you want to add \".WAD\" and continue ?");
386
387 choice = DialogShowAndGetChoice(ALERT_TXT, skull_image,
388 buffer, "OK", "Cancel");
389
390 if (choice != 0)
391 return FALSE;
392 }
393
394 char *new_input = HelperReplaceExt(guix_info.input_file, "wad");
395
396 GlbspFree(guix_info.input_file);
397 guix_info.input_file = GlbspStrDup(new_input);
398
399 guix_win->files->ReadInfo();
400 }
401
402 if (! HelperHasExt(guix_info.output_file))
403 {
404 if (guix_prefs.lack_ext_warn)
405 {
406 sprintf(buffer,
407 "The Output file you selected has no extension.\n"
408 "\n"
409 "Do you want to add \".%s\" and continue ?",
410 guix_info.gwa_mode ? "GWA" : "WAD");
411
412 choice = DialogShowAndGetChoice(ALERT_TXT, skull_image,
413 buffer, "OK", "Cancel");
414
415 if (choice != 0)
416 return FALSE;
417 }
418
419 char *new_output = HelperReplaceExt(guix_info.output_file,
420 guix_info.gwa_mode ? "gwa" : "wad");
421
422 GlbspFree(guix_info.output_file);
423 guix_info.output_file = GlbspStrDup(new_output);
424
425 guix_win->files->ReadInfo();
426 }
427
428
429 // c) No such input file
430
431 if (! HelperFileExists(guix_info.input_file))
432 {
433 sprintf(buffer,
434 "Could not open the Input file:\n"
435 "\n"
436 " %s\n"
437 "\n"
438 "Please check the filename and try again.",
439 guix_info.input_file);
440
441 DialogShowAndGetChoice(ALERT_TXT, skull_image, buffer);
442 return FALSE;
443 }
444
445
446 // d) Use of the ".gwa" extension
447
448 if (HelperCheckExt(guix_info.input_file, "gwa"))
449 {
450 DialogShowAndGetChoice(ALERT_TXT, skull_image,
451 "The Input file you selected has the GWA extension, "
452 "but GWA files do not contain any level data, so "
453 "there wouldn't be anything to build nodes for.\n"
454 "\n"
455 "Please choose another Input file.");
456 return FALSE;
457 }
458
459 if (HelperCheckExt(guix_info.output_file, "gwa") &&
460 ! guix_info.gwa_mode)
461 {
462 choice = DialogShowAndGetChoice(ALERT_TXT, skull_image,
463 "The Output file you selected has the GWA extension, "
464 "but the GWA Mode option is not enabled.\n"
465 "\n"
466 "Do you want to enable GWA Mode and continue ?",
467 "OK", "Cancel");
468
469 if (choice != 0)
470 return FALSE;
471
472 guix_info.gwa_mode = TRUE;
473 guix_info.no_normal = FALSE;
474 guix_info.force_normal = FALSE;
475
476 guix_win->build_mode->ReadInfo();
477 guix_win->files->GWA_Changed();
478 guix_win->misc_opts->GWA_Changed();
479 }
480
481
482 // e) Input == Output
483 // f) Output file already exists
484
485 guix_info.load_all = FALSE;
486
487 if (HelperCaseCmp(guix_info.input_file, guix_info.output_file) == 0)
488 {
489 if (guix_prefs.same_file_warn)
490 {
491 sprintf(buffer,
492 "Warning: Input and Output files are the same.\n"
493 "\n"
494 "This will use a lot more memory than normal, since the "
495 "whole input file must be loaded in. On a low memory "
496 "machine, the node building may fail (especially if the "
497 "wad is very large, e.g. DOOM2.WAD). There is also a "
498 "small risk: if something goes wrong during saving, your "
499 "wad file will be toast.\n"
500 "\n"
501 "Do you want to continue ?");
502
503 choice = DialogShowAndGetChoice(ALERT_TXT, skull_image,
504 buffer, "OK", "Cancel");
505
506 if (choice != 0)
507 return FALSE;
508 }
509
510 guix_info.load_all = TRUE;
511 }
512 else if (guix_prefs.overwrite_warn &&
513 HelperFileExists(guix_info.output_file))
514 {
515 sprintf(buffer,
516 "Warning: the chosen Output file already exists:\n"
517 "\n"
518 " %s\n"
519 "\n"
520 "Do you want to overwrite it ?",
521 guix_info.output_file);
522
523 choice = DialogShowAndGetChoice(ALERT_TXT, skull_image,
524 buffer, "OK", "Cancel");
525
526 if (choice != 0)
527 return FALSE;
528 }
529
530 return TRUE;
531 }
532
BuildCheckInfo(void)533 static boolean_g BuildCheckInfo(void)
534 {
535 char buffer[1024];
536
537 for (;;)
538 {
539 glbsp_ret_e ret = GlbspCheckInfo(&guix_info, &guix_comms);
540
541 if (ret == GLBSP_E_OK)
542 return TRUE;
543
544 if (ret != GLBSP_E_BadInfoFixed)
545 {
546 sprintf(buffer,
547 "The following problem was detected with the current "
548 "node building options:\n"
549 "\n"
550 " %s\n"
551 "\n"
552 "Please fix the problem and try again.",
553 guix_comms.message ? guix_comms.message : MISSING_COMMS);
554
555 // user doesn't have any real choice here
556 DialogShowAndGetChoice(ALERT_TXT, skull_image, buffer);
557
558 guix_win->ReadAllInfo();
559 break;
560 }
561
562 sprintf(buffer,
563 "The following problem was detected with the current "
564 "node building options:\n"
565 "\n"
566 " %s\n"
567 "\n"
568 "However, the option causing the problem has now been "
569 "changed into something that should work. "
570 "Do you want to continue ?",
571 guix_comms.message ? guix_comms.message : MISSING_COMMS);
572
573 int choice = DialogShowAndGetChoice(ALERT_TXT, skull_image,
574 buffer, "OK", "Cancel");
575
576 if (choice != 0)
577 break;
578 }
579
580 return FALSE;
581 }
582
BuildDoBuild(void)583 static void BuildDoBuild(void)
584 {
585 glbsp_ret_e ret = GlbspBuildNodes(&guix_info, &guix_funcs, &guix_comms);
586
587 if (ret == GLBSP_E_OK)
588 return;
589
590 guix_win->progress->ClearBars();
591
592 if (ret == GLBSP_E_Cancelled)
593 {
594 guix_win->text_box->AddMsg("\n*** Cancelled ***\n", FL_BLUE, TRUE);
595 return;
596 }
597
598 // something went wrong :(
599
600 char err_kind = '?';
601
602 switch (ret)
603 {
604 case GLBSP_E_ReadError:
605 guix_win->text_box->AddMsg("\n*** Read Error ***\n", FL_BLUE, TRUE);
606 err_kind = 'r';
607 break;
608
609 case GLBSP_E_WriteError:
610 guix_win->text_box->AddMsg("\n*** Write Error ***\n", FL_BLUE, TRUE);
611 err_kind = 'w';
612 break;
613
614 // these two shouldn't happen
615 case GLBSP_E_BadArgs:
616 case GLBSP_E_BadInfoFixed:
617 guix_win->text_box->AddMsg("\n*** Option Error ***\n", FL_BLUE, TRUE);
618 err_kind = 'o';
619 break;
620
621 case GLBSP_E_Unknown:
622 default:
623 guix_win->text_box->AddMsg("\n*** Error ***\n", FL_BLUE, TRUE);
624 break;
625 }
626
627 char buffer[1024];
628
629 sprintf(buffer,
630 "The following problem was encountered when trying to "
631 "build the nodes:\n"
632 "\n"
633 " %s\n",
634 guix_comms.message ? guix_comms.message : MISSING_COMMS);
635
636 if (err_kind == 'r')
637 {
638 strcat(buffer, "\nCheck that the Input file is a valid WAD "
639 "file, and it is not corrupted.");
640 }
641 else if (err_kind == 'w')
642 {
643 strcat(buffer, "\nCheck that your hard disk (or floppy disk, etc) "
644 "has not run out of storage space.");
645 }
646
647 DialogShowAndGetChoice(ALERT_TXT, pldie_image, buffer);
648 }
649
builder_build_CB(Fl_Widget * w,void * data)650 static void builder_build_CB(Fl_Widget *w, void *data)
651 {
652 // disable most of the interface, especially the BUILD button itself
653 // (this routine is NOT reentrant !).
654 guix_win->LockOut(TRUE);
655
656 // make sure info is up-to-date
657 guix_win->WriteAllInfo();
658
659 // save cookies, in case the build crashes or calls the fatal-error
660 // function.
661 CookieWriteAll();
662
663 // sleight of hand for GWA mode: we remember the old output name in
664 // the nodebuildinfo and replace it with the gwa name. The memory
665 // stuff is messy, since we can't be 100% sure that 'output_file'
666 // field won't be freed and assigned a new value by the main code.
667
668 const char *old_output = guix_info.output_file;
669 boolean_g gwa_hack = FALSE;
670
671 if (guix_info.gwa_mode)
672 {
673 guix_info.output_file = GlbspStrDup(guix_win->files->gwa_filename);
674 gwa_hack = TRUE;
675 }
676
677 #if 0 // DEBUG
678 fprintf(stderr, "BUILD\n INPUT = [%s]\n OUTPUT = [%s]\n\n",
679 guix_info.input_file, guix_info.output_file);
680 #endif
681
682 if (BuildValidateOptions())
683 {
684 if (BuildCheckInfo())
685 {
686 BuildDoBuild();
687 guix_win->text_box->AddHorizBar();
688 }
689 }
690
691 if (gwa_hack)
692 {
693 GlbspFree(guix_info.output_file);
694 guix_info.output_file = old_output;
695 }
696
697 // if the build info changed, make sure widgets are in sync.
698 // This is not the ideal place, it would be better to call this as
699 // soon as any change could've happened -- but the GWA hack
700 // interferes with that approach.
701 //
702 guix_win->ReadAllInfo();
703
704 GlbspFree(guix_comms.message);
705 guix_comms.message = NULL;
706
707 // restore user interface to normal
708 guix_win->LockOut(FALSE);
709 guix_win->progress->ClearBars();
710 }
711
builder_cancel_CB(Fl_Widget * w,void * data)712 static void builder_cancel_CB(Fl_Widget *w, void *data)
713 {
714 guix_comms.cancelled = TRUE;
715 }
716
717
718 //
719 // BuildButton Constructor
720 //
Guix_BuildButton(int x,int y,int w,int h)721 Guix_BuildButton::Guix_BuildButton(int x, int y, int w, int h) :
722 Fl_Group(x, y, w, h)
723 {
724 end(); // turn off auto-add-widgets
725
726 resizable(0); // no resizing the kiddies, please
727
728 // create button sitting in a space of its own
729
730 build = new Fl_Button(x+10, y+10, 90, 30, "Build");
731 build->box(FL_ROUND_UP_BOX);
732 build->align(FL_ALIGN_INSIDE);
733 build->callback((Fl_Callback *) builder_build_CB);
734 add(build);
735
736 stopper = new Fl_Button(x+140, y+10, 90, 30, "Stop");
737 stopper->box(FL_ROUND_UP_BOX);
738 stopper->align(FL_ALIGN_INSIDE);
739 stopper->callback((Fl_Callback *) builder_cancel_CB);
740 stopper->shortcut(FL_Escape);
741 add(stopper);
742 }
743
744 //
745 // BuildButton Destructor
746 //
~Guix_BuildButton()747 Guix_BuildButton::~Guix_BuildButton()
748 {
749 // nothing to do
750 }
751
752
LockOut(boolean_g lock_it)753 void Guix_BuildButton::LockOut(boolean_g lock_it)
754 {
755 if (lock_it)
756 build->set_output();
757 else
758 build->clear_output();
759 }
760
761