/* Copyright (c) 2006 by Arkkra Enterprises */ /* All rights reserved */ // Code for the Config menu item on the main toolbar #include "globals.H" #include "Preferences.H" #include "Config.H" #include "Main.H" #include "utils.H" #include #include #include #include #include #include // Window to ask user where files and tools are located FileLocations_dialog::FileLocations_dialog(void) : Fl_Double_Window(620, 300, "Mupmate File Locations") { mup_documentation_p = new Fl_Input(200, 30, 400, 30, "Mup Documentation Folder"); mup_documentation_p->tooltip("Set where Mup documentation\n" "files are installed on your system.\n" "This folder must contain the \"uguide\"\n" "folder that contains the HTML version\n" "of the Mup User's Guide."); mup_program_p = new Fl_Input(200, 65, 400, 30, "Mup Command Path"); mup_program_p->tooltip("Set where the Mup program\n" "is installed on your system."); music_files_p = new Fl_Input(200, 100, 400, 30, "Folder for Mup Files"); music_files_p->tooltip("Set the default folder for storing\n" "your Mup files (.mup input files,\n" "and .ps and .mid output files)."); muppath_p = new Fl_Input(200, 135, 400, 30, "Folder for Mup include Files"); static char include_tip_text[200]; (void) sprintf(include_tip_text, "Set the default folder (or list of folders,\n" "separated by %c characters) for\n" "storing your Mup \"include\" files.", path_separator()); muppath_p->tooltip(include_tip_text); viewer_p = new Fl_Input(200, 170, 400, 30, "PostScript Viewer Path"); viewer_p->tooltip("Set which PostScript viewing program\n" "to use for displaying Mup output.\n" #ifdef OS_LIKE_WIN32 "This is typically GSview32.exe\n" "which you can obtain from\n" "http://www.cs.wisc.edu/~ghost/gsview/" #else "The \"gv\" program is a common choice." #endif ); player_p = new Fl_Input(200, 205, 400, 30, "MIDI Player Path"); player_p->tooltip("Set which MIDI player program\n" "to use for playing Mup MIDI output.\n" #ifdef OS_LIKE_WIN32 "This is typically wmplayer.exe" #else "Common choices include xplaymidi or timidity." #endif ); apply_p = new Fl_Return_Button(50, 255, 100, 30, "Apply"); apply_p->when(FL_WHEN_RELEASE); apply_p->callback(Apply_cb, this); cancel_p = new Fl_Button(w() - 150, 255, 100, 30, "Cancel"); cancel_p->shortcut(FL_Escape); cancel_p->when(FL_WHEN_RELEASE); cancel_p->callback(Cancel_cb, this); // Populate the fields set_current_values(); // Arrange for destructor to clean up new-ed widgets end(); // Arrange for window manager closes to do Cancel. callback(Cancel_cb, this); when(FL_WHEN_NEVER); } FileLocations_dialog::~FileLocations_dialog() { } //--- Callback for when user clicks "Apply" on FileLocations dialog. // Save values in preferences file. CALL_BACK(FileLocations_dialog, Apply) { bool changes = false; // if any changes made bool error = false; // if any errors found char location[FL_PATH_MAX]; // Documentation location if (mup_documentation_p->size() > 0) { (void) Preferences_p->set(Mup_documentation_location, mup_documentation_p->value()); changes = true; // Documentation being wrong means User's Guide can't be // shown, which is bad, although not fatal. if ( ! fl_filename_isdir(mup_documentation_p->value()) ) { fl_alert("Location for Mup documentation is not a valid folder."); error = true; } else { if (access(users_guide_index_file( mup_documentation_p->value()), F_OK) != 0) { fl_alert("Folder specified for Mup documentation it not correct:\n" "it does not contain the Mup User's Guide."); error = true; } } } // Location of Mup program if (mup_program_p->size() > 0) { if (find_executable(mup_program_p->value(), location)) { (void) Preferences_p->set(Mup_program_location, mup_program_p->value()); changes = true; } else { fl_alert("Location specified for Mup program is not valid."); error = true; } } // Default folder for Mup input files if (music_files_p->size() > 0) { if (chdir(music_files_p->value()) != 0) { fl_alert("Value for \"Folder for Mup Files\" is not a valid folder."); error = true; } else { (void) Preferences_p->set(Music_files_location, music_files_p->value()); changes = true; } } // $MUPPATH value if (muppath_p->size() > 0) { (void) Preferences_p->set(MUPPATH_location, muppath_p->value()); // Set $MUPPATH set_muppath(muppath_p->value()); changes = true; // Setting MUPPATH correctly is only important if user // actually uses it, which many people won't, but if it is set // to something invalid, we give a warning. // Since MUPPATH can be a list, we check each component // in the list. char pathcopy[muppath_p->size() + 1]; (void) strcpy(pathcopy, muppath_p->value()); char * component_p = pathcopy; char * sep_p; // where path separator appears in list do { if ((sep_p = strchr(component_p, path_separator())) != 0) { *sep_p = '\0'; } if (strlen(component_p) > 0 && ! fl_filename_isdir(component_p)) { fl_alert("Location for Mup include files\n" "\"%s\"\nis not a valid folder.", component_p); error = true; } component_p += strlen(component_p) + 1; } while (sep_p != 0); } // PostScript viewer program if (viewer_p->size() > 0) { if (find_executable(viewer_p->value(), location)) { (void) Preferences_p->set(Viewer_location, viewer_p->value()); changes = true; } else { fl_alert("Location specified for PostScript viewer is not valid."); error = true; } } // MIDI player if (player_p->size() > 0) { if (find_executable(player_p->value(), location)) { (void) Preferences_p->set(MIDI_player_location, player_p->value()); changes = true; } else { fl_alert("Location specified for MIDI player is not valid."); error = true; } } // If any changes, persist the data. if (changes) { Preferences_p->flush(); } // If there were errors, leave form up so user can try to correct them. if ( ! error ) { hide(); } } //--- callback for when user clicks "Cancel" on FileLocations dialog CALL_BACK(FileLocations_dialog, Cancel) { hide(); // Put all the original settings back on the form set_current_values(); } // Populate form with the current default values from user's preferences. void FileLocations_dialog::set_current_values(void) { char * val; (void) Preferences_p->get(Mup_documentation_location, val, Default_Mup_documentation_location); mup_documentation_p->value(val); (void) Preferences_p->get(Mup_program_location, val, Default_Mup_program_location); mup_program_p->value(val); (void) Preferences_p->get(Music_files_location, val, Default_music_files_location); music_files_p->value(val); (void) Preferences_p->get(MUPPATH_location, val, Default_MUPPATH_location); muppath_p->value(val); (void) Preferences_p->get(Viewer_location, val, Default_viewer_location); viewer_p->value(val); (void) Preferences_p->get(MIDI_player_location, val, Default_MIDI_player_location); player_p->value(val); } //----------------------------------------------------------------- // List of standard FLTK fonts, and info to map name to menu entry. static struct Font { const char * name; Fl_Font value; int menu_offset; } Fontlist[] = { { "Courier", FL_COURIER }, { "Courier Bold", FL_COURIER_BOLD }, { "Courier Italic", FL_COURIER_ITALIC }, { "Courier Bold Italic", FL_COURIER_BOLD_ITALIC }, { "Helvetica", FL_HELVETICA }, { "Helvetica Bold", FL_HELVETICA_BOLD }, { "Helvetica Italic", FL_HELVETICA_ITALIC }, { "Helvetica Bold Italic", FL_HELVETICA_BOLD_ITALIC }, { "Times", FL_TIMES }, { "Times Bold", FL_TIMES_BOLD }, { "Times Italic", FL_TIMES_ITALIC }, { "Times Bold Italic", FL_TIMES_BOLD_ITALIC }, }; static const int Fontlistlength = sizeof(Fontlist) / sizeof(Fontlist[0]); // Window to ask user preferences, like editor font, size, etc. Preferences_dialog::Preferences_dialog(void) : Fl_Double_Window(400, 280, "Mupmate Preferences") { // Make widget for user's editor font choice. font_p = new Fl_Choice(20, 40, 210, 30, "Text Font"); font_p->tooltip("Select the font to be used\n" "in the editor window where you\n" "type in Mup input. It is also used\n" "for the Help and error report text."); // Arrange to reset size menu if font selection changes font_p->callback(fontchg_cb, this); font_p->when(FL_WHEN_CHANGED); font_p->align(FL_ALIGN_TOP_LEFT); // Make widget for user's editor size choice. size_p = new Fl_Choice(270, 40, 100, 30, "Text Size"); size_p->tooltip("Select the text size to be used\n" "in the editor window where you\n" "type in Mup input. It is also used\n" "for the Help and error report text."); size_p->align(FL_ALIGN_TOP_LEFT); auto_display_p = new Fl_Check_Button(20, 90, 180, 30, "Auto-Display on Save"); auto_display_p->tooltip("Set whether your music\n" "is displayed automatically\n" "whenever you save your Mup file."); auto_save_p = new Fl_Check_Button(w() - 170, 90, 150, 30, "Auto-Save on Run"); auto_save_p->tooltip("Set whether your music is saved\n" "automatically whenever you do Display, Play,\n" "Write PostScript or Write MIDI from the Run menu."); tooltips_delay_p = new Fl_Value_Input(150, 155, 100, 30, "Tool Tip Delay"); tooltips_delay_p->minimum(0.0); tooltips_delay_p->precision(3); tooltips_delay_p->tooltip("Set how long to delay before showing\n" "tool tips, in seconds.\n"); tooltips_delay_p->align(FL_ALIGN_TOP_LEFT); // Create and configure widget for Apply button apply_p = new Fl_Return_Button(60, 215, 100, 30, "Apply"); apply_p->when(FL_WHEN_RELEASE); apply_p->callback(Apply_cb, this); // Create and configure widget for Cancel button cancel_p = new Fl_Button(w() - 160, 215, 100, 30, "Cancel"); cancel_p->shortcut(FL_Escape); cancel_p->when(FL_WHEN_RELEASE); cancel_p->callback(Cancel_cb, this); // Populate the fields set_current_values(); // Arrange for destructor to clean up new-ed widgets end(); // Arrange for window manager closes to do Cancel. callback(Cancel_cb, this); when(FL_WHEN_NEVER); } Preferences_dialog::~Preferences_dialog() { } //---- Callback for when user changes font selection. // This re-creates the size menu to be what sizes are available // for that font, since each font could have a different set of sizes. CALL_BACK(Preferences_dialog, fontchg) { unsigned char size; if (size_p->mvalue() != 0) { size = atoi(size_p->mvalue()->text); } else { // Shouldn't really be possible to get here, // but better to be safe. size = (unsigned char) atoi(Default_editor_size); } set_size_list(Config::fontvalue(font_p->mvalue()->text), size); } //--- Callback for when user clicks Apply in Preferences // Save the new values. CALL_BACK(Preferences_dialog, Apply) { Fl_Font font; int n; Preferences_p->set(Auto_display_preference, auto_display_p->value()); Preferences_p->set(Auto_save_preference, auto_save_p->value()); Preferences_p->set(Tooltips_delay_preference, tooltips_delay_p->value()); Fl_Tooltip::delay(tooltips_delay_p->value()); // Convert font menu selection into font value. for (n = 0; n < Fontlistlength; n++) { if (Fontlist[n].menu_offset == font_p->value()) { Preferences_p->set(Editor_font_preference, Fontlist[n].name); font = Fontlist[n].value; break; } } if (n >= Fontlistlength) { // Selection not valid. Fall back to using the default. char * fontname; (void) Preferences_p->get(Editor_font_preference, fontname, Default_editor_font); font = Config::fontvalue(fontname); } // Save size value. unsigned char size; if (size_p->text() != 0) { (void) Preferences_p->set(Editor_size_preference, size_p->text()); size = (unsigned char) atoi(size_p->text()); } else { size = (unsigned char) atoi(Default_editor_size); } // Persist the data. Preferences_p->flush(); // Actually change the font/size in all relevant windows. // Windows that want to know about these changes register a callback, // so we call them. Font_change_registration::run_callbacks(font, size); hide(); } //--- callback for when user clicks Cancel in Preferences CALL_BACK(Preferences_dialog, Cancel) { hide(); // Put all the original settings back on the form set_current_values(); } // Populate form with current values from user's preferences void Preferences_dialog::set_current_values(void) { int auto_display; (void) Preferences_p->get(Auto_display_preference, auto_display, Default_auto_display); auto_display_p->value(auto_display); int auto_save; (void) Preferences_p->get(Auto_save_preference, auto_save, Default_auto_save); auto_save_p->value(auto_save); double tooltips_delay; (void) Preferences_p->get(Tooltips_delay_preference, tooltips_delay, Default_tooltips_delay); tooltips_delay_p->value(tooltips_delay); char * fontname; (void) Preferences_p->get(Editor_font_preference, fontname, Default_editor_font); Fl_Font font = Config::fontvalue(fontname); // Populate font menu font_p->clear(); for (int i = 0; i < Fontlistlength; i++) { Fontlist[i].menu_offset = font_p->add(Fontlist[i].name, 0, 0, 0, 0); // Set the current value if (Fontlist[i].value == font) { font_p->value(Fontlist[i].menu_offset); } } char * sizename; (void) Preferences_p->get(Editor_size_preference, sizename, Default_editor_size); unsigned char size = (unsigned char) atoi(sizename); // Populate the size menu set_size_list(font, size); } // When font selection changes, re-create the size menu, // because each font could have different sizes available. void Preferences_dialog::set_size_list(Fl_Font font, uchar curr_size) { // Avoid really tiny sizes, or more importantly, zero, like if an atoi // failed, because otherwise FLTK may try to divide by zero. // Also limit to a maximum size. if (curr_size < Min_size || curr_size > Max_size) { curr_size = (unsigned char) atoi(Default_editor_size); } // Clean out the current menu if any size_p->clear(); // Populate the menu int * sizelist; int numsizes = Fl::get_font_sizes(font, sizelist); // Set current value to ridiculous value, then find closest int currvalue = 5000; int i; // index through sizelist int menu_index; // index into menu for (i = menu_index = 0; i < numsizes; i++) { if (sizelist[i] == 0) { // This means font is scaleable continue; } if (sizelist[i] > Max_size) { break; } char num_as_string[4]; (void) sprintf(num_as_string, "%d", sizelist[i]); size_p->add(num_as_string, 0, 0, 0, 0); // If this is closest index to desired size, mark as current if ( abs(sizelist[i] - currvalue) > abs(sizelist[i] - curr_size) ) { currvalue = sizelist[i]; size_p->value(menu_index); } menu_index++; } if (numsizes == 0 || (numsizes == 1 && sizelist[0] == 0)) { // Either no available sizes at all, or only // scaleable, with no special "good" sizes, // so we pick some and hope for the best. size_p->add("10", 0, 0, 0, 0); if (curr_size <= 11) { size_p->value(0); } size_p->add("12", 0, 0, 0, 0); if (curr_size >= 12 && curr_size <= 13) { size_p->value(1); } size_p->add("14", 0, 0, 0, 0); if (curr_size >= 14 && curr_size <= 15) { size_p->value(2); } size_p->add("16", 0, 0, 0, 0); if (curr_size >= 16 && curr_size <= 17) { size_p->value(3); } size_p->add("18", 0, 0, 0, 0); if (curr_size >= 18) { size_p->value(4); } } } //----------dialog to let user fill in the Registration form--------------- #define MULTI_OS "Note that if you wish to use Mup\n" \ "on multiple machines simultaneously,\n" \ "you need to purchase a registration\n" \ "for each." RegistrationForm_dialog::RegistrationForm_dialog(void) : Fl_Double_Window(500, 450, "Mup Registration") { name_p = new Fl_Input(80, 20, 400, 30, "Name"); name_p->tooltip("Enter your name."); address_p = new Fl_Input(80, 60, 400, 30, "Address"); address_p->tooltip("Enter your street address."); city_p = new Fl_Input(80, 100, 180, 30, "City"); city_p->tooltip("Enter the name of the city\n" "in which you live."); state_p = new Fl_Input(380, 100, 100, 30, "State/Province"); state_p->tooltip("Enter the state or province (if any)\n" "in which you live."); postal_code_p = new Fl_Input(110, 140, 120, 30, "Postal Code"); postal_code_p->tooltip("Enter your zip code or postal code\n" "as appropriate for your country."); country_p = new Fl_Input(320, 140, 160, 30, "Country"); country_p->tooltip("Enter the name of the country in which\n" "you live (optional if in USA)."); email_p = new Fl_Input(110, 180, 370, 30, "Email address"); email_p->tooltip("Enter your email address. This will only be used\n" "to send you your registration key\n" "and announcements of future (free) Mup upgrades."); how_heard_p = new Fl_Input(20, 240, 460, 30, "Where did you hear about Mup?"); how_heard_p->align(FL_ALIGN_TOP_LEFT); how_heard_p->tooltip("Please let us know how you learned about Mup\n" "(a particular web link, magazine, book, etc.)."); // Checkboxes for OS types. // If we are compiled for a particular OS, // automatically check that box. Windows_p = new Fl_Check_Button(20, 280, 80, 30, "Windows"); #ifdef __WIN32 Windows_p->value(1); #endif Windows_p->tooltip("Check here if you plan to run Mup\n" "under Microsoft Windows.\n" MULTI_OS); Mac_p = new Fl_Check_Button(110, 280, 50, 30, "Mac"); Mac_p->tooltip("Check here if you plan to run Mup\n" "under Apple Mac OS.\n" MULTI_OS); #ifdef __APPLE__ Mac_p->value(1); #endif Linux_p = new Fl_Check_Button(170, 280, 60, 30, "Linux"); Linux_p->tooltip("Check here if you plan to run Mup\n" "under Linux. " MULTI_OS); #ifdef __linux Linux_p->value(1); #endif other_p = new Fl_Check_Button(240, 280, 60, 30, "Other"); other_p->tooltip("Check here if you plan to run Mup\n" "under an OS not listed.\n" MULTI_OS); other_OS_p = new Fl_Input(300, 280, 180, 30, ""); other_OS_p->tooltip("If you checked \"Other,\"\n" "specify the name of the Operating System.\n" MULTI_OS); mailing_list_p = new Fl_Check_Button(100, 320, 350, 30, "I would like to join the Mup user's mailing list"); mailing_list_p->tooltip("There is a email mailing list for registered\n" "Mup users, for sharing information about Mup.\n" "Check here if you want to join the list.\n" "There is no extra charge, and you can always\n" "subscribe/unsubscribe later if you change your mind."); num_regs_p = new Positive_Int_Input(340, 355, 60, 30, "Number of Registrations ($29 each)"); num_regs_p->value("1"); num_regs_p->tooltip("Enter the number of registrations\n" "you wish to purchase.\n" MULTI_OS); save_form_p = new Fl_Return_Button(40, h() - 50, 120, 30, "Save Form"); save_form_p->callback(SaveForm_cb, this); cancel_p = new Fl_Button(w() - 160, h() - 50, 120, 30, "Cancel"); cancel_p->shortcut(FL_Escape); cancel_p->when(FL_WHEN_RELEASE); cancel_p->callback(Cancel_cb, this); // Arrange for destructor to clean up new-ed widgets end(); // Arrange for window manager closes to do Cancel. callback(Cancel_cb, this); when(FL_WHEN_NEVER); } RegistrationForm_dialog::~RegistrationForm_dialog(void) { } CALL_BACK(RegistrationForm_dialog, SaveForm) { generate_form(); hide(); } CALL_BACK(RegistrationForm_dialog, Cancel) { hide(); } // Generate the registration form with fields filled in. extern const char * const registration_text; static const char * const checkmark = "X"; static const char * const reg_file_name = "mup-reg.txt"; void RegistrationForm_dialog::generate_form() { char * text = strdup(registration_text); // First find all the fields in the registration form. // Do this before filling anything is to avoid any chance // of being confused by what we fill in. char * name = strstr(text, "Name"); char * address = strstr(text, "Address"); char * city = strstr(text, "City"); char * state = strstr(text, "State"); char * postal_code = strstr(text, "Zip code"); char * country = strstr(text, "Country"); char * email = strstr(text, "Email"); char * how_heard = strstr(text, "How did you"); char * how_heard_line2 = strstr(how_heard, "\n\n"); char * Linux = strstr(text, "Linux"); char * Windows = strstr(text, "Windows/MS-DOS"); char * Mac = strstr(text, "Mac"); char * other = strstr(text, "Other"); char * mailing_list = strstr(text, "Yes"); char * regs = strstr(text, "Mup Version"); (void) fill_in(false, name, name_p->value()); (void) fill_in(false, address, address_p->value()); (void) fill_in(false, city, city_p->value()); (void) fill_in(false, state, state_p->value()); (void) fill_in(false, postal_code, postal_code_p->value()); (void) fill_in(false, country, country_p->value()); (void) fill_in(false, email, email_p->value()); const char * remaining; if ((remaining = fill_in(false, how_heard, how_heard_p->value())) != 0) { (void) fill_in(false, how_heard_line2, remaining); } if (Windows_p->value()) { (void) fill_in(true, Windows, checkmark); } if (Linux_p->value()) { (void) fill_in(true, Linux, checkmark); } if (Mac_p->value()) { (void) fill_in(true, Mac, checkmark); } if (other_p->value()) { (void) fill_in(true, other, checkmark); } if (other_OS_p->size() > 0) { (void) fill_in(false, other, other_OS_p->value()); } (void) fill_in(mailing_list_p->value(), mailing_list, checkmark); (void) fill_in(true, regs, num_regs_p->value()); // write to file FILE * regfile; if ((regfile = fopen(reg_file_name, "w")) == 0) { fl_alert("Unable to write registration form file."); } else { (void) fprintf(regfile, "%s", text); (void) fprintf(regfile, "\n\n\t Total due: $%.2f\n", (29.0 + sales_tax()) * atoi(num_regs_p->value())); fclose(regfile); char currdir[FL_PATH_MAX]; if (getcwd(currdir, sizeof(currdir)) == 0) { currdir[0] = '\0'; } hide(); fl_message("Your registration form has been saved in\n" "%s%c%s.", currdir, dir_separator(), reg_file_name); } free(text); } // Fills in value into blank either before or after the given place. // Center the string in the blank. // If it can't fit the entire value, it returns a pointer to // what was left over, otherwise returns zero. const char * RegistrationForm_dialog::fill_in(bool before, char * place, const char * const value) { if (place == 0 || value == 0) { // Shouldn't happen, but better than core dump. return(value); } char * blanks_p; // Find beginning of the blank. if (before) { // back up to beginning of blanks, skipping any spaces for (blanks_p = place - 1; *blanks_p == ' '; blanks_p--) ; for ( ; *blanks_p == '_'; blanks_p--) ; blanks_p++; } else { blanks_p = strchr(place, '_'); } // Figure out how much leading padding to leave int count = strspn(blanks_p, "_"); int length = strlen(value); // Fill in the blank. int padding; if (length > count) { // Try to split at white space. int used_length; for (used_length = count; used_length > 10; used_length--) { if (value[used_length] == ' ') { break; } } padding = (count - used_length) / 2; strncpy(blanks_p + padding, value, used_length); return(value + used_length + 1); } else { padding = (count - length) / 2; strncpy(blanks_p + padding, value, length); return(0); } } // Since Arkkra is based in Illinois, Illinois residents need to pay // sales tax. So try to deduce if the address is Illinois. // Simple minded--may sometimes guess wrong. double RegistrationForm_dialog::sales_tax(void) { const char * pattern; if (state_p->size() > 0) { // Skip leading white space for (pattern = state_p->value(); *pattern == ' '; pattern++) ; if (*pattern == '\0') { return(0.0); } // Remove any trailing white space. // Can't remove in place, since string is const. // So remove from copy. char state[strlen(pattern) + 1]; (void) strcpy(state, pattern); char * p; for (p = state + strlen(pattern) - 1; p > state ; p--) { if (*p == ' ') { *p = '\0'; } else { break; } } if (strcmp(state, "IL") == 0 || strcasecmp(state, "Illinois") == 0 || strcasecmp(state, "Ill.") == 0) { // Sales tax is $2.18 per registration. return(2.18); } } return(0.0); } //----------dialog to let user type in the Registration Key--------------- RegistrationKey_dialog::RegistrationKey_dialog(void) : Fl_Double_Window(250, 100, "Registration Key") { key_p = new Fl_Secret_Input(60, 20, 150, 30, "Key:"); key_p->tooltip("Enter the registration key\n" "you received from Arkkra Enterprises\n" "after you have paid your registration fee."); OK_p = new Fl_Return_Button(25, 60, 80, 30, "OK:"); OK_p->when(FL_WHEN_RELEASE); OK_p->callback(OK_cb, this); cancel_p = new Fl_Button(120, 60, 90, 30, "Cancel"); cancel_p->shortcut(FL_Escape); cancel_p->when(FL_WHEN_RELEASE); cancel_p->callback(Cancel_cb, this); // Arrange for destructor to clean up new-ed widgets end(); // Arrange for window manager closes to do Cancel. callback(Cancel_cb, this); when(FL_WHEN_NEVER); } RegistrationKey_dialog::~RegistrationKey_dialog() { } CALL_BACK(RegistrationKey_dialog, OK) { hide(); FILE * keyfile; if ((keyfile = fopen(magic_file(), "w")) == 0) { fl_alert("Unable to open registration key file %s.", magic_file()); } else { if (fprintf(keyfile, "%s", key_p->value()) != key_p->size()) { fl_alert("Unable to save registration key in %s.", magic_file()); } fclose(keyfile); } // Blank out the field, for if it gets displayed again later. key_p->value(""); } // If user cancels entering registration key, we just hide the window CALL_BACK(RegistrationKey_dialog, Cancel) { hide(); } //-------the Config menu item on main toolbar------------------------------- Config::Config() { locations_p = 0; preferences_p = 0; registrationform_p = 0; registrationkey_p = 0; } Config::~Config() { if (locations_p != 0) { delete locations_p; locations_p = 0; } if (preferences_p != 0) { delete preferences_p; preferences_p = 0; } if (registrationform_p != 0) { delete registrationform_p; registrationform_p = 0; } if (registrationkey_p != 0) { delete registrationkey_p; registrationkey_p = 0; } } // Bring up the dialog for "File Locations" menu item CALL_BACK(Config, FileLocations) { if (locations_p == 0) { // first time, create widget locations_p = new FileLocations_dialog(); } locations_p->show(); } // Bring up the dialog for "Preferences" menu item CALL_BACK(Config, Preferences) { if (preferences_p == 0) { // first time, create widget preferences_p = new Preferences_dialog(); } preferences_p->show(); } // Bring up dialog for filling in Registration Form CALL_BACK(Config, RegistrationForm) { if (registrationform_p == 0) { // first time, create widget registrationform_p = new RegistrationForm_dialog(); } registrationform_p->show(); fl_message("Note: For fastest service, you can register via\n" "credit card at http://www.arkkra.com/doc/credtcrd.html\n" "rather than filling out and mailing in a paper form."); } // Bring up dialog to let user enter their registration key after paying CALL_BACK(Config, RegistrationKey) { if (registrationkey_p == 0) { // first time, create widget registrationkey_p = new RegistrationKey_dialog(); } registrationkey_p->show(); } // Translate font name to FL_Font value. Fl_Font Config::fontvalue(const char * fontname) { int n; // Linear search of the list (it is short). for (n = 0; n < Fontlistlength; n++) { if (strcmp(Fontlist[n].name, fontname) == 0) { return(Fontlist[n].value); } } // Hmmm. Not found. Should not happen. Hunt for default for (n = 0; n < Fontlistlength; n++) { if (strcmp(Fontlist[n].name, Default_editor_font) == 0) { return(Fontlist[n].value); } } // Wow. Can't find default either. Punt. return(FL_COURIER); } //--------------------- class that lets other classes register a callback // to be called for changes in font/size // List of callbacks for when font/size change Font_change_registration * Font_change_registration::list_p = 0; Font_change_registration::Font_change_registration(Font_change_callback func, void * arg) { // Save callback information. callback = func; callback_arg = arg; // Add to list of callbacks. next = list_p; list_p = this; // Set the font and size on this newly registered widget. // Look up the current values and call the newly registered callback. char * fontstr; (void) Preferences_p->get(Editor_font_preference, fontstr, Default_editor_font); Fl_Font font = Config::fontvalue(fontstr); char * sizestr; (void) Preferences_p->get(Editor_size_preference, sizestr, Default_editor_size); unsigned char size = (unsigned char) atoi(sizestr); if (size < Min_size) { size = (unsigned char) atoi(Default_editor_size); } (*func)(arg, font, size); } Font_change_registration::~Font_change_registration(void) { // Remove callback from linked list if (list_p == this) { list_p = next; } else { Font_change_registration * fcr_p; for (fcr_p = list_p; fcr_p != 0; fcr_p = fcr_p->next) { if (fcr_p->next == this) { fcr_p->next = next; return; } } } } // Notify all classes that want to know about font/size changes, // by calling the callback function they registered. void Font_change_registration::run_callbacks(Fl_Font font, unsigned char size) { // Avoid unreadably small sizes and division by zero if // earlier atoi() of size failed due to bad data // (e.g., user hand-editing the preference file) if (size < Min_size || size > Max_size) { size = (unsigned char) atoi(Default_editor_size); } // Walk through list of registered callbacks, calling each. Font_change_registration * fcr_p; for (fcr_p = list_p; fcr_p != 0; fcr_p = fcr_p->next) { (*(fcr_p->callback))(fcr_p->callback_arg, font, size); } }