Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members   Related Pages  

MainFltkMenu.C

Go to the documentation of this file.
00001 /***************************************************************************
00002  *cr                                                                       
00003  *cr            (C) Copyright 1995-2008 The Board of Trustees of the           
00004  *cr                        University of Illinois                       
00005  *cr                         All Rights Reserved                        
00006  *cr                                                                   
00007  ***************************************************************************/
00008 #include "Inform.h"
00009 
00010 #include "MainFltkMenu.h"
00011 #include "FL/Fl_Menu_Bar.H"
00012 #include "FL/Fl_Menu_Button.H"
00013 #include "FL/Fl_Menu_Item.H"
00014 #include "MolBrowser.h"
00015 #include "frame_selector.h"
00016 #include "FL/Fl_Radio_Button.H"
00017 #include "FL/Fl_Value_Slider.H"
00018 #include "FL/Fl_Int_Input.H"
00019 #include "TextEvent.h"
00020 
00021 #if FL_MAJOR_VERSION <= 1
00022 #if FL_MINOR_VERSION < 1
00023 #include "FL/fl_file_chooser.H"
00024 #endif
00025 #endif
00026 
00027 
00028 #include "FL/forms.H"
00029 
00030 #include "VMDApp.h"
00031 #include "VMDMenu.h"
00032 #include "CommandQueue.h"
00033 #include "CmdMenu.h"
00034 #include "CmdAnimate.h"
00035 #include "Mouse.h"
00036 #include "TextEvent.h"
00037 #include "FPS.h"
00038 #include "Stage.h"
00039 #include "Axes.h"
00040 #include "Scene.h"
00041 #include "Animation.h"
00042 #include "DisplayDevice.h"
00043 #include "PickModeList.h"
00044 
00045 #define EXT_MENU_NAME "Extensions"
00046 
00047 
00048 // Special main window callback to prevent ESC from closing the 
00049 // main window, and tie window closure via mouse to quitting VMD.
00050 void MainFltkMenu::vmd_main_window_cb(Fl_Widget * w, void *) {
00051   MainFltkMenu *m = (MainFltkMenu *)w;
00052 
00053   if (Fl::event_key() == FL_Escape) return; // ignore Escape key
00054 
00055   if (fl_show_question("Really Quit?", 0))
00056     m->app->VMDexit("",0,0);
00057 
00058   // Normal code executed by all other windows is:
00059   // m->app->menu_show(m->get_name(), 0);
00060 }
00061 
00062 // callback for all pulldown menu items that just raise a form
00063 static void menu_cb(Fl_Widget *w, void *v) {
00064   VMDApp *app = (VMDApp *)(w->user_data());
00065   const char *name = (const char *)v;
00066   app->menu_show(name, 0);
00067   app->menu_show(name, 1);
00068 }
00069 
00070 static void loadnew_cb(Fl_Widget *w, void *v) {
00071   VMDApp *app = (VMDApp *)(w->user_data());
00072   app->menu_select_mol("files", -1);
00073   app->menu_show("files", 0);
00074   app->menu_show("files", 1);
00075 }
00076 
00077 void MainFltkMenu::loadfile_cb(Fl_Widget *w, void *v) {
00078   VMDApp *app = (VMDApp *)(w->user_data());
00079   int selmol = ((MainFltkMenu *) v)->get_selected_molecule();
00080   app->menu_select_mol("files", selmol);
00081   app->menu_show("files", 0);
00082   app->menu_show("files", 1);
00083 }
00084 
00085 void MainFltkMenu::savefile_cb(Fl_Widget *w, void *v) {
00086   VMDApp *app = (VMDApp *)(w->user_data());
00087   int selmol = ((MainFltkMenu *) v)->get_selected_molecule();
00088   app->menu_select_mol("save", selmol);
00089   app->menu_show("save", 0);
00090   app->menu_show("save", 1);
00091 }
00092 
00093 static void render_cb(Fl_Widget *w, void *v) {
00094   VMDApp *app = (VMDApp *)(w->user_data());
00095   app->menu_show("render", 0);
00096   app->menu_show("render", 1);
00097 }
00098 
00099 static void savestate_cb(Fl_Widget *w, void *) {
00100   VMDApp *app = (VMDApp *)(w->user_data());
00101   if (!app->save_state()) {
00102     fl_alert("Save State failed.");
00103   }
00104 }
00105 
00106 static void quit_cb(Fl_Widget *w, void *) {
00107   VMDApp *app = (VMDApp *)(w->user_data());
00108   if (fl_show_question("Really Quit?", 0))
00109     app->VMDexit("",0,0);
00110 }
00111   
00112 static void aa_cb(Fl_Widget *w, void *) {
00113   VMDApp *app = (VMDApp *)(w->user_data());
00114   app->display_set_aa(
00115     ((Fl_Menu_ *)w)->mvalue()->value());
00116 }
00117  
00118 static void depthcue_cb(Fl_Widget *w, void *) {
00119   VMDApp *app = (VMDApp *)(w->user_data());
00120   app->display_set_depthcue(
00121     ((Fl_Menu_ *)w)->mvalue()->value());
00122 }
00123 
00124 static void culling_cb(Fl_Widget *w, void *) {
00125   VMDApp *app = (VMDApp *)(w->user_data());
00126   app->display_set_culling(
00127     ((Fl_Menu_ *)w)->mvalue()->value());
00128 }
00129 
00130 static void fps_cb(Fl_Widget *w, void *) {
00131   VMDApp *app = (VMDApp *)(w->user_data());
00132   app->display_set_fps(
00133   ((Fl_Menu_ *)w)->mvalue()->value()); 
00134 }
00135 
00136 static void light_cb(Fl_Widget *w, void *v) {
00137   VMDApp *app = (VMDApp *)(w->user_data());
00138   int *whichlight = (int *)v;
00139   int turnon = ((Fl_Menu_ *)w)->mvalue()->value();
00140   app->light_on(*whichlight, turnon);
00141 }
00142 
00143 static void stage_cb(Fl_Widget *w, void *v) {
00144   Fl_Menu_ *m = (Fl_Menu_ *)w;
00145   VMDApp *app = (VMDApp *)v;
00146   app->stage_set_location(m->text());
00147 }
00148 
00149 static void axes_cb(Fl_Widget *w, void *v) {
00150   Fl_Menu_ *m = (Fl_Menu_ *)w;
00151   VMDApp *app = (VMDApp *)v;
00152   app->axes_set_location(m->text());
00153 }
00154 
00155 static void backgroundmode_cb(Fl_Widget *w, void *v) {
00156   Fl_Menu_ *m = (Fl_Menu_ *)w;
00157   VMDApp *app = (VMDApp *)(w->user_data());
00158   if (!strcmp("Gradient", m->text())) {
00159     app->display_set_background_mode(1);
00160   } else {
00161     app->display_set_background_mode(0);
00162   }
00163 }
00164 
00165 static void stereo_cb(Fl_Widget *w, void *v) {
00166   Fl_Menu_ *m = (Fl_Menu_ *)w;
00167   VMDApp *app = (VMDApp *)v;
00168   app->display_set_stereo(m->text());
00169 }
00170 
00171 static void cachemode_cb(Fl_Widget *w, void *v) {
00172   Fl_Menu_ *m = (Fl_Menu_ *)w;
00173   VMDApp *app = (VMDApp *)v;
00174   app->display_set_cachemode(m->text());
00175 }
00176 
00177 static void rendermode_cb(Fl_Widget *w, void *v) {
00178   Fl_Menu_ *m = (Fl_Menu_ *)w;
00179   VMDApp *app = (VMDApp *)v;
00180   app->display_set_rendermode(m->text());
00181 }
00182 
00183 static void resetview_cb(Fl_Widget *w, void *) {
00184   VMDApp *app = (VMDApp *)(w->user_data());
00185   app->scene_stoprotation();
00186   app->scene_resetview();
00187 }
00188 
00189 static void stoprotation_cb(Fl_Widget *w, void *) {
00190   VMDApp *app = (VMDApp *)(w->user_data());
00191   app->scene_stoprotation();
00192 }
00193  
00194 static void proj_cb(Fl_Widget *w, void *) {
00195   Fl_Menu_ *m = (Fl_Menu_ *)w;
00196   VMDApp *app = (VMDApp *)(w->user_data());
00197   app->display_set_projection(m->text());
00198 }
00199 
00200 static void mouse_cb(Fl_Widget *w, void *v) {
00201   VMDApp *app = (VMDApp *)(w->user_data());
00202   app->mouse_set_mode(*((int *)v), -1);
00203 }
00204  
00205 static void move_light_cb(Fl_Widget *w, void *v) {
00206   VMDApp *app = (VMDApp *)(w->user_data());
00207   app->mouse_set_mode(Mouse::LIGHT, *((int *)v) );
00208 }
00209 
00210 static void help_cb(Fl_Widget *w, void *v) {
00211   VMDApp *app = (VMDApp *)(w->user_data());
00212   app->commandQueue->runcommand(new HelpEvent((const char*)v));
00213 }
00214 
00215 // edit menu callbacks
00216 static void mol_top_cb(Fl_Widget *w, void *v) {
00217   VMDApp *app = (VMDApp *)w->user_data();
00218   MolBrowser *browser = (MolBrowser *)v;
00219   for (int i=0; i<browser->size(); i++) {
00220     if (browser->selected(i+1)) {
00221       app->molecule_make_top(app->molecule_id(i));
00222       break;
00223     }
00224   }
00225 }
00226 
00227 static void mol_active_cb(Fl_Widget *w, void *v) {
00228   VMDApp *app = (VMDApp *)w->user_data();
00229   MolBrowser *browser = (MolBrowser *)v;
00230   for (int i=0; i<browser->size(); i++) {
00231     if (browser->selected(i+1)) {
00232       int molid = app->molecule_id(i);
00233       app->molecule_activate(molid, !app->molecule_is_active(molid));
00234     }
00235   }
00236 }
00237 
00238 static void mol_displayed_cb(Fl_Widget *w, void *v) {
00239   VMDApp *app = (VMDApp *)w->user_data();
00240   MolBrowser *browser = (MolBrowser *)v;
00241   for (int i=0; i<browser->size(); i++) {
00242     if (browser->selected(i+1)) {
00243       int molid = app->molecule_id(i);
00244       app->molecule_display(molid, !app->molecule_is_displayed(molid));
00245     }
00246   }
00247 }
00248   
00249 static void mol_fixed_cb(Fl_Widget *w, void *v) {
00250   VMDApp *app = (VMDApp *)w->user_data();
00251   MolBrowser *browser = (MolBrowser *)v;
00252   for (int i=0; i<browser->size(); i++) {
00253     if (browser->selected(i+1)) {
00254       int molid = app->molecule_id(i);
00255       app->molecule_fix(molid, !app->molecule_is_fixed(molid));
00256     }
00257   }
00258 }
00259 
00260 
00261 static void mol_rename_cb(Fl_Widget *w, void *v) {
00262   VMDApp *app = (VMDApp *)w->user_data();
00263   MolBrowser *browser = (MolBrowser *)v;
00264   int molid=-1;
00265   for (int i=0; i<browser->size(); i++)
00266     if (browser->selected(i+1)) {
00267       molid = app->molecule_id(i);
00268       break;
00269     }
00270   if (molid < 0) return;
00271   
00272   // this code snippet is replicated in MolBrowser.C:
00273   const char *oldname = app->molecule_name(molid);
00274   const char *newname = fl_input("Enter a new name for molecule %d:", 
00275       oldname, molid);
00276   if (newname) app->molecule_rename(molid, newname);
00277 }
00278   
00279   
00280 static void mol_cancel_cb(Fl_Widget *w, void *v) {
00281   VMDApp *app = (VMDApp *)w->user_data();
00282   MolBrowser *browser = (MolBrowser *)v;
00283   for (int i=0; i<browser->size(); i++) {
00284     if (browser->selected(i+1)) {
00285       int molid = app->molecule_id(i);
00286       app->molecule_cancel_io(molid);
00287     }
00288   }
00289 }
00290 
00291 static void mol_delete_ts_cb(Fl_Widget *w, void *v) {
00292   VMDApp *app = (VMDApp *)w->user_data();
00293   MolBrowser *browser = (MolBrowser *)v;
00294   int molid=-1;
00295   for (int i=0; i<browser->size(); i++)
00296     if (browser->selected(i+1)) {
00297       molid = app->molecule_id(i);
00298       break;
00299     }
00300   if (molid < 0) return;
00301   
00302   // this code snippet is replicated in MolBrowser.C:
00303   int numframes = app->molecule_numframes(molid);
00304   if (!numframes) {
00305     fl_alert("Molecule %d has no frames to delete!", molid);
00306   } else {
00307     const char *molname = app->molecule_name(molid);
00308     int first=0, last=numframes-1, stride=0;
00309     int ok = frame_delete_selector(molname, last, &first, &last, &stride);
00310     if (ok) app->molecule_deleteframes(molid, first, last, stride);
00311   }
00312 }
00313 
00314 static void mol_delete_cb(Fl_Widget *w, void *v) {
00315   VMDApp *app = (VMDApp *)w->user_data();
00316   MolBrowser *browser = (MolBrowser *)v;
00317   ResizeArray<int> idlist;
00318   for (int i=0; i<browser->size(); i++) {
00319     if (browser->selected(i+1)) {
00320       idlist.append(app->molecule_id(i));
00321     }
00322   }
00323   for (int j=0; j<idlist.num(); j++)
00324     app->molecule_delete(idlist[j]);
00325 }
00326 
00327 static void loadstate_cb(Fl_Widget *w, void *v) {
00328   VMDApp *app = (VMDApp *)w->user_data();
00329   char *file = app->vmd_choose_file(
00330     "Enter filename containing VMD saved state:",  // Title
00331     "*.vmd",                                      // extension
00332     "VMD files",                                  // label
00333     0                                             // do_save
00334   );
00335   if (!file) return;
00336   char *buf = new char[strlen(file)+10];
00337   sprintf(buf, "play {%s}", file);
00338   app->commandQueue->runcommand(new TclEvalEvent(buf));
00339   delete [] buf;
00340   delete [] file;
00341 }
00342   
00343 
00344 // the menu behavior describes whether or not the menu item require a 
00345 // molecule(s) to exist or be selected in the main browser or not, in order 
00346 // to be active. The fields need to be in the same order as they appear in 
00347 // the menu description.
00348 
00349 static const MenuBehavior file_menu_behavior[] = {
00350   MENU_ALWAYS_ON,           // new
00351   MENU_NEED_UNIQUE_SEL,     // load file
00352   MENU_NEED_UNIQUE_SEL,     // save file
00353   MENU_ALWAYS_ON,           // load state
00354   MENU_ALWAYS_ON,           // save state
00355   MENU_ALWAYS_ON,           // render
00356   MENU_ALWAYS_ON            // quit
00357 };
00358 
00359 // Note: the user_data (i.e. callback argument) for all file_menu items 
00360 // will be reset to the "this" MainFltkMenu object instance.
00361 static const Fl_Menu_Item init_file_menuitems[] = {
00362   {"New Molecule...",            0, loadnew_cb    },
00363   {"Load Data Into Molecule...", 0, NULL /* set later */},
00364   {"Save Coordinates...",        0, NULL /* set later */,  NULL,   FL_MENU_DIVIDER},
00365   {"Load State...",          0, loadstate_cb  },
00366   {"Save State...",          0, savestate_cb, NULL,   FL_MENU_DIVIDER},
00367   {"Render...",                  0, render_cb,    },
00368   {"Quit",                       0, quit_cb       },
00369   {NULL}
00370 };
00371 
00372 static const MenuBehavior molecule_menu_behavior[] = {
00373   MENU_NEED_UNIQUE_SEL,     // top
00374   MENU_NEED_SEL,            // active
00375   MENU_NEED_SEL,            // displayed
00376   MENU_NEED_SEL,            // fixed
00377   MENU_NEED_UNIQUE_SEL,     // rename
00378   MENU_NEED_UNIQUE_SEL,     // delete ts
00379   MENU_NEED_SEL,            // cancel file i/o
00380   MENU_NEED_SEL             // delete mol
00381 };
00382 
00383 // Note: the user_data (i.e. callback argument) for all molecule_menu items 
00384 // will be reset to this->browser.
00385 static const Fl_Menu_Item init_molecule_menuitems[] = {
00386   {"Make Top",          0, mol_top_cb,       }, 
00387   {"Toggle Active",     0, mol_active_cb,    },
00388   {"Toggle Displayed",  0, mol_displayed_cb, },
00389   {"Toggle Fixed",      0, mol_fixed_cb,     NULL,   FL_MENU_DIVIDER},
00390   {"Rename...",         0, mol_rename_cb     },
00391   {"Delete Frames...",  0, mol_delete_ts_cb  },
00392   {"Abort File I/O",    0, mol_cancel_cb,    },
00393   {"Delete Molecule",   0, mol_delete_cb     },
00394   {NULL}
00395 };
00396 
00397 
00398 static const MenuBehavior browserpopup_menu_behavior[] = {
00399   MENU_ALWAYS_ON,           // new
00400   MENU_NEED_UNIQUE_SEL,     // load file
00401   MENU_NEED_UNIQUE_SEL,     // save file
00402   MENU_NEED_UNIQUE_SEL,     // rename
00403   MENU_NEED_UNIQUE_SEL,     // delete ts
00404   MENU_NEED_SEL,            // cancel file i/o
00405   MENU_NEED_SEL             // delete mol
00406 };
00407 
00408 // Note: the user_data (i.e. callback argument) for all molecule_menu items 
00409 // will be reset to this->browser.
00410 static const Fl_Menu_Item init_browserpopup_menuitems[] = {
00411   // Here: user_data will be set to (MainFltkMenu*) this.
00412   {"New Molecule...",            0, loadnew_cb    },
00413   {"Load Data Into Molecule...", 0, NULL /* set later */},
00414   {"Save Coordinates...",        0, NULL /* set later */,  NULL, FL_MENU_DIVIDER},
00415   // Here: user_data will be set to this->browser
00416   {"Rename...",         0, mol_rename_cb     },
00417   {"Delete Frames...",  0, mol_delete_ts_cb  },
00418   {"Abort File I/O",    0, mol_cancel_cb,    },
00419   {"Delete Molecule",   0, mol_delete_cb     },
00420   {NULL}
00421 };
00422 
00423 static const Fl_Menu_Item graphics_menuitems[] = {
00424   {"Representations...", 0, menu_cb, (void *)"graphics"},
00425   {"Colors...", 0, menu_cb, (void *)"color"},
00426   {"Materials...", 0, menu_cb, (void *)"material"},
00427   {"Labels...", 0, menu_cb, (void *)"labels", FL_MENU_DIVIDER},
00428   {"Tools...", 0, menu_cb, (void *)"tool"}, 
00429   {0}
00430 };
00431 
00432 static int cbdata[] = {
00433   0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22
00434 };
00435 
00436 static const Fl_Menu_Item init_display_menuitems[] = {
00437   {"Reset View", '=', resetview_cb},
00438   {"Stop Rotation", 0, stoprotation_cb, NULL, FL_MENU_DIVIDER},
00439   {"Perspective", 0, proj_cb, NULL, FL_MENU_RADIO },
00440   {"Orthographic", 0, proj_cb, NULL, FL_MENU_RADIO | FL_MENU_DIVIDER},
00441   {"Antialiasing", 0, aa_cb, NULL, FL_MENU_TOGGLE  | FL_MENU_INACTIVE},
00442   {"Depth Cueing", 0, depthcue_cb, NULL, FL_MENU_TOGGLE | FL_MENU_INACTIVE},
00443   {"Culling", 0, culling_cb, NULL, FL_MENU_TOGGLE | FL_MENU_INACTIVE},
00444   {"FPS Indicator", 0, fps_cb, NULL, FL_MENU_TOGGLE | FL_MENU_DIVIDER},
00445   {"Light 0", 0, light_cb, cbdata+0, FL_MENU_TOGGLE},
00446   {"Light 1", 0, light_cb, cbdata+1, FL_MENU_TOGGLE},
00447   {"Light 2", 0, light_cb, cbdata+2, FL_MENU_TOGGLE},
00448   {"Light 3", 0, light_cb, cbdata+3, FL_MENU_TOGGLE | FL_MENU_DIVIDER},
00449   {"Axes",   0, NULL, NULL, FL_SUBMENU_POINTER},
00450   {"Background", 0, backgroundmode_cb, NULL, FL_SUBMENU_POINTER},
00451   {"Stage",   0, NULL, NULL, FL_SUBMENU_POINTER},
00452   {"Stereo",  0, NULL, NULL, FL_SUBMENU_POINTER | FL_MENU_DIVIDER},
00453   {"Cachemode", 0, NULL, NULL, FL_SUBMENU_POINTER},
00454   {"Rendermode", 0, NULL, NULL, FL_SUBMENU_POINTER | FL_MENU_DIVIDER},
00455   {"Display Settings...", 0, menu_cb, (void *)"display"},
00456   {0}
00457 };
00458 
00459 // forward declaration
00460 static void cb_cb(Fl_Widget *w, void *v); 
00461 
00462 // These are the items that appear in the mouse submenu.  
00463 // If items are added or removed from this menu, the update_mousemode method
00464 // must be updated to reflect the new positions if the items.
00465 static const Fl_Menu_Item init_mouse_menuitems[] = {
00466   {"Rotate Mode", 'r', mouse_cb, cbdata+Mouse::ROTATION,FL_MENU_RADIO|FL_MENU_VALUE},
00467   {"Translate Mode",'t',mouse_cb,cbdata+Mouse::TRANSLATION,FL_MENU_RADIO},
00468   {"Scale Mode", 's', mouse_cb,  cbdata+Mouse::SCALING, FL_MENU_RADIO | FL_MENU_DIVIDER},
00469   {"Center", 'c', mouse_cb,      cbdata+Mouse::CENTER, FL_MENU_RADIO},
00470   {"Query", '0', mouse_cb,       cbdata+Mouse::QUERY,  FL_MENU_RADIO},
00471       
00472   {"Label",0,cb_cb,0, FL_SUBMENU | FL_MENU_TOGGLE },
00473     {"Atoms", '1', mouse_cb,     cbdata+Mouse::LABELATOM, FL_MENU_RADIO},
00474     {"Bonds", '2', mouse_cb,     cbdata+Mouse::LABELBOND, FL_MENU_RADIO},
00475     {"Angles", '3', mouse_cb,    cbdata+Mouse::LABELANGLE, FL_MENU_RADIO},
00476     {"Dihedrals", '4', mouse_cb, cbdata+Mouse::LABELDIHEDRAL, FL_MENU_RADIO},
00477     {0},
00478   {"Move",0,cb_cb,0, FL_SUBMENU | FL_MENU_TOGGLE},
00479     {"Atom", '5', mouse_cb,      cbdata+Mouse::MOVEATOM, FL_MENU_RADIO},
00480     {"Residue", '6', mouse_cb,   cbdata+Mouse::MOVERES, FL_MENU_RADIO},
00481     {"Fragment", '7', mouse_cb,  cbdata+Mouse::MOVEFRAG, FL_MENU_RADIO},
00482     {"Molecule", '8', mouse_cb,  cbdata+Mouse::MOVEMOL, FL_MENU_RADIO},
00483     {"Rep", '9', mouse_cb,       cbdata+Mouse::MOVEREP, FL_MENU_RADIO},
00484     {0},
00485   {"Force",0,cb_cb,0, FL_SUBMENU | FL_MENU_TOGGLE},
00486     {"Atom", '%', mouse_cb,      cbdata+Mouse::FORCEATOM, FL_MENU_RADIO},
00487     {"Residue", '^', mouse_cb,   cbdata+Mouse::FORCERES, FL_MENU_RADIO},
00488     {"Fragment", '&', mouse_cb,  cbdata+Mouse::FORCEFRAG, FL_MENU_RADIO},
00489     {0},
00490   {"Move Light", 0,cb_cb,0, FL_SUBMENU | FL_MENU_TOGGLE},
00491     {"0", 0, move_light_cb, cbdata+0, FL_MENU_RADIO},
00492     {"1", 0, move_light_cb, cbdata+1, FL_MENU_RADIO},
00493     {"2", 0, move_light_cb, cbdata+2, FL_MENU_RADIO},
00494     {"3", 0, move_light_cb, cbdata+3, FL_MENU_RADIO},
00495     {0},
00496   {"Add/Remove Bonds", 0, mouse_cb, cbdata+Mouse::ADDBOND, FL_MENU_RADIO},
00497   {"Pick", 'p', mouse_cb,        cbdata+Mouse::PICK,    FL_MENU_RADIO},
00498   {0}
00499 };
00500 
00501 static const Fl_Menu_Item init_help_menuitems[] = {
00502   {"Quick Help",        0, help_cb, (void*) "quickhelp"},
00503   {"User's Guide",        0, help_cb, (void*) "userguide"},
00504   {"Tutorial",        0, help_cb, (void*) "tutorial", FL_MENU_DIVIDER},
00505   {"Homepage",          0, help_cb, (void*) "homepage"},
00506   {"FAQ",               0, help_cb, (void*) "faq"},
00507   {"Mailing List",      0, help_cb, (void*) "maillist"},
00508   {"Script Library",    0, help_cb, (void*) "scripts"},
00509   {"Plugin Library",    0, help_cb, (void*) "plugins", FL_MENU_DIVIDER},
00510   {"Related Software",  0, help_cb, (void*) "software"},
00511   {"3D Renderers",      0, 0, 0, FL_SUBMENU},
00512     {"POV-Ray",         0, help_cb, (void*) "povray"},
00513     {"Radiance",        0, help_cb, (void*) "radiance"},
00514     {"Raster3D",        0, help_cb, (void*) "raster3D"},
00515     {"Rayshade",        0, help_cb, (void*) "rayshade"},
00516     {"Tachyon",         0, help_cb, (void*) "tachyon"},
00517     {"VRML",            0, help_cb, (void*) "vrml"},
00518     {0},
00519   {"Auxiliary Programs", 0, 0, 0, FL_SUBMENU},
00520     {"Babel",             0, help_cb, (void*) "babel"},
00521     {"BioCoRE",           0, help_cb, (void*) "biocore"},
00522     {"MSMS",              0, help_cb, (void*) "msms"},
00523     {"NAMD",              0, help_cb, (void*) "namd"},
00524     {"Tcl/Tk",            0, help_cb, (void*) "tcl"},
00525     {"Python",            0, help_cb, (void*) "python"},
00526     {0},
00527   {0}
00528 };
00529 
00530 // turn the item on if any of its children are on; otherwise restore it
00531 // to its off state.
00532 static void cb_cb(Fl_Widget *w, void *v) {
00533   Fl_Menu_Item *titleitem = (Fl_Menu_Item*) ((Fl_Menu_ *)w)->mvalue();
00534   const Fl_Menu_Item *item;
00535   for (item = titleitem+1; item->label(); item++)
00536     if (item->value()) {
00537       titleitem->set();
00538       return;
00539     }
00540   titleitem->clear();
00541 }
00542     
00543 void MainFltkMenu::frameslider_cb(Fl_Widget *w, void *v) {
00544   Fl_Valuator *val = (Fl_Valuator *)w;
00545   MainFltkMenu *self = (MainFltkMenu *)v;
00546   // If the right mouse button is active, update frame only on release...
00547   //if (Fl::event_button() == FL_RIGHT_MOUSE) {  XXX wrong way to do it
00548   if (Fl::event_state(FL_BUTTON3)) {
00549     if (!Fl::event_state()) {
00550       self->app->animation_set_frame((int)val->value());
00551     } else {
00552       // but still update the value displayed in the current frame.
00553       char buf[10];
00554       sprintf(buf, "%d", (int)val->value());
00555       self->curframe->value(buf);
00556     }
00557   } else {
00558     self->app->animation_set_frame((int)val->value());
00559   }
00560 }
00561 
00562 static void curframe_cb(Fl_Widget *w, void *v) {
00563   Fl_Input *inp = (Fl_Input *)w;
00564   VMDApp *app = (VMDApp *)v;
00565   int val = atoi(inp->value());
00566   int max = app->molecule_numframes(app->molecule_top());
00567   if (val < 0) val = 0;
00568   if (val >= max) val = max-1;
00569   app->animation_set_frame(val);
00570 }
00571 
00572 static void start_cb(Fl_Widget *, void *v) {
00573   VMDApp *app = (VMDApp *)v;
00574   app->animation_set_frame(-1);
00575 }
00576 
00577 static void stop_cb(Fl_Widget *, void *v) {
00578   VMDApp *app = (VMDApp *)v;
00579   app->animation_set_frame(-2);
00580 }
00581 
00582 static void prev_cb(Fl_Widget *, void *v) {
00583   VMDApp *app = (VMDApp *)v;
00584   app->animation_set_dir(Animation::ANIM_REVERSE1);
00585 }
00586 
00587 static void next_cb(Fl_Widget *, void *v) {
00588   VMDApp *app = (VMDApp *)v;
00589   app->animation_set_dir(Animation::ANIM_FORWARD1);
00590 }
00591 
00592 static void forward_cb(Fl_Widget *w, void *v) {
00593   Fl_Button *button = (Fl_Button *)w;
00594   VMDApp *app = (VMDApp *)v;
00595   if (button->value())
00596     app->animation_set_dir(Animation::ANIM_FORWARD);
00597   else
00598     app->animation_set_dir(Animation::ANIM_PAUSE);
00599 }
00600 
00601 static void reverse_cb(Fl_Widget *w, void *v) {
00602   Fl_Button *button = (Fl_Button *)w;
00603   VMDApp *app = (VMDApp *)v;
00604   if (button->value())
00605     app->animation_set_dir(Animation::ANIM_REVERSE);
00606   else
00607     app->animation_set_dir(Animation::ANIM_PAUSE);
00608 }
00609 
00610 static void style_cb(Fl_Widget *w, void *v) {
00611   Fl_Choice *choice = (Fl_Choice *)w;
00612   VMDApp *app = (VMDApp *)v;
00613   app->animation_set_style(choice->value());
00614 }
00615 
00616 static void step_cb(Fl_Widget *w, void *v) {
00617   Fl_Counter *counter = (Fl_Counter *)w;
00618   VMDApp *app = (VMDApp *)v;
00619   app->animation_set_stride((int)counter->value());
00620 }
00621 
00622 static void speed_cb(Fl_Widget *w, void *v) {
00623   Fl_Slider *slider = (Fl_Slider *)w;
00624   VMDApp *app = (VMDApp *)v;
00625   app->animation_set_speed((float) slider->value());
00626 }
00627 
00628 void MainFltkMenu::zoom_cb(Fl_Widget *w, void *v) {
00629   Fl_Button *b = (Fl_Button *)w;
00630   MainFltkMenu *self = (MainFltkMenu *)v;
00631   int numframes = self->app->molecule_numframes(self->app->molecule_top());
00632   if (numframes < 1) return;
00633   double full_range = (double)numframes;
00634   if (b->value()) {
00635     // turn on zoom: recenter the range around the current value of the slider
00636     double pixel_range = 100;
00637     if (full_range > pixel_range) {
00638       double curval = self->frameslider->value();
00639       double curfrac = curval/full_range;
00640       self->frameslider->range(curval - pixel_range*curfrac,
00641                                curval + pixel_range*(1.0-curfrac));
00642       self->frameslider->color(FL_WHITE, FL_RED);
00643       self->frameslider->redraw();
00644     }
00645   } else {
00646     // turn off zoom; make the range equal to the number of frames
00647     self->frameslider->range(0, full_range-1);
00648     self->frameslider->color(FL_WHITE, FL_BLACK);
00649     self->frameslider->redraw();
00650   }
00651 }
00652 
00653 void MainFltkMenu::update_mousemode(Command *cmd) {
00654   int mode = ((CmdMouseMode *)cmd)->mouseMode;
00655   int setting = ((CmdMouseMode *)cmd)->mouseSetting;
00656   
00657   Fl_Menu_Item *items = mouse_menuitems;
00658   int menulen = sizeof(init_mouse_menuitems)/sizeof(Fl_Menu_Item);
00659   for (int j=0; j<menulen; j++) // replaced hard-coded <=29 with <menulen
00660     items[j].clear();
00661 
00662   switch(mode) {
00663     case Mouse::ROTATION:      items[ 0].setonly(); break;
00664     case Mouse::TRANSLATION:   items[ 1].setonly(); break;
00665     case Mouse::SCALING:       items[ 2].setonly(); break;
00666     case Mouse::QUERY:         items[ 4].setonly(); break;
00667     case Mouse::CENTER:        items[ 3].setonly(); break;
00668     case Mouse::LABELATOM:     items[ 6].setonly(); break;
00669     case Mouse::LABELBOND:     items[ 7].setonly(); break;
00670     case Mouse::LABELANGLE:    items[ 8].setonly(); break;   
00671     case Mouse::LABELDIHEDRAL: items[ 9].setonly(); break;  
00672     case Mouse::MOVEATOM:      items[12].setonly(); break; 
00673     case Mouse::MOVERES:       items[13].setonly(); break; 
00674     case Mouse::MOVEFRAG:      items[14].setonly(); break;  
00675     case Mouse::MOVEMOL:       items[15].setonly(); break; 
00676     case Mouse::MOVEREP:       items[16].setonly(); break; 
00677     case Mouse::FORCEATOM:     items[19].setonly(); break; 
00678     case Mouse::FORCERES:      items[20].setonly(); break; 
00679     case Mouse::FORCEFRAG:     items[21].setonly(); break; 
00680     case Mouse::ADDBOND:       items[29].setonly(); break; 
00681     case Mouse::PICK:          items[30].setonly(); break;
00682     case Mouse::LIGHT:
00683       switch (setting) {
00684         case 0: items[24].setonly(); break;
00685         case 1: items[25].setonly(); break;
00686         case 2: items[26].setonly(); break;
00687         case 3: items[27].setonly(); break;
00688       }
00689   }
00690   if (mode >= Mouse::PICK) {
00691     items[0].setonly();  // check "rotate" mouse mode
00692     if (mode == Mouse::LABELATOM  || mode == Mouse::LABELBOND || \
00693         mode == Mouse::LABELANGLE || mode == Mouse::LABELDIHEDRAL)
00694       items[5].set();
00695     else if (mode == Mouse::MOVEATOM || mode == Mouse::MOVERES || \
00696              mode == Mouse::MOVEMOL  || mode == Mouse::MOVEREP)
00697       items[11].set();
00698     else if (mode == Mouse::FORCEATOM || mode == Mouse::FORCERES || mode == Mouse::FORCEFRAG)
00699       items[18].set();
00700   } else if (mode == Mouse::LIGHT) {
00701     if (setting >= 0 && setting <= 3) items[23].set();   
00702   }
00703 }
00704 
00705 void MainFltkMenu::update_dispmode() {
00706   const char *projname = app->display->get_projection();
00707   for (int ii=2; ii<=3; ii++) {
00708     if (!strupcmp(projname, display_menuitems[ii].label())) {
00709       display_menuitems[ii].setonly();
00710       break;
00711     }
00712   }
00713   if (app->display->aa_enabled()) 
00714     display_menuitems[4].set();
00715   else
00716     display_menuitems[4].clear();
00717 
00718   if (app->display->cueing_enabled()) 
00719     display_menuitems[5].set();
00720   else
00721     display_menuitems[5].clear();
00722 
00723   if (app->display->culling_enabled()) 
00724     display_menuitems[6].set();
00725   else
00726     display_menuitems[6].clear();
00727 
00728   if (app->fps->displayed()) 
00729     display_menuitems[7].set();
00730   else
00731     display_menuitems[7].clear();
00732 
00733   for (int j=0; j<4; j++)
00734     if (app->scene->light_active(j))
00735       display_menuitems[8+j].set();
00736     else
00737       display_menuitems[8+j].clear();
00738 
00739   axes_menuitems[app->axes->location()].setonly();
00740   backgroundmode_menuitems[app->scene->background_mode()].setonly();
00741   stage_menuitems[app->stage->location()].setonly();
00742   stereo_menuitems[app->display->stereo_mode()].setonly();
00743   cachemode_menuitems[app->display->cache_mode()].setonly();
00744   rendermode_menuitems[app->display->render_mode()].setonly();
00745 } 
00746     
00747     
00748 // Add some extra space at the bottom of the menu for the OSX resizing tab;
00749 // otherwise it obscures buttons on the menu.
00750 #if defined(ARCH_MACOSX) || defined(ARCH_MACOSXX86) || defined(ARCH_MACOSXX86_64)
00751 #define MAINFLTKMENUHEIGHT 205
00752 #else
00753 #define MAINFLTKMENUHEIGHT 190
00754 #endif
00755 
00756 MainFltkMenu::MainFltkMenu(VMDApp *vmdapp)
00757 : VMDFltkMenu("main", "VMD Main", vmdapp) {
00758   size(450,MAINFLTKMENUHEIGHT);
00759   size_range(450,MAINFLTKMENUHEIGHT,450,0); // resizable in y but not in x.
00760   command_wanted(Command::MOL_NEW);
00761   command_wanted(Command::MOL_DEL);
00762   command_wanted(Command::MOL_ACTIVE);
00763   command_wanted(Command::MOL_ON);
00764   command_wanted(Command::MOL_RENAME);
00765   command_wanted(Command::MOL_FIX);
00766   command_wanted(Command::MOL_TOP);
00767   command_wanted(Command::MOL_VOLUME);
00768   command_wanted(Command::ANIM_JUMP);
00769   command_wanted(Command::ANIM_NEW_FRAME);
00770   command_wanted(Command::ANIM_NEW_NUM_FRAMES);
00771   command_wanted(Command::MOUSE_MODE);
00772   command_wanted(Command::MENU_TK_ADD);
00773   command_wanted(Command::MENU_TK_REMOVE);
00774   command_wanted(Command::ANIM_STYLE);
00775   command_wanted(Command::ANIM_SKIP);
00776   command_wanted(Command::ANIM_SPEED);
00777   command_wanted(Command::ANIM_DIRECTION);
00778   command_wanted(Command::ANIM_JUMP);
00779 
00780   command_wanted(Command::DISP_DEPTHCUE);
00781   command_wanted(Command::DISP_CULLING);
00782   command_wanted(Command::DISP_ANTIALIAS);
00783   command_wanted(Command::DISP_FPS);
00784   command_wanted(Command::DISP_LIGHT_ON);
00785   command_wanted(Command::CMD_STAGE);
00786   command_wanted(Command::CMD_AXES);
00787   command_wanted(Command::DISP_BACKGROUNDGRADIENT);
00788   command_wanted(Command::DISP_PROJ);
00789   command_wanted(Command::DISP_STEREO);
00790   command_wanted(Command::DISP_CACHEMODE);
00791   command_wanted(Command::DISP_RENDERMODE);
00792 
00793   browser = new MolBrowser(vmdapp, this, 0, 60);
00794 
00795   // ******** CREATE MENUS *********
00796   // We make copies of the static data because we will be changing the state
00797   // and contents of some menus and menu items.
00798   
00799   int menulen;
00800   Fl_Menu_Item nullitem = {NULL};
00801      
00802   // create menu instances and fill in user_data fields for menu callback use.
00803   menulen = sizeof(init_file_menuitems)/sizeof(Fl_Menu_Item);
00804   file_menuitems = new Fl_Menu_Item[menulen];
00805   int j;
00806   for (j=0; j<menulen; j++) {
00807     file_menuitems[j] = init_file_menuitems[j];
00808     file_menuitems[j].user_data(this);
00809   }
00810   // these are set here because the are private functions
00811   file_menuitems[1].callback(loadfile_cb);
00812   file_menuitems[2].callback(savefile_cb);
00813         
00814   menulen = sizeof(init_molecule_menuitems)/sizeof(Fl_Menu_Item);
00815   molecule_menuitems = new Fl_Menu_Item[menulen];
00816   for (j=0; j<menulen; j++) {
00817     molecule_menuitems[j] = init_molecule_menuitems[j];
00818     molecule_menuitems[j].user_data(browser);
00819   }
00820   
00821   
00822   // This is the popup menu in the molbrowser window (mix of file and molecule menus)
00823   menulen = sizeof(init_browserpopup_menuitems)/sizeof(Fl_Menu_Item);
00824   browserpopup_menuitems = new Fl_Menu_Item[menulen];
00825   for (j=0; j<3; j++) {
00826     browserpopup_menuitems[j] = init_browserpopup_menuitems[j];
00827     browserpopup_menuitems[j].user_data(this);
00828   }
00829   for (j=3; j<menulen; j++) {
00830     browserpopup_menuitems[j] = init_browserpopup_menuitems[j];
00831     browserpopup_menuitems[j].user_data(browser);
00832   }
00833   // these are set here because the are private functions
00834   browserpopup_menuitems[1].callback(loadfile_cb);
00835   browserpopup_menuitems[2].callback(savefile_cb);
00836 
00837   
00838   menulen = sizeof(init_display_menuitems)/sizeof(Fl_Menu_Item);
00839   display_menuitems = new Fl_Menu_Item[menulen];
00840   for (j=0; j<menulen; j++)
00841     display_menuitems[j] = init_display_menuitems[j];
00842   if (app->display->aa_available()) display_menuitems[4].activate();
00843   if (app->display->cueing_available()) display_menuitems[5].activate();
00844   if (app->display->culling_available()) display_menuitems[6].activate();
00845   
00846   menulen = app->axes->locations();
00847   axes_menuitems_storage = new Fl_Menu_Item[menulen+2]; 
00848   axes_menuitems_storage[0] = nullitem;   // pad the beginning of the array 
00849                                           // to prevent an Fltk crash
00850   axes_menuitems = axes_menuitems_storage+1; 
00851   for (j=0; j<menulen; j++) {
00852     Fl_Menu_Item item = {app->axes->loc_description(j), 0, axes_cb, app, FL_MENU_RADIO};
00853     axes_menuitems[j] = item;
00854   }
00855   axes_menuitems[menulen] = nullitem;
00856   display_menuitems[12].user_data(axes_menuitems);
00857 
00858   menulen = 2;
00859   backgroundmode_menuitems_storage = new  Fl_Menu_Item[menulen+2];
00860   backgroundmode_menuitems_storage[0] = nullitem;
00861   backgroundmode_menuitems = backgroundmode_menuitems_storage+1;
00862   {
00863     Fl_Menu_Item item = { "Solid Color", 0, backgroundmode_cb, app, FL_MENU_RADIO};
00864     backgroundmode_menuitems[0] = item;
00865   }
00866   {
00867     Fl_Menu_Item item = { "Gradient", 0, backgroundmode_cb, app, FL_MENU_RADIO};
00868     backgroundmode_menuitems[1] = item;
00869   }
00870   backgroundmode_menuitems[menulen] = nullitem;
00871   display_menuitems[13].user_data(backgroundmode_menuitems);
00872  
00873   menulen = app->stage->locations();
00874   stage_menuitems_storage = new Fl_Menu_Item[menulen+2]; 
00875   stage_menuitems_storage[0] = nullitem;
00876   stage_menuitems = stage_menuitems_storage+1;  
00877   for (j=0; j<menulen; j++) {
00878     Fl_Menu_Item item = {app->stage->loc_description(j), 0, stage_cb, app, FL_MENU_RADIO};  
00879     stage_menuitems[j] = item;
00880   }
00881   stage_menuitems[menulen] = nullitem;
00882   display_menuitems[14].user_data(stage_menuitems);
00883   
00884   menulen = app->display->num_stereo_modes();
00885   stereo_menuitems_storage = new Fl_Menu_Item[menulen+2]; 
00886   stereo_menuitems_storage[0] = nullitem;
00887   stereo_menuitems = stereo_menuitems_storage+1; 
00888   for (j=0; j<menulen; j++) {
00889     Fl_Menu_Item item = {app->display->stereo_name(j), 0, stereo_cb, vmdapp, FL_MENU_RADIO}; 
00890     stereo_menuitems[j] = item;
00891   }
00892   stereo_menuitems[menulen] = nullitem;
00893   display_menuitems[15].user_data(stereo_menuitems);
00894 
00895   menulen = app->display->num_cache_modes();
00896   cachemode_menuitems_storage = new Fl_Menu_Item[menulen+2]; 
00897   cachemode_menuitems_storage[0] = nullitem;
00898   cachemode_menuitems = cachemode_menuitems_storage+1; 
00899   for (j=0; j<menulen; j++) {
00900     Fl_Menu_Item item = {app->display->cache_name(j), 0, cachemode_cb, vmdapp, FL_MENU_RADIO}; 
00901     cachemode_menuitems[j] = item;
00902   }
00903   cachemode_menuitems[menulen] = nullitem;
00904   display_menuitems[16].user_data(cachemode_menuitems);
00905   
00906   menulen = app->display->num_render_modes();
00907   rendermode_menuitems_storage = new Fl_Menu_Item[menulen+2]; 
00908   rendermode_menuitems_storage[0] = nullitem;
00909   rendermode_menuitems = rendermode_menuitems_storage+1; 
00910   for (j=0; j<menulen; j++) {
00911     Fl_Menu_Item item = {app->display->render_name(j), 0, rendermode_cb, vmdapp, FL_MENU_RADIO}; 
00912     rendermode_menuitems[j] = item;
00913   }
00914   rendermode_menuitems[menulen] = nullitem;
00915   display_menuitems[17].user_data(rendermode_menuitems);
00916 
00917   update_dispmode();
00918 
00919   menulen = sizeof(init_mouse_menuitems)/sizeof(Fl_Menu_Item);
00920   mouse_menuitems_storage = new Fl_Menu_Item[menulen+2]; 
00921   mouse_menuitems_storage[0] = nullitem;
00922   mouse_menuitems = mouse_menuitems_storage+1; 
00923   for (j=0; j<menulen; j++)
00924     mouse_menuitems[j] = init_mouse_menuitems[j];
00925 
00926   
00927   // ******** CREATE MENU BAR *********
00928   menubar = new Fl_Menu_Bar(0,0,450,30);
00929   menubar->add("File",0,0,(void *)file_menuitems,FL_SUBMENU_POINTER);
00930   menubar->add("Molecule",0,0,(void *)molecule_menuitems,FL_SUBMENU_POINTER);
00931   menubar->add("Graphics",0,0,(void *)graphics_menuitems, FL_SUBMENU_POINTER);
00932   menubar->add("Display",0,0,(void*)display_menuitems, FL_SUBMENU_POINTER);
00933   menubar->add("Mouse",0,0,(void *)mouse_menuitems, FL_SUBMENU_POINTER);
00934   menubar->add(EXT_MENU_NAME,0,0, NULL, FL_SUBMENU);
00935   menubar->add("Help",0,0,(void *)init_help_menuitems, FL_SUBMENU_POINTER);
00936   menubar->user_data(vmdapp);
00937   menubar->selection_color(FL_BLACK);
00938 
00939   // ******** CREATE CONTROLS *********
00940   Fl_Group::current()->resizable(browser);
00941 
00942   Fl_Button *b;
00943   int bwidth = 20, bheight = 20;
00944   b = new Fl_Button(0,150,bwidth,bheight,"@4->|");
00945   b->labeltype(FL_SYMBOL_LABEL);
00946   b->callback(start_cb, app);
00947   reverse = new Fl_Button(0,150+bheight,bwidth,bheight,"@<");
00948   reverse->labeltype(FL_SYMBOL_LABEL);
00949   reverse->type(FL_TOGGLE_BUTTON);
00950   reverse->callback(reverse_cb, app);
00951   b = new Fl_Button(bwidth,150+bheight,bwidth,bheight,"@<|");
00952   b->labeltype(FL_SYMBOL_LABEL);
00953   b->callback(prev_cb, app);
00954   b = new Fl_Button(450-bwidth,150,bwidth,bheight,"@->|");
00955   b->labeltype(FL_SYMBOL_LABEL);
00956   b->callback(stop_cb, app);
00957   forward = new Fl_Button(450-bwidth,150+bheight,bwidth,bheight,"@>");
00958   forward->labeltype(FL_SYMBOL_LABEL);
00959   forward->type(FL_TOGGLE_BUTTON);
00960   forward->callback(forward_cb, app);
00961   b = new Fl_Button(450-2*bwidth,150+bheight,bwidth,bheight,"@|>");
00962   b->labeltype(FL_SYMBOL_LABEL);
00963   b->callback(next_cb, app);
00964   
00965   curframe = new Fl_Int_Input(bwidth,150, 2*bwidth, bheight);
00966   curframe->textsize(12);
00967   curframe->callback(curframe_cb, app);
00968   curframe->when(FL_WHEN_ENTER_KEY);
00969   //curframe->selection_color(FL_YELLOW);
00970   curframe->selection_color(FL_BLACK);
00971 
00972   frameslider = new Fl_Slider(3*bwidth, 150,450-4*bwidth, bheight);
00973   frameslider->type(FL_HOR_NICE_SLIDER);
00974   frameslider->step(1,1);
00975   frameslider->callback(frameslider_cb, this);
00976   frameslider->color(FL_WHITE, FL_BLACK);
00977   frameslider->when(FL_WHEN_CHANGED | FL_WHEN_RELEASE);
00978 
00979   step = new Fl_Counter(220,150+bheight, 45,bheight, "step");
00980   step->labelsize(12);
00981   step->type(FL_SIMPLE_COUNTER);
00982   step->step(1,1);
00983   step->minimum(1);
00984   step->value(1);
00985   step->callback(step_cb, app);
00986   step->align(FL_ALIGN_LEFT);
00987 
00988   style = new Fl_Choice(120, 150+bheight, 65, bheight);
00989   style->textsize(12);
00990   style->selection_color(FL_BLACK);
00991   style->box(FL_THIN_UP_BOX);
00992   for (int s=0; s<Animation::ANIM_TOTAL_STYLES; s++)
00993     style->add(animationStyleName[s]);
00994 
00995   // XXX The Animation class starts with ANIM_LOOP as its style, so that's
00996   // what we do, too.
00997   style->value(1);
00998   style->callback(style_cb, app);
00999 
01000   zoom = new Fl_Check_Button(80, 150+bheight-2, bwidth+5, bheight+5, "zoom");
01001   zoom->labelsize(12);
01002   zoom->align(FL_ALIGN_LEFT);
01003   zoom->value(0);
01004   //zoom->selection_color(FL_RED);
01005   zoom->color(FL_BLACK, FL_RED);
01006   zoom->callback(zoom_cb, this);
01007 
01008   speed = new Fl_Slider(315, 150+bheight, 90, bheight, "speed");
01009   speed->labelsize(12);
01010   speed->type(FL_HORIZONTAL);
01011   speed->color(FL_WHITE, FL_BLACK);
01012   speed->value(1.0);
01013   speed->callback(speed_cb, app);
01014   speed->align(FL_ALIGN_LEFT);
01015 
01016   guistate = UNDEFINED;
01017   update_gui_state();
01018 
01019   callback(vmd_main_window_cb); // override default FLTK/VMD global handlers
01020           
01021   Fl_Window::end();
01022 }
01023  
01024 int MainFltkMenu::act_on_command(int type, Command *cmd) {
01025   if (type == Command::MOL_NEW) {
01026     // XXX force set of anim style to the current GUI setting
01027     // when new molecules are loaded, since they get the default otherwise
01028     app->animation_set_style(style->value());
01029   } 
01030 
01031   if (type == Command::MOL_ACTIVE || 
01032       type == Command::MOL_ON ||
01033       type == Command::MOL_FIX  || 
01034       type == Command::MOL_NEW ||
01035       type == Command::MOL_RENAME ||
01036       type == Command::MOL_VOLUME ||
01037       type == Command::ANIM_NEW_NUM_FRAMES ||
01038       type == Command::MOL_DEL ||
01039       type == Command::MOL_TOP
01040      ) {
01041     browser->update();
01042   }
01043 
01044   if (type == Command::MOL_TOP || 
01045       type == Command::MOL_DEL || // XXX ought to emit a MOL_TOP too, IMHO
01046       type == Command::MOL_NEW ||
01047       type == Command::MOL_VOLUME ||
01048       type == Command::ANIM_JUMP ||
01049       type == Command::ANIM_NEW_NUM_FRAMES ||
01050       type == Command::ANIM_NEW_FRAME) {
01051     int id = app->molecule_top();
01052     int frame = app->molecule_frame(id);
01053     if (type != Command::ANIM_NEW_FRAME) {
01054       int max = app->molecule_numframes(id);
01055       frameslider->range(0, max-1);  
01056     } 
01057     frameslider->value(frame);
01058     char buf[20];
01059     sprintf(buf, "%d", frame);
01060     curframe->value(buf);
01061     if (type == Command::ANIM_JUMP) {
01062       forward->value(0);
01063       reverse->value(0);
01064     }
01065   } else if (type == Command::MOUSE_MODE) {
01066     update_mousemode(cmd);
01067   } else if (type == Command::DISP_DEPTHCUE  || type == Command::DISP_CULLING
01068           || type == Command::DISP_ANTIALIAS || type == Command::DISP_FPS
01069           || type == Command::DISP_LIGHT_ON  || type == Command::CMD_STAGE
01070           || type == Command::CMD_AXES       || type == Command::DISP_PROJ
01071           || type == Command::DISP_BACKGROUNDGRADIENT
01072           || type == Command::DISP_STEREO
01073           || type == Command::DISP_CACHEMODE 
01074           || type == Command::DISP_RENDERMODE) {
01075     update_dispmode();
01076   } else if (type == Command::MENU_TK_ADD) {
01077     char *shortpath = ((CmdMenuExtensionAdd *)cmd)->menupath;
01078     char *longpath = new char[strlen(EXT_MENU_NAME)+strlen(shortpath)+2];
01079     sprintf(longpath, "%s/%s",EXT_MENU_NAME,((CmdMenuExtensionAdd *)cmd)->menupath);
01080     char *menuname = stringdup(((CmdMenuExtensionAdd *)cmd)->name);
01081     menubar->add(longpath, 0, menu_cb, menuname);
01082     delete[] longpath;
01083   } else if (type == Command::MENU_TK_REMOVE) {
01084     const Fl_Menu_Item *menubase = menubar->menu();
01085     int remove_menu_index = 0;
01086     int m;
01087 
01088     for (m=0; m<menubase->size(); m++) 
01089       if (!strcmp(menubase[m].label(), EXT_MENU_NAME)) break;
01090     const Fl_Menu_Item *extmenu = menubase+m;
01091     for (m=1; m<extmenu[1].size(); m++) 
01092       if (extmenu[m].user_data() && !strcmp((char*)extmenu[m].user_data(), ((CmdMenuExtensionRemove*)cmd)->name)) {
01093         remove_menu_index = extmenu-menubase+m;
01094         break;
01095       }
01096     if (remove_menu_index) menubar->remove(remove_menu_index);
01097   } else if (type == Command::ANIM_STYLE) {
01098     style->value((int)((CmdAnimStyle *)cmd)->newStyle);
01099   } else if (type == Command::ANIM_SKIP) {
01100     step->value(((CmdAnimSkip *)cmd)->newSkip);
01101   } else if (type == Command::ANIM_SPEED) {
01102     // XXX should put some kind of scaling in here to improve the dynamic
01103     // range of the slider.  Also put the inverse scaling in speed_cb.
01104     double val = ((CmdAnimSpeed *)cmd)->newSpeed;
01105     speed->value(val);
01106   } else if (type == Command::ANIM_DIRECTION) {
01107     Animation::AnimDir newDir = ((CmdAnimDir *)cmd)->newDir;
01108     forward->value(newDir == Animation::ANIM_FORWARD);
01109     reverse->value(newDir == Animation::ANIM_REVERSE);
01110   } else {
01111     return TRUE;
01112   }
01113 
01114   return FALSE;
01115 }
01116  
01117 MainFltkMenu::~MainFltkMenu() {
01118   delete[] file_menuitems;
01119   delete[] molecule_menuitems;
01120   delete[] display_menuitems;
01121   delete[] axes_menuitems_storage;
01122   delete[] backgroundmode_menuitems_storage;
01123   delete[] stage_menuitems_storage;
01124   delete[] stereo_menuitems_storage;
01125   delete[] cachemode_menuitems_storage;
01126   delete[] rendermode_menuitems_storage;
01127   delete[] mouse_menuitems_storage;
01128   delete[] browserpopup_menuitems;
01129 }
01130 
01131 int MainFltkMenu::get_selected_molecule() {
01132   for (int j=0; j<browser->size(); j++)
01133     if (browser->selected(j+1)) 
01134       return j;
01135 
01136   return -1;
01137 }
01138 
01140 void MainFltkMenu::update_menu_state(Fl_Menu_Item* mymenuitems, const MenuBehavior* mymenu_behavior) {
01141   int j;
01142   
01143   switch (guistate) {
01144     case MANY_SELECTED_MOL:
01145       for (j=0; mymenuitems[j].label(); j++) {
01146         if (mymenu_behavior[j] == MENU_NEED_UNIQUE_SEL) mymenuitems[j].deactivate();
01147         else mymenuitems[j].activate();
01148       }
01149       break;
01150     case ONE_SELECTED_MOL:
01151       for (j=0; mymenuitems[j].label(); j++)
01152         mymenuitems[j].activate();
01153       break;
01154     case NO_SELECTED_MOL:
01155       for (j=0; mymenuitems[j].label(); j++) {
01156         if (mymenu_behavior[j] & MENU_NEED_SEL) mymenuitems[j].deactivate();
01157         else mymenuitems[j].activate();
01158       }
01159       break;
01160     case UNDEFINED: //gets rid of g++ compiler warning 
01161      break;
01162   } 
01163 }
01164 
01165     
01166 void MainFltkMenu::update_gui_state() {
01167   char has_selected_mol = 0;
01168   int old_guistate = guistate;
01169   
01170   for (int item=1; item<=browser->size(); item++) {
01171     if (browser->selected(item)) { 
01172       has_selected_mol++; 
01173       if (has_selected_mol >= 2) break;
01174     }
01175   }
01176 
01177   if (has_selected_mol == 2) guistate = MANY_SELECTED_MOL;
01178   else if (has_selected_mol == 1) guistate = ONE_SELECTED_MOL;
01179   else if (!has_selected_mol) guistate = NO_SELECTED_MOL;
01180 
01181   // (de)activate the Molecule menu items 
01182   if (old_guistate != guistate) {
01183     update_menu_state(file_menuitems, file_menu_behavior);
01184     update_menu_state(molecule_menuitems, molecule_menu_behavior);
01185     update_menu_state(browserpopup_menuitems, browserpopup_menu_behavior);
01186   }
01187     
01188 }
01189 
01190 
01191 
01192 void MainFltkMenu::draw() {
01193 #if defined(ARCH_MACOSX) || defined(ARCH_MACOSXX86) || defined(ARCH_MACOSXX86_64)
01194   size(450, h());
01195 #endif
01196   Fl_Window::draw();
01197 }
01198 

Generated on Wed Oct 8 01:26:31 2008 for VMD (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002