00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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
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
00132 if (!strlen(name)) continue;
00133 const char *macro = table->get_custom_singleword(name);
00134 if (macro) {
00135 macrobrowser->add(name);
00136
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
00164
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
00192
00193 self->macrooutput->value(macro);
00194 } else {
00195 self->macrooutput->value(name+2);
00196
00197
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
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
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
00235 palette->valuebrowser->clear();
00236
00237
00238 const char *keyword = palette->keywordbrowser->text(
00239 palette->keywordbrowser->value());
00240 int list = palette->table->fctns.typecode(keyword);
00241
00242
00243
00244 if(palette->mol && list >= 0 && list < palette->table->fctns.num()) {
00245
00246
00247
00248
00249 atomsel_ctxt context(palette->table, palette->mol, -1, NULL);
00250
00251
00252
00253 SymbolTableElement *info = palette->table->fctns.data(list);
00254
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
00264 hash_t hash;
00265 hash_init(&hash, num);
00266
00267
00268
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
00312
00313 info->keyword_string(&context, num, data, flgs);
00314
00315 for (i=0; i<num; i++) {
00316
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
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 }