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 00009 /*************************************************************************** 00010 * RCS INFORMATION: 00011 * 00012 * $RCSfile: SelectionBuilder.C,v $ 00013 * $Author: johns $ $Locker: $ $State: Exp $ 00014 * $Revision: 1.30 $ $Date: 2019年01月17日 21:21:01 $ 00015 * 00016 *************************************************************************** 00017 * DESCRIPTION: 00018 * generated by Fast Light User Interface Designer (fluid) version 1.0011 00019 ***************************************************************************/ 00020 00021 #include "SelectionBuilder.h" 00022 #include "Molecule.h" 00023 #include "SymbolTable.h" 00024 #include "ParseTree.h" 00025 #include "FL/Fl.H" 00026 #include "FL/forms.H" 00027 00028 extern "C" int vmd_int_compare(const void *x, const void *y) { 00029 return *((const int *) x) - *((const int *) y); 00030 } 00031 00032 extern "C" int vmd_double_compare(const void *x, const void *y) { 00033 double delta = *((const double *) x) - *((const double *) y); 00034 if (delta < 0) { 00035 return -1; 00036 } 00037 if (delta == 0) { 00038 return 0; 00039 } 00040 return 1; 00041 } 00042 00043 extern "C" int vmd_string_compare(const void *x, const void *y) { 00044 return strcmp( *((const char **) x), *((const char **) y)); 00045 } 00046 00047 static void vmdsort_int(int *intlist, int num) { 00048 qsort(intlist, num, sizeof(int), vmd_int_compare); 00049 } 00050 00051 static void vmdsort_double(double *dlist, int num) { 00052 qsort(dlist, num, sizeof(double), vmd_double_compare); 00053 } 00054 00055 static void vmdsort_string(const char **jlist, int num) { 00056 qsort(jlist, num, sizeof(const char *), vmd_string_compare); 00057 } 00058 00059 00060 SelectionBuilder::SelectionBuilder(int xpos, int ypos, GraphicsFltkMenu *m, 00061 Fl_Input *input, SymbolTable *sym) 00062 : Fl_Group(xpos, ypos, 300, 330, "Selections") 00063 { 00064 menu = m; 00065 selectiontext = input; 00066 mol = NULL; 00067 table = sym; 00068 goto_end = 0; 00069 00070 applybutton = new Fl_Button(xpos+215, ypos+60, 70, 25, "Apply"); 00071 #if defined(VMDMENU_WINDOW) 00072 applybutton->color(VMDMENU_WINDOW, FL_GRAY); 00073 #endif 00074 applybutton->callback(apply_cb, this); 00075 00076 resetbutton = new Fl_Button(xpos+215, ypos+85, 70, 25, "Reset"); 00077 #if defined(VMDMENU_WINDOW) 00078 resetbutton->color(VMDMENU_WINDOW, FL_GRAY); 00079 #endif 00080 resetbutton->callback(reset_cb, this); 00081 { Fl_Browser* o = keywordbrowser = new Fl_Hold_Browser(xpos+15, ypos+180, 135, 150, "Keyword"); 00082 o->color(VMDMENU_BROWSER_BG); 00083 o->selection_color(VMDMENU_BROWSER_SEL); 00084 o->align(FL_ALIGN_TOP); 00085 o->callback(keyword_cb, this); 00086 } 00087 { Fl_Browser* o = valuebrowser = new Fl_Hold_Browser(xpos+165, ypos+180, 135, 150, "Value"); 00088 o->color(VMDMENU_BROWSER_BG); 00089 o->selection_color(VMDMENU_BROWSER_SEL); 00090 o->align(FL_ALIGN_TOP); 00091 o->callback(value_cb, this); 00092 } 00093 andbutton = new Fl_Button(xpos+205, ypos+25, 35, 25, "and"); 00094 #if defined(VMDMENU_WINDOW) 00095 andbutton->color(VMDMENU_WINDOW, FL_GRAY); 00096 #endif 00097 andbutton->callback(and_cb, this); 00098 orbutton = new Fl_Button(xpos+240, ypos+25, 25, 25, "or"); 00099 #if defined(VMDMENU_WINDOW) 00100 orbutton->color(VMDMENU_WINDOW, FL_GRAY); 00101 #endif 00102 orbutton->callback(or_cb, this); 00103 notbutton = new Fl_Button(xpos+265, ypos+25, 35, 25, "not"); 00104 #if defined(VMDMENU_WINDOW) 00105 notbutton->color(VMDMENU_WINDOW, FL_GRAY); 00106 #endif 00107 notbutton->callback(not_cb, this); 00108 macrobrowser = new Fl_Hold_Browser(xpos+15, ypos+25, 180, 85, "Singlewords"); 00109 macrobrowser->color(VMDMENU_BROWSER_BG, VMDMENU_BROWSER_SEL); 00110 macrobrowser->align(FL_ALIGN_TOP); 00111 macrobrowser->callback(macrobrowser_cb, this); 00112 00113 macrooutput = new Fl_Output(xpos+15, ypos+130, 285, 25, "Macro definition:"); 00114 macrooutput->align(FL_ALIGN_TOP | FL_ALIGN_LEFT); 00115 macrooutput->selection_color(VMDMENU_VALUE_SEL); 00116 // leave deactivated until it's possible to edit macros from the GUI 00117 macrooutput->deactivate(); 00118 end(); 00119 00120 for (int i=0; i<table->fctns.num(); i++) { 00121 if (table->fctns.data(i)->is_a == SymbolTableElement::KEYWORD) 00122 keywordbrowser->add(table->fctns.name(i)); 00123 } 00124 } 00125 00126 void SelectionBuilder::update_macrobrowser() { 00127 macrobrowser->clear(); 00128 for (int i=0; i<table->fctns.num(); i++) { 00129 if (table->fctns.data(i)->is_a == SymbolTableElement::SINGLEWORD) { 00130 const char *name = table->fctns.name(i); 00131 // macros are never removed, just renamed to "" 00132 if (!strlen(name)) continue; 00133 const char *macro = table->get_custom_singleword(name); 00134 if (macro) { 00135 macrobrowser->add(name); 00136 // XXX add to text input 00137 } else { 00138 JString buf("@i"); 00139 buf += name; 00140 macrobrowser->add((const char *)buf); 00141 } 00142 } 00143 } 00144 } 00145 00146 void SelectionBuilder::and_cb(Fl_Widget *, void *v) { 00147 SelectionBuilder *palette = (SelectionBuilder *)v; 00148 palette->append_text("and "); 00149 } 00150 00151 void SelectionBuilder::or_cb(Fl_Widget *, void *v) { 00152 SelectionBuilder *palette = (SelectionBuilder *)v; 00153 palette->append_text("or "); 00154 } 00155 00156 void SelectionBuilder::not_cb(Fl_Widget *, void *v) { 00157 SelectionBuilder *palette = (SelectionBuilder *)v; 00158 palette->append_text("not "); 00159 } 00160 00161 void SelectionBuilder::apply_cb(Fl_Widget *, void *v) { 00162 SelectionBuilder *palette = (SelectionBuilder *)v; 00163 // Try to parse the text now, to make sure it's valid. Parsing should 00164 // be very fast, not nearly so slow as actually finding the atoms. 00165 const char *seltext = palette->selectiontext->value(); 00166 ParseTree *tree = palette->table->parse(seltext); 00167 if (tree) { 00168 delete tree; 00169 palette->menu->update_selection(seltext); 00170 } else { 00171 fl_message("Unable to parse this atom selection."); 00172 } 00173 } 00174 00175 void SelectionBuilder::reset_cb(Fl_Widget *, void *v) { 00176 SelectionBuilder *palette = (SelectionBuilder *)v; 00177 palette->menu->update_selection(NULL); 00178 } 00179 00180 void SelectionBuilder::macrobrowser_cb(Fl_Widget *, void *v) { 00181 SelectionBuilder *self = (SelectionBuilder *)v; 00182 00183 int line = self->macrobrowser->value(); 00184 if (!line) { 00185 self->macrooutput->value(NULL); 00186 return; 00187 } 00188 const char *name = self->macrobrowser->text(line); 00189 const char *macro = self->table->get_custom_singleword(name); 00190 if (macro) { 00191 // leave deactivated until it's possible to edit macros from the GUI 00192 //self->macrooutput->activate(); 00193 self->macrooutput->value(macro); 00194 } else { 00195 self->macrooutput->value(name+2); // offset by two because of italics 00196 // leave deactivated until it's possible to edit macros from the GUI 00197 //self->macrooutput->deactivate(); 00198 } 00199 00200 if (Fl::event_clicks()) { 00201 JString buf(self->macrooutput->value()); 00202 buf += " "; 00203 self->append_text((const char *)buf); 00204 Fl::event_clicks(-1); 00205 } 00206 } 00207 00208 void SelectionBuilder::value_cb(Fl_Widget *, void *v) { 00209 SelectionBuilder *palette = (SelectionBuilder *)v; 00210 if (Fl::event_clicks()) { 00211 int line = palette->valuebrowser->value(); 00212 if (!line) return; 00213 JString buf(palette->valuebrowser->text(line)); 00214 buf += " "; 00215 //palette->selectiontext->value((const char *)buf); 00216 palette->append_text((const char *)buf); 00217 Fl::event_clicks(-1); 00218 } 00219 } 00220 00221 void SelectionBuilder::keyword_cb(Fl_Widget *, void *v) { 00222 SelectionBuilder *palette = (SelectionBuilder *)v; 00223 if (Fl::event_clicks()) { 00224 // add keyword to selection text 00225 int line = palette->keywordbrowser->value(); 00226 if (!line) return; 00227 JString buf( 00228 palette->keywordbrowser->text(line)); 00229 buf += " "; 00230 palette->append_text(buf); 00231 Fl::event_clicks(-1); 00232 return; 00233 } 00234 // just update the value browser 00235 palette->valuebrowser->clear(); 00236 00237 // get current name list selection, and check for a category with names 00238 const char *keyword = palette->keywordbrowser->text( 00239 palette->keywordbrowser->value()); 00240 int list = palette->table->fctns.typecode(keyword); 00241 00242 // only if a list has been selected, and is useful one, do we enter names 00243 // also, only need to fill browser if there is a molecule currently 00244 if(palette->mol && list >= 0 && list < palette->table->fctns.num()) { 00245 // tell the atom selection commands to use the current molecule to 00246 // get the required information. The current frame doesn't matter for 00247 // our purposes here, so just use -1 (which means the current frame) 00248 // Since we're looking only at keywords, not singlewords, macro is NULL. 00249 atomsel_ctxt context(palette->table, palette->mol, -1, NULL); 00250 00251 // get all the info from the item in the table 00252 // first see what it does 00253 SymbolTableElement *info = palette->table->fctns.data(list); 00254 // the only one that shows anything are the KEYWORDs 00255 if (info -> is_a == SymbolTableElement::KEYWORD) { 00256 int num = palette->mol->nAtoms; 00257 int *flgs = new int[num]; 00258 int i; 00259 for (i=0; i<num; i++) { 00260 flgs[i] = 1; 00261 } 00262 00263 // initialize a hash table for finding the unique entries 00264 hash_t hash; 00265 hash_init(&hash, num); 00266 00267 // get the the into an array whose type matches the type of the 00268 // data. That way we don't convert to string until the end 00269 switch(info -> returns_a) { 00270 case (SymbolTableElement::IS_INT): 00271 { 00272 int *data = new int[num]; 00273 JString *strdata = new JString[num]; 00274 info->keyword_int(&context, num, data, flgs); 00275 vmdsort_int(data, num); 00276 for (i=0; i<num; i++) { 00277 char buf[40]; 00278 sprintf(buf, "%d", data[i]); 00279 strdata[i] = buf; 00280 if (hash_insert(&hash, (const char *)strdata[i], 0) == HASH_FAIL) 00281 palette->valuebrowser->add(buf); 00282 } 00283 delete [] data; 00284 delete [] strdata; 00285 break; 00286 } 00287 case (SymbolTableElement::IS_FLOAT): 00288 { 00289 double *data = new double[num]; 00290 JString *strdata = new JString[num]; 00291 info->keyword_double(&context, num, data, flgs); 00292 vmdsort_double(data, num); 00293 for (i=0; i<num; i++) { 00294 char buf[40]; 00295 float tmp = (float)data[i]; 00296 sprintf(buf, "%f", tmp); 00297 strdata[i] = buf; 00298 if (hash_insert(&hash, (const char *)strdata[i], 0) == HASH_FAIL) 00299 palette->valuebrowser->add(buf); 00300 } 00301 delete [] data; 00302 delete [] strdata; 00303 break; 00304 } 00305 case (SymbolTableElement::IS_STRING): 00306 { 00307 const char **data = new const char *[num]; 00308 const char **hashdata = new const char *[num]; 00309 int j=0; 00310 00311 // XXX crashes can occur here when only coords are loaded 00312 // and "structure" is displayed in the selection builder. 00313 info->keyword_string(&context, num, data, flgs); 00314 00315 for (i=0; i<num; i++) { 00316 // XXX prevent crashes when no atom names are available 00317 if (data[i] != NULL) { 00318 if (hash_insert(&hash, data[i], 0) == HASH_FAIL) 00319 hashdata[j++] = data[i]; 00320 } 00321 } 00322 00323 vmdsort_string(hashdata, j); 00324 for (i=0; i<j; i++) { 00325 palette->valuebrowser->add(hashdata[i]); 00326 } 00327 delete [] data; 00328 delete [] hashdata; 00329 } 00330 default: ; 00331 } 00332 hash_destroy(&hash); 00333 delete [] flgs; 00334 } 00335 } 00336 } 00337 00338 void SelectionBuilder::append_text(const char *s) { 00339 // If there's selected text, replace it. Otherwise, just append at the end 00340 selectiontext->replace(selectiontext->position(), selectiontext->mark(), s); 00341 00342 if (goto_end) { 00343 selectiontext->position(selectiontext->size()); 00344 goto_end = 0; 00345 } 00346 } 00347 00348 void SelectionBuilder::use_molecule(Molecule *m) { 00349 mol = m; 00350 keyword_cb(keywordbrowser, this); 00351 } 00352 00353 void SelectionBuilder::set_selection(const char *s) { 00354 selectiontext->value(s); 00355 selectiontext->position(selectiontext->size()); 00356 }