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

Generated on Mon May 21 01:50:56 2012 for VMD (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002