1 /* Copyright (c) 2006 by Arkkra Enterprises */
2 /* All rights reserved */
4 // Code for the Config menu item on the main toolbar
7 #include "Preferences.H"
11 #include <FL/fl_ask.H>
12 #include <FL/Fl_Tooltip.H>
19 // Window to ask user where files and tools are located
21 FileLocations_dialog::FileLocations_dialog(void)
22 : Fl_Double_Window(620, 300, "Mupmate File Locations")
24 mup_documentation_p = new Fl_Input(200, 30, 400, 30, "Mup Documentation Folder");
25 mup_documentation_p->tooltip("Set where Mup documentation\n"
26 "files are installed on your system.\n"
27 "This folder must contain the \"uguide\"\n"
28 "folder that contains the HTML version\n"
29 "of the Mup User's Guide.");
31 mup_program_p = new Fl_Input(200, 65, 400, 30, "Mup Command Path");
32 mup_program_p->tooltip("Set where the Mup program\n"
33 "is installed on your system.");
35 music_files_p = new Fl_Input(200, 100, 400, 30, "Folder for Mup Files");
36 music_files_p->tooltip("Set the default folder for storing\n"
37 "your Mup files (.mup input files,\n"
38 "and .ps and .mid output files).");
40 muppath_p = new Fl_Input(200, 135, 400, 30, "Folder for Mup include Files");
41 static char include_tip_text[200];
42 (void) sprintf(include_tip_text,
43 "Set the default folder (or list of folders,\n"
44 "separated by %c characters) for\n"
45 "storing your Mup \"include\" files.",
47 muppath_p->tooltip(include_tip_text);
49 viewer_p = new Fl_Input(200, 170, 400, 30, "PostScript Viewer Path");
50 viewer_p->tooltip("Set which PostScript viewing program\n"
51 "to use for displaying Mup output.\n"
53 "This is typically GSview32.exe\n"
54 "which you can obtain from\n"
55 "http://www.cs.wisc.edu/~ghost/gsview/"
57 "The \"gv\" program is a common choice."
61 player_p = new Fl_Input(200, 205, 400, 30, "MIDI Player Path");
62 player_p->tooltip("Set which MIDI player program\n"
63 "to use for playing Mup MIDI output.\n"
65 "This is typically wmplayer.exe"
67 "Common choices include xplaymidi or timidity."
71 apply_p = new Fl_Return_Button(50, 255, 100, 30, "Apply");
72 apply_p->when(FL_WHEN_RELEASE);
73 apply_p->callback(Apply_cb, this);
75 cancel_p = new Fl_Button(w() - 150, 255, 100, 30, "Cancel");
76 cancel_p->shortcut(FL_Escape);
77 cancel_p->when(FL_WHEN_RELEASE);
78 cancel_p->callback(Cancel_cb, this);
80 // Populate the fields
83 // Arrange for destructor to clean up new-ed widgets
86 // Arrange for window manager closes to do Cancel.
87 callback(Cancel_cb, this);
92 FileLocations_dialog::~FileLocations_dialog()
97 //--- Callback for when user clicks "Apply" on FileLocations dialog.
98 // Save values in preferences file.
100 CALL_BACK(FileLocations_dialog, Apply)
102 bool changes = false; // if any changes made
103 bool error = false; // if any errors found
104 char location[FL_PATH_MAX];
106 // Documentation location
107 if (mup_documentation_p->size() > 0) {
108 (void) Preferences_p->set(Mup_documentation_location,
109 mup_documentation_p->value());
111 // Documentation being wrong means User's Guide can't be
112 // shown, which is bad, although not fatal.
113 if ( ! fl_filename_isdir(mup_documentation_p->value()) ) {
114 fl_alert("Location for Mup documentation is not a valid folder.");
118 if (access(users_guide_index_file(
119 mup_documentation_p->value()), F_OK)
121 fl_alert("Folder specified for Mup documentation it not correct:\n"
122 "it does not contain the Mup User's Guide.");
128 // Location of Mup program
129 if (mup_program_p->size() > 0) {
130 if (find_executable(mup_program_p->value(), location)) {
131 (void) Preferences_p->set(Mup_program_location,
132 mup_program_p->value());
136 fl_alert("Location specified for Mup program is not valid.");
141 // Default folder for Mup input files
142 if (music_files_p->size() > 0) {
143 if (chdir(music_files_p->value()) != 0) {
144 fl_alert("Value for \"Folder for Mup Files\" is not a valid folder.");
148 (void) Preferences_p->set(Music_files_location,
149 music_files_p->value());
155 if (muppath_p->size() > 0) {
156 (void) Preferences_p->set(MUPPATH_location, muppath_p->value());
158 set_muppath(muppath_p->value());
160 // Setting MUPPATH correctly is only important if user
161 // actually uses it, which many people won't, but if it is set
162 // to something invalid, we give a warning.
163 // Since MUPPATH can be a list, we check each component
165 char pathcopy[muppath_p->size() + 1];
166 (void) strcpy(pathcopy, muppath_p->value());
167 char * component_p = pathcopy;
168 char * sep_p; // where path separator appears in list
170 if ((sep_p = strchr(component_p, path_separator())) != 0) {
173 if (strlen(component_p) > 0 &&
174 ! fl_filename_isdir(component_p)) {
175 fl_alert("Location for Mup include files\n"
176 "\"%s\"\nis not a valid folder.",
180 component_p += strlen(component_p) + 1;
181 } while (sep_p != 0);
184 // PostScript viewer program
185 if (viewer_p->size() > 0) {
186 if (find_executable(viewer_p->value(), location)) {
187 (void) Preferences_p->set(Viewer_location, viewer_p->value());
191 fl_alert("Location specified for PostScript viewer is not valid.");
197 if (player_p->size() > 0) {
198 if (find_executable(player_p->value(), location)) {
199 (void) Preferences_p->set(MIDI_player_location, player_p->value());
203 fl_alert("Location specified for MIDI player is not valid.");
208 // If any changes, persist the data.
210 Preferences_p->flush();
213 // If there were errors, leave form up so user can try to correct them.
220 //--- callback for when user clicks "Cancel" on FileLocations dialog
222 CALL_BACK(FileLocations_dialog, Cancel)
225 // Put all the original settings back on the form
226 set_current_values();
230 // Populate form with the current default values from user's preferences.
233 FileLocations_dialog::set_current_values(void)
236 (void) Preferences_p->get(Mup_documentation_location, val,
237 Default_Mup_documentation_location);
238 mup_documentation_p->value(val);
240 (void) Preferences_p->get(Mup_program_location, val,
241 Default_Mup_program_location);
242 mup_program_p->value(val);
244 (void) Preferences_p->get(Music_files_location, val,
245 Default_music_files_location);
246 music_files_p->value(val);
247 (void) Preferences_p->get(MUPPATH_location, val,
248 Default_MUPPATH_location);
249 muppath_p->value(val);
250 (void) Preferences_p->get(Viewer_location, val,
251 Default_viewer_location);
252 viewer_p->value(val);
253 (void) Preferences_p->get(MIDI_player_location, val,
254 Default_MIDI_player_location);
255 player_p->value(val);
259 //-----------------------------------------------------------------
261 // List of standard FLTK fonts, and info to map name to menu entry.
267 { "Courier", FL_COURIER },
268 { "Courier Bold", FL_COURIER_BOLD },
269 { "Courier Italic", FL_COURIER_ITALIC },
270 { "Courier Bold Italic", FL_COURIER_BOLD_ITALIC },
271 { "Helvetica", FL_HELVETICA },
272 { "Helvetica Bold", FL_HELVETICA_BOLD },
273 { "Helvetica Italic", FL_HELVETICA_ITALIC },
274 { "Helvetica Bold Italic", FL_HELVETICA_BOLD_ITALIC },
275 { "Times", FL_TIMES },
276 { "Times Bold", FL_TIMES_BOLD },
277 { "Times Italic", FL_TIMES_ITALIC },
278 { "Times Bold Italic", FL_TIMES_BOLD_ITALIC },
280 static const int Fontlistlength = sizeof(Fontlist) / sizeof(Fontlist[0]);
282 // Window to ask user preferences, like editor font, size, etc.
284 Preferences_dialog::Preferences_dialog(void)
285 : Fl_Double_Window(400, 280, "Mupmate Preferences")
287 // Make widget for user's editor font choice.
288 font_p = new Fl_Choice(20, 40, 210, 30, "Text Font");
289 font_p->tooltip("Select the font to be used\n"
290 "in the editor window where you\n"
291 "type in Mup input. It is also used\n"
292 "for the Help and error report text.");
293 // Arrange to reset size menu if font selection changes
294 font_p->callback(fontchg_cb, this);
295 font_p->when(FL_WHEN_CHANGED);
296 font_p->align(FL_ALIGN_TOP_LEFT);
298 // Make widget for user's editor size choice.
299 size_p = new Fl_Choice(270, 40, 100, 30, "Text Size");
300 size_p->tooltip("Select the text size to be used\n"
301 "in the editor window where you\n"
302 "type in Mup input. It is also used\n"
303 "for the Help and error report text.");
304 size_p->align(FL_ALIGN_TOP_LEFT);
306 auto_display_p = new Fl_Check_Button(20, 90, 180, 30,
307 "Auto-Display on Save");
308 auto_display_p->tooltip("Set whether your music\n"
309 "is displayed automatically\n"
310 "whenever you save your Mup file.");
312 auto_save_p = new Fl_Check_Button(w() - 170, 90, 150, 30,
314 auto_save_p->tooltip("Set whether your music is saved\n"
315 "automatically whenever you do Display, Play,\n"
316 "Write PostScript or Write MIDI from the Run menu.");
318 tooltips_delay_p = new Fl_Value_Input(150, 155, 100, 30, "Tool Tip Delay");
319 tooltips_delay_p->minimum(0.0);
320 tooltips_delay_p->precision(3);
321 tooltips_delay_p->tooltip("Set how long to delay before showing\n"
322 "tool tips, in seconds.\n");
323 tooltips_delay_p->align(FL_ALIGN_TOP_LEFT);
325 // Create and configure widget for Apply button
326 apply_p = new Fl_Return_Button(60, 215, 100, 30, "Apply");
327 apply_p->when(FL_WHEN_RELEASE);
328 apply_p->callback(Apply_cb, this);
330 // Create and configure widget for Cancel button
331 cancel_p = new Fl_Button(w() - 160, 215, 100, 30, "Cancel");
332 cancel_p->shortcut(FL_Escape);
333 cancel_p->when(FL_WHEN_RELEASE);
334 cancel_p->callback(Cancel_cb, this);
336 // Populate the fields
337 set_current_values();
339 // Arrange for destructor to clean up new-ed widgets
342 // Arrange for window manager closes to do Cancel.
343 callback(Cancel_cb, this);
347 Preferences_dialog::~Preferences_dialog()
352 //---- Callback for when user changes font selection.
353 // This re-creates the size menu to be what sizes are available
354 // for that font, since each font could have a different set of sizes.
356 CALL_BACK(Preferences_dialog, fontchg)
359 if (size_p->mvalue() != 0) {
360 size = atoi(size_p->mvalue()->text);
363 // Shouldn't really be possible to get here,
364 // but better to be safe.
365 size = (unsigned char) atoi(Default_editor_size);
368 set_size_list(Config::fontvalue(font_p->mvalue()->text), size);
372 //--- Callback for when user clicks Apply in Preferences
373 // Save the new values.
375 CALL_BACK(Preferences_dialog, Apply)
380 Preferences_p->set(Auto_display_preference, auto_display_p->value());
381 Preferences_p->set(Auto_save_preference, auto_save_p->value());
382 Preferences_p->set(Tooltips_delay_preference, tooltips_delay_p->value());
383 Fl_Tooltip::delay(tooltips_delay_p->value());
385 // Convert font menu selection into font value.
386 for (n = 0; n < Fontlistlength; n++) {
387 if (Fontlist[n].menu_offset == font_p->value()) {
388 Preferences_p->set(Editor_font_preference, Fontlist[n].name);
389 font = Fontlist[n].value;
393 if (n >= Fontlistlength) {
394 // Selection not valid. Fall back to using the default.
396 (void) Preferences_p->get(Editor_font_preference, fontname,
397 Default_editor_font);
398 font = Config::fontvalue(fontname);
403 if (size_p->text() != 0) {
404 (void) Preferences_p->set(Editor_size_preference, size_p->text());
405 size = (unsigned char) atoi(size_p->text());
408 size = (unsigned char) atoi(Default_editor_size);
412 Preferences_p->flush();
414 // Actually change the font/size in all relevant windows.
415 // Windows that want to know about these changes register a callback,
417 Font_change_registration::run_callbacks(font, size);
422 //--- callback for when user clicks Cancel in Preferences
424 CALL_BACK(Preferences_dialog, Cancel)
427 // Put all the original settings back on the form
428 set_current_values();
432 // Populate form with current values from user's preferences
435 Preferences_dialog::set_current_values(void)
438 (void) Preferences_p->get(Auto_display_preference, auto_display,
439 Default_auto_display);
440 auto_display_p->value(auto_display);
443 (void) Preferences_p->get(Auto_save_preference, auto_save,
445 auto_save_p->value(auto_save);
447 double tooltips_delay;
448 (void) Preferences_p->get(Tooltips_delay_preference, tooltips_delay,
449 Default_tooltips_delay);
450 tooltips_delay_p->value(tooltips_delay);
453 (void) Preferences_p->get(Editor_font_preference, fontname,
454 Default_editor_font);
455 Fl_Font font = Config::fontvalue(fontname);
456 // Populate font menu
458 for (int i = 0; i < Fontlistlength; i++) {
459 Fontlist[i].menu_offset =
460 font_p->add(Fontlist[i].name, 0, 0, 0, 0);
461 // Set the current value
462 if (Fontlist[i].value == font) {
463 font_p->value(Fontlist[i].menu_offset);
468 (void) Preferences_p->get(Editor_size_preference, sizename,
469 Default_editor_size);
470 unsigned char size = (unsigned char) atoi(sizename);
471 // Populate the size menu
472 set_size_list(font, size);
476 // When font selection changes, re-create the size menu,
477 // because each font could have different sizes available.
480 Preferences_dialog::set_size_list(Fl_Font font, uchar curr_size)
482 // Avoid really tiny sizes, or more importantly, zero, like if an atoi
483 // failed, because otherwise FLTK may try to divide by zero.
484 // Also limit to a maximum size.
485 if (curr_size < Min_size || curr_size > Max_size) {
486 curr_size = (unsigned char) atoi(Default_editor_size);
489 // Clean out the current menu if any
494 int numsizes = Fl::get_font_sizes(font, sizelist);
496 // Set current value to ridiculous value, then find closest
497 int currvalue = 5000;
499 int i; // index through sizelist
500 int menu_index; // index into menu
501 for (i = menu_index = 0; i < numsizes; i++) {
502 if (sizelist[i] == 0) {
503 // This means font is scaleable
506 if (sizelist[i] > Max_size) {
509 char num_as_string[4];
510 (void) sprintf(num_as_string, "%d", sizelist[i]);
511 size_p->add(num_as_string, 0, 0, 0, 0);
512 // If this is closest index to desired size, mark as current
513 if ( abs(sizelist[i] - currvalue) > abs(sizelist[i] - curr_size) ) {
514 currvalue = sizelist[i];
515 size_p->value(menu_index);
519 if (numsizes == 0 || (numsizes == 1 && sizelist[0] == 0)) {
520 // Either no available sizes at all, or only
521 // scaleable, with no special "good" sizes,
522 // so we pick some and hope for the best.
523 size_p->add("10", 0, 0, 0, 0);
524 if (curr_size <= 11) {
527 size_p->add("12", 0, 0, 0, 0);
528 if (curr_size >= 12 && curr_size <= 13) {
531 size_p->add("14", 0, 0, 0, 0);
532 if (curr_size >= 14 && curr_size <= 15) {
535 size_p->add("16", 0, 0, 0, 0);
536 if (curr_size >= 16 && curr_size <= 17) {
539 size_p->add("18", 0, 0, 0, 0);
540 if (curr_size >= 18) {
546 //----------dialog to let user fill in the Registration form---------------
548 #define MULTI_OS "Note that if you wish to use Mup\n" \
549 "on multiple machines simultaneously,\n" \
550 "you need to purchase a registration\n" \
554 RegistrationForm_dialog::RegistrationForm_dialog(void)
555 : Fl_Double_Window(500, 450, "Mup Registration")
557 name_p = new Fl_Input(80, 20, 400, 30, "Name");
558 name_p->tooltip("Enter your name.");
560 address_p = new Fl_Input(80, 60, 400, 30, "Address");
561 address_p->tooltip("Enter your street address.");
563 city_p = new Fl_Input(80, 100, 180, 30, "City");
564 city_p->tooltip("Enter the name of the city\n"
565 "in which you live.");
566 state_p = new Fl_Input(380, 100, 100, 30, "State/Province");
567 state_p->tooltip("Enter the state or province (if any)\n"
568 "in which you live.");
570 postal_code_p = new Fl_Input(110, 140, 120, 30, "Postal Code");
571 postal_code_p->tooltip("Enter your zip code or postal code\n"
572 "as appropriate for your country.");
574 country_p = new Fl_Input(320, 140, 160, 30, "Country");
575 country_p->tooltip("Enter the name of the country in which\n"
576 "you live (optional if in USA).");
578 email_p = new Fl_Input(110, 180, 370, 30, "Email address");
579 email_p->tooltip("Enter your email address. This will only be used\n"
580 "to send you your registration key\n"
581 "and announcements of future (free) Mup upgrades.");
583 how_heard_p = new Fl_Input(20, 240, 460, 30, "Where did you hear about Mup?");
584 how_heard_p->align(FL_ALIGN_TOP_LEFT);
585 how_heard_p->tooltip("Please let us know how you learned about Mup\n"
586 "(a particular web link, magazine, book, etc.).");
588 // Checkboxes for OS types.
589 // If we are compiled for a particular OS,
590 // automatically check that box.
591 Windows_p = new Fl_Check_Button(20, 280, 80, 30, "Windows");
595 Windows_p->tooltip("Check here if you plan to run Mup\n"
596 "under Microsoft Windows.\n"
599 Mac_p = new Fl_Check_Button(110, 280, 50, 30, "Mac");
600 Mac_p->tooltip("Check here if you plan to run Mup\n"
601 "under Apple Mac OS.\n"
607 Linux_p = new Fl_Check_Button(170, 280, 60, 30, "Linux");
608 Linux_p->tooltip("Check here if you plan to run Mup\n"
615 other_p = new Fl_Check_Button(240, 280, 60, 30, "Other");
616 other_p->tooltip("Check here if you plan to run Mup\n"
617 "under an OS not listed.\n"
619 other_OS_p = new Fl_Input(300, 280, 180, 30, "");
620 other_OS_p->tooltip("If you checked \"Other,\"\n"
621 "specify the name of the Operating System.\n"
624 mailing_list_p = new Fl_Check_Button(100, 320, 350, 30,
625 "I would like to join the Mup user's mailing list");
626 mailing_list_p->tooltip("There is a email mailing list for registered\n"
627 "Mup users, for sharing information about Mup.\n"
628 "Check here if you want to join the list.\n"
629 "There is no extra charge, and you can always\n"
630 "subscribe/unsubscribe later if you change your mind.");
632 num_regs_p = new Positive_Int_Input(340, 355, 60, 30,
633 "Number of Registrations ($29 each)");
634 num_regs_p->value("1");
635 num_regs_p->tooltip("Enter the number of registrations\n"
636 "you wish to purchase.\n"
639 save_form_p = new Fl_Return_Button(40, h() - 50, 120, 30, "Save Form");
640 save_form_p->callback(SaveForm_cb, this);
641 cancel_p = new Fl_Button(w() - 160, h() - 50, 120, 30, "Cancel");
642 cancel_p->shortcut(FL_Escape);
643 cancel_p->when(FL_WHEN_RELEASE);
644 cancel_p->callback(Cancel_cb, this);
646 // Arrange for destructor to clean up new-ed widgets
649 // Arrange for window manager closes to do Cancel.
650 callback(Cancel_cb, this);
655 RegistrationForm_dialog::~RegistrationForm_dialog(void)
660 CALL_BACK(RegistrationForm_dialog, SaveForm)
667 CALL_BACK(RegistrationForm_dialog, Cancel)
673 // Generate the registration form with fields filled in.
675 extern const char * const registration_text;
676 static const char * const checkmark = "X";
677 static const char * const reg_file_name = "mup-reg.txt";
680 RegistrationForm_dialog::generate_form()
682 char * text = strdup(registration_text);
684 // First find all the fields in the registration form.
685 // Do this before filling anything is to avoid any chance
686 // of being confused by what we fill in.
687 char * name = strstr(text, "Name");
688 char * address = strstr(text, "Address");
689 char * city = strstr(text, "City");
690 char * state = strstr(text, "State");
691 char * postal_code = strstr(text, "Zip code");
692 char * country = strstr(text, "Country");
693 char * email = strstr(text, "Email");
694 char * how_heard = strstr(text, "How did you");
695 char * how_heard_line2 = strstr(how_heard, "\n\n");
696 char * Linux = strstr(text, "Linux");
697 char * Windows = strstr(text, "Windows/MS-DOS");
698 char * Mac = strstr(text, "Mac");
699 char * other = strstr(text, "Other");
700 char * mailing_list = strstr(text, "Yes");
701 char * regs = strstr(text, "Mup Version");
703 (void) fill_in(false, name, name_p->value());
704 (void) fill_in(false, address, address_p->value());
705 (void) fill_in(false, city, city_p->value());
706 (void) fill_in(false, state, state_p->value());
707 (void) fill_in(false, postal_code, postal_code_p->value());
708 (void) fill_in(false, country, country_p->value());
709 (void) fill_in(false, email, email_p->value());
710 const char * remaining;
711 if ((remaining = fill_in(false, how_heard, how_heard_p->value()))
713 (void) fill_in(false, how_heard_line2, remaining);
716 if (Windows_p->value()) {
717 (void) fill_in(true, Windows, checkmark);
719 if (Linux_p->value()) {
720 (void) fill_in(true, Linux, checkmark);
722 if (Mac_p->value()) {
723 (void) fill_in(true, Mac, checkmark);
725 if (other_p->value()) {
726 (void) fill_in(true, other, checkmark);
728 if (other_OS_p->size() > 0) {
729 (void) fill_in(false, other, other_OS_p->value());
731 (void) fill_in(mailing_list_p->value(), mailing_list, checkmark);
733 (void) fill_in(true, regs, num_regs_p->value());
737 if ((regfile = fopen(reg_file_name, "w")) == 0) {
738 fl_alert("Unable to write registration form file.");
741 (void) fprintf(regfile, "%s", text);
742 (void) fprintf(regfile, "\n\n\t Total due: $%.2f\n",
743 (29.0 + sales_tax()) * atoi(num_regs_p->value()));
745 char currdir[FL_PATH_MAX];
747 if (getcwd(currdir, sizeof(currdir)) == 0) {
751 fl_message("Your registration form has been saved in\n"
752 "%s%c%s.", currdir, dir_separator(), reg_file_name);
758 // Fills in value into blank either before or after the given place.
759 // Center the string in the blank.
760 // If it can't fit the entire value, it returns a pointer to
761 // what was left over, otherwise returns zero.
764 RegistrationForm_dialog::fill_in(bool before, char * place, const char * const value)
766 if (place == 0 || value == 0) {
767 // Shouldn't happen, but better than core dump.
772 // Find beginning of the blank.
774 // back up to beginning of blanks, skipping any spaces
775 for (blanks_p = place - 1; *blanks_p == ' '; blanks_p--)
777 for ( ; *blanks_p == '_'; blanks_p--)
782 blanks_p = strchr(place, '_');
785 // Figure out how much leading padding to leave
786 int count = strspn(blanks_p, "_");
787 int length = strlen(value);
789 // Fill in the blank.
791 if (length > count) {
792 // Try to split at white space.
794 for (used_length = count; used_length > 10; used_length--) {
795 if (value[used_length] == ' ') {
799 padding = (count - used_length) / 2;
800 strncpy(blanks_p + padding, value, used_length);
801 return(value + used_length + 1);
804 padding = (count - length) / 2;
805 strncpy(blanks_p + padding, value, length);
811 // Since Arkkra is based in Illinois, Illinois residents need to pay
812 // sales tax. So try to deduce if the address is Illinois.
813 // Simple minded--may sometimes guess wrong.
816 RegistrationForm_dialog::sales_tax(void)
818 const char * pattern;
820 if (state_p->size() > 0) {
821 // Skip leading white space
822 for (pattern = state_p->value(); *pattern == ' '; pattern++)
824 if (*pattern == '\0') {
827 // Remove any trailing white space.
828 // Can't remove in place, since string is const.
829 // So remove from copy.
830 char state[strlen(pattern) + 1];
831 (void) strcpy(state, pattern);
833 for (p = state + strlen(pattern) - 1; p > state ; p--) {
842 if (strcmp(state, "IL") == 0
843 || strcasecmp(state, "Illinois") == 0
844 || strcasecmp(state, "Ill.") == 0) {
845 // Sales tax is $2.18 per registration.
853 //----------dialog to let user type in the Registration Key---------------
855 RegistrationKey_dialog::RegistrationKey_dialog(void)
856 : Fl_Double_Window(250, 100, "Registration Key")
858 key_p = new Fl_Secret_Input(60, 20, 150, 30, "Key:");
859 key_p->tooltip("Enter the registration key\n"
860 "you received from Arkkra Enterprises\n"
861 "after you have paid your registration fee.");
863 OK_p = new Fl_Return_Button(25, 60, 80, 30, "OK:");
864 OK_p->when(FL_WHEN_RELEASE);
865 OK_p->callback(OK_cb, this);
867 cancel_p = new Fl_Button(120, 60, 90, 30, "Cancel");
868 cancel_p->shortcut(FL_Escape);
869 cancel_p->when(FL_WHEN_RELEASE);
870 cancel_p->callback(Cancel_cb, this);
872 // Arrange for destructor to clean up new-ed widgets
875 // Arrange for window manager closes to do Cancel.
876 callback(Cancel_cb, this);
881 RegistrationKey_dialog::~RegistrationKey_dialog()
885 CALL_BACK(RegistrationKey_dialog, OK)
889 if ((keyfile = fopen(magic_file(), "w")) == 0) {
890 fl_alert("Unable to open registration key file %s.",
894 if (fprintf(keyfile, "%s", key_p->value()) != key_p->size()) {
895 fl_alert("Unable to save registration key in %s.",
901 // Blank out the field, for if it gets displayed again later.
906 // If user cancels entering registration key, we just hide the window
908 CALL_BACK(RegistrationKey_dialog, Cancel)
914 //-------the Config menu item on main toolbar-------------------------------
920 registrationform_p = 0;
921 registrationkey_p = 0;
926 if (locations_p != 0) {
930 if (preferences_p != 0) {
931 delete preferences_p;
934 if (registrationform_p != 0) {
935 delete registrationform_p;
936 registrationform_p = 0;
938 if (registrationkey_p != 0) {
939 delete registrationkey_p;
940 registrationkey_p = 0;
945 // Bring up the dialog for "File Locations" menu item
947 CALL_BACK(Config, FileLocations)
949 if (locations_p == 0) {
950 // first time, create widget
951 locations_p = new FileLocations_dialog();
957 // Bring up the dialog for "Preferences" menu item
959 CALL_BACK(Config, Preferences)
961 if (preferences_p == 0) {
962 // first time, create widget
963 preferences_p = new Preferences_dialog();
965 preferences_p->show();
969 // Bring up dialog for filling in Registration Form
971 CALL_BACK(Config, RegistrationForm)
973 if (registrationform_p == 0) {
974 // first time, create widget
975 registrationform_p = new RegistrationForm_dialog();
977 registrationform_p->show();
978 fl_message("Note: For fastest service, you can register via\n"
979 "credit card at http://www.arkkra.com/doc/credtcrd.html\n"
980 "rather than filling out and mailing in a paper form.");
984 // Bring up dialog to let user enter their registration key after paying
986 CALL_BACK(Config, RegistrationKey)
988 if (registrationkey_p == 0) {
989 // first time, create widget
990 registrationkey_p = new RegistrationKey_dialog();
992 registrationkey_p->show();
996 // Translate font name to FL_Font value.
999 Config::fontvalue(const char * fontname)
1002 // Linear search of the list (it is short).
1003 for (n = 0; n < Fontlistlength; n++) {
1004 if (strcmp(Fontlist[n].name, fontname) == 0) {
1005 return(Fontlist[n].value);
1008 // Hmmm. Not found. Should not happen. Hunt for default
1009 for (n = 0; n < Fontlistlength; n++) {
1010 if (strcmp(Fontlist[n].name, Default_editor_font) == 0) {
1011 return(Fontlist[n].value);
1014 // Wow. Can't find default either. Punt.
1019 //--------------------- class that lets other classes register a callback
1020 // to be called for changes in font/size
1023 // List of callbacks for when font/size change
1024 Font_change_registration * Font_change_registration::list_p = 0;
1026 Font_change_registration::Font_change_registration(Font_change_callback func, void * arg)
1028 // Save callback information.
1032 // Add to list of callbacks.
1036 // Set the font and size on this newly registered widget.
1037 // Look up the current values and call the newly registered callback.
1039 (void) Preferences_p->get(Editor_font_preference, fontstr,
1040 Default_editor_font);
1041 Fl_Font font = Config::fontvalue(fontstr);
1044 (void) Preferences_p->get(Editor_size_preference, sizestr,
1045 Default_editor_size);
1046 unsigned char size = (unsigned char) atoi(sizestr);
1047 if (size < Min_size) {
1048 size = (unsigned char) atoi(Default_editor_size);
1050 (*func)(arg, font, size);
1053 Font_change_registration::~Font_change_registration(void)
1055 // Remove callback from linked list
1056 if (list_p == this) {
1060 Font_change_registration * fcr_p;
1061 for (fcr_p = list_p; fcr_p != 0; fcr_p = fcr_p->next) {
1062 if (fcr_p->next == this) {
1071 // Notify all classes that want to know about font/size changes,
1072 // by calling the callback function they registered.
1075 Font_change_registration::run_callbacks(Fl_Font font, unsigned char size)
1077 // Avoid unreadably small sizes and division by zero if
1078 // earlier atoi() of size failed due to bad data
1079 // (e.g., user hand-editing the preference file)
1080 if (size < Min_size || size > Max_size) {
1081 size = (unsigned char) atoi(Default_editor_size);
1084 // Walk through list of registered callbacks, calling each.
1085 Font_change_registration * fcr_p;
1086 for (fcr_p = list_p; fcr_p != 0; fcr_p = fcr_p->next) {
1087 (*(fcr_p->callback))(fcr_p->callback_arg, font, size);