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

MainFltkMenu.C

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

Generated on Fri Oct 11 02:43:52 2024 for VMD (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002