1 | // =============================================================== // |
---|
2 | // // |
---|
3 | // File : SEC_graphic.cxx // |
---|
4 | // Purpose : GUI for structure window // |
---|
5 | // // |
---|
6 | // Institute of Microbiology (Technical University Munich) // |
---|
7 | // http://www.arb-home.de/ // |
---|
8 | // // |
---|
9 | // =============================================================== // |
---|
10 | |
---|
11 | #include "SEC_graphic.hxx" |
---|
12 | #include "SEC_root.hxx" |
---|
13 | #include "SEC_iter.hxx" |
---|
14 | #include "SEC_toggle.hxx" |
---|
15 | |
---|
16 | #include <ed4_extern.hxx> |
---|
17 | |
---|
18 | #include <aw_awars.hxx> |
---|
19 | #include <aw_global.hxx> |
---|
20 | #include <aw_preset.hxx> |
---|
21 | #include <aw_msg.hxx> |
---|
22 | #include <aw_root.hxx> |
---|
23 | #include <aw_question.hxx> |
---|
24 | #include <arbdbt.h> |
---|
25 | #include <ad_cb.h> |
---|
26 | |
---|
27 | #include <vector> |
---|
28 | |
---|
29 | using namespace std; |
---|
30 | |
---|
31 | AW_gc_manager SEC_graphic::init_devices(AW_window *aww, AW_device *device, AWT_canvas *scr) |
---|
32 | { |
---|
33 | AW_gc_manager gc_manager = |
---|
34 | AW_manage_GC(aww, |
---|
35 | scr->get_gc_base_name(), |
---|
36 | device, |
---|
37 | SEC_GC_LOOP, |
---|
38 | SEC_GC_MAX, |
---|
39 | AW_GCM_DATA_AREA, |
---|
40 | makeWindowCallback(AWT_expose_cb, scr), |
---|
41 | false, |
---|
42 | "#A1A1A1", |
---|
43 | "LOOP$#247900", |
---|
44 | "HELIX$#085DAB", |
---|
45 | "NONPAIRING HELIX$#D52B69", |
---|
46 | "DEFAULT$#000000", |
---|
47 | "BONDS$#000000", |
---|
48 | "ECOLI POSITION$#FFE223", |
---|
49 | "HELIX NUMBERS$#D4D4D4", |
---|
50 | |
---|
51 | // Color Ranges to paint SAIs |
---|
52 | "+-RANGE 0$#FFFFFF", "+-RANGE 1$#E0E0E0", "-RANGE 2$#C0C0C0", |
---|
53 | "+-RANGE 3$#A0A0A0", "+-RANGE 4$#909090", "-RANGE 5$#808080", |
---|
54 | "+-RANGE 6$#808080", "+-RANGE 7$#505050", "-RANGE 8$#404040", |
---|
55 | "+-RANGE 9$#303030", "+-CURSOR$#BF1515", "-MISMATCHES$#FF9AFF", |
---|
56 | |
---|
57 | // colors used to Paint search patterns |
---|
58 | // (do not change the names of these gcs) |
---|
59 | "+-User1$#B8E2F8", "+-User2$#B8E2F8", "-Probe$#B8E2F8", |
---|
60 | "+-Primer(l)$#A9FE54", "+-Primer(r)$#A9FE54", "-Primer(g)$#A9FE54", |
---|
61 | "+-Sig(l)$#DBB0FF", "+-Sig(r)$#DBB0FF", "-Sig(g)$#DBB0FF", |
---|
62 | |
---|
63 | // colors used to paint the skeleton of the structure |
---|
64 | "+-SKELETON HELIX${HELIX}", "+-SKELETON LOOP${LOOP}", "-SKELETON NONHELIX${NONPAIRING HELIX}", |
---|
65 | NULL); |
---|
66 | |
---|
67 | return gc_manager; |
---|
68 | } |
---|
69 | |
---|
70 | static GB_ERROR change_constraints(SEC_base *elem) { |
---|
71 | GB_ERROR error = 0; |
---|
72 | |
---|
73 | GB_CSTR constraint_type = 0; |
---|
74 | GB_CSTR element_type = 0; |
---|
75 | |
---|
76 | switch (elem->getType()) { |
---|
77 | case SEC_HELIX: |
---|
78 | constraint_type = "length"; |
---|
79 | element_type = "helix"; |
---|
80 | break; |
---|
81 | case SEC_LOOP: |
---|
82 | constraint_type = "radius"; |
---|
83 | element_type = "loop"; |
---|
84 | break; |
---|
85 | default: |
---|
86 | sec_assert(0); |
---|
87 | error = "Illegal element type"; |
---|
88 | break; |
---|
89 | } |
---|
90 | |
---|
91 | if (!error) { |
---|
92 | char *question = GBS_global_string_copy("%s-constraints for %s", constraint_type, element_type); |
---|
93 | char *answer = aw_input(question, GBS_global_string("%.2f-%.2f", elem->minSize(), elem->maxSize())); |
---|
94 | |
---|
95 | while (answer) { |
---|
96 | char *end; |
---|
97 | double low = strtod(answer, &end); |
---|
98 | |
---|
99 | if (end[0]!='-') { |
---|
100 | error = "Wrong format! Wanted format is 'lower-upper'"; |
---|
101 | } |
---|
102 | else { |
---|
103 | double high = strtod(end+1, 0); |
---|
104 | |
---|
105 | if (low<0 || high<0 || (low && high && low>high)) { |
---|
106 | error = "Illegal values"; |
---|
107 | } |
---|
108 | else { |
---|
109 | #if defined(DEBUG) |
---|
110 | sec_assert(!low || !high || low<=high); |
---|
111 | #endif // DEBUG |
---|
112 | elem->setConstraints(low, high); |
---|
113 | break; |
---|
114 | } |
---|
115 | } |
---|
116 | |
---|
117 | sec_assert(error); |
---|
118 | aw_message(error); |
---|
119 | |
---|
120 | char *retry = aw_input(question, answer); |
---|
121 | free(answer); |
---|
122 | |
---|
123 | answer = retry; |
---|
124 | } |
---|
125 | |
---|
126 | free(answer); |
---|
127 | free(question); |
---|
128 | } |
---|
129 | return error; |
---|
130 | } |
---|
131 | |
---|
132 | |
---|
133 | GB_ERROR SEC_graphic::handleKey(AW_event_type event, AW_key_mod key_modifier, AW_key_code key_code, char key_char) { |
---|
134 | GB_ERROR error = 0; |
---|
135 | |
---|
136 | if (event == AW_Keyboard_Press) { |
---|
137 | int curpos = sec_root->get_cursor(); |
---|
138 | int maxIndex = sec_root->max_index(); |
---|
139 | bool setCurpos = false; |
---|
140 | bool handled = false; |
---|
141 | |
---|
142 | if (key_modifier == AW_KEYMODE_NONE) { |
---|
143 | bool wrapped = false; // avoid deadlock |
---|
144 | |
---|
145 | switch (key_code) { |
---|
146 | case AW_KEY_LEFT: { |
---|
147 | while (1) { |
---|
148 | curpos--; |
---|
149 | if (curpos<0) { |
---|
150 | curpos = maxIndex; |
---|
151 | if (wrapped) break; |
---|
152 | wrapped = true; |
---|
153 | } |
---|
154 | if (sec_root->shallDisplayPosition(curpos)) { |
---|
155 | setCurpos = true; |
---|
156 | break; |
---|
157 | } |
---|
158 | } |
---|
159 | break; |
---|
160 | } |
---|
161 | case AW_KEY_RIGHT: { |
---|
162 | while (1) { |
---|
163 | curpos++; |
---|
164 | if (curpos > maxIndex) { |
---|
165 | curpos = 0; |
---|
166 | if (wrapped) break; |
---|
167 | wrapped = true; |
---|
168 | } |
---|
169 | if (sec_root->shallDisplayPosition(curpos)) { |
---|
170 | setCurpos = true; |
---|
171 | break; |
---|
172 | } |
---|
173 | } |
---|
174 | break; |
---|
175 | } |
---|
176 | case AW_KEY_ASCII: { |
---|
177 | const char *toggle_awar = 0; |
---|
178 | int val_max = 1; |
---|
179 | |
---|
180 | switch (key_char) { |
---|
181 | case 'b': toggle_awar = AWAR_SECEDIT_SHOW_BONDS; val_max = 2; break; |
---|
182 | case 'B': toggle_awar = AWAR_SECEDIT_HIDE_BASES; break; |
---|
183 | case 'k': toggle_awar = AWAR_SECEDIT_SHOW_STR_SKELETON; break; |
---|
184 | |
---|
185 | case 'c': toggle_awar = AWAR_SECEDIT_SHOW_CURPOS; val_max = 3; break; |
---|
186 | case 'h': toggle_awar = AWAR_SECEDIT_SHOW_HELIX_NRS; break; |
---|
187 | case 'e': toggle_awar = AWAR_SECEDIT_SHOW_ECOLI_POS; break; |
---|
188 | |
---|
189 | case 's': toggle_awar = AWAR_SECEDIT_DISPLAY_SAI; break; |
---|
190 | case 'r': toggle_awar = AWAR_SECEDIT_DISPLAY_SEARCH; break; |
---|
191 | |
---|
192 | case 'E': toggle_awar = AWAR_SECEDIT_DISPPOS_ECOLI; break; |
---|
193 | case 'H': toggle_awar = AWAR_SECEDIT_DISPPOS_BINDING; break; |
---|
194 | |
---|
195 | #if defined(DEBUG) |
---|
196 | case 'd': toggle_awar = AWAR_SECEDIT_SHOW_DEBUG; break; |
---|
197 | #endif // DEBUG |
---|
198 | |
---|
199 | case 't': |
---|
200 | error = sec_root->get_db()->structure()->next(); |
---|
201 | handled = true; |
---|
202 | break; |
---|
203 | } |
---|
204 | |
---|
205 | if (toggle_awar) { |
---|
206 | AW_awar *awar = aw_root->awar(toggle_awar); |
---|
207 | int val = awar->read_int()+1; |
---|
208 | |
---|
209 | if (val>val_max) val = 0; |
---|
210 | awar->write_int(val); |
---|
211 | |
---|
212 | handled = true; |
---|
213 | } |
---|
214 | |
---|
215 | break; |
---|
216 | } |
---|
217 | default: |
---|
218 | break; |
---|
219 | } |
---|
220 | } |
---|
221 | |
---|
222 | if (setCurpos) { |
---|
223 | aw_root->awar_int(AWAR_SET_CURSOR_POSITION)->write_int(curpos); |
---|
224 | handled = true; |
---|
225 | } |
---|
226 | |
---|
227 | if (!handled) { // pass unhandled key events to EDIT4 |
---|
228 | AW_event faked_event; |
---|
229 | |
---|
230 | memset((char*)&faked_event, 0, sizeof(faked_event)); |
---|
231 | |
---|
232 | faked_event.type = event; |
---|
233 | faked_event.keymodifier = key_modifier; |
---|
234 | faked_event.keycode = key_code; |
---|
235 | faked_event.character = key_char; |
---|
236 | |
---|
237 | sec_root->host().forward_event(&faked_event); |
---|
238 | } |
---|
239 | } |
---|
240 | |
---|
241 | return error; |
---|
242 | } |
---|
243 | |
---|
244 | GB_ERROR SEC_graphic::handleMouse(AW_device *device, AW_event_type event, int button, AWT_COMMAND_MODE cmd, const Position& world, SEC_base *elem, int abspos) { |
---|
245 | GB_ERROR error = 0; |
---|
246 | |
---|
247 | // ------------------------------------------ |
---|
248 | // handle element dependent actions |
---|
249 | |
---|
250 | if (elem) { |
---|
251 | static Position start; // click position on mouse down |
---|
252 | |
---|
253 | Position fixpoint = elem->get_fixpoint(); // of strand or loop |
---|
254 | |
---|
255 | SEC_loop *loop = 0; |
---|
256 | SEC_helix *helix = 0; |
---|
257 | |
---|
258 | if (elem->getType() == SEC_HELIX) helix = static_cast<SEC_helix*>(elem); |
---|
259 | else { |
---|
260 | sec_assert(elem->getType() == SEC_LOOP); |
---|
261 | loop = static_cast<SEC_loop*>(elem); |
---|
262 | } |
---|
263 | |
---|
264 | if (event == AW_Mouse_Press) start = world; // store start position |
---|
265 | |
---|
266 | switch (cmd) { |
---|
267 | case AWT_MODE_STRETCH: { // change constraints with mouse |
---|
268 | static double start_size; // helix/loop size at start click |
---|
269 | |
---|
270 | switch (event) { |
---|
271 | case AW_Mouse_Press: |
---|
272 | if (button == AW_BUTTON_LEFT) { |
---|
273 | start_size = elem->drawnSize(); |
---|
274 | sec_root->set_show_constraints(elem->getType()); |
---|
275 | exports.refresh = 1; |
---|
276 | } |
---|
277 | else { // right button -> reset constraints |
---|
278 | elem->setConstraints(0, 0); |
---|
279 | elem->sizeChanged(); |
---|
280 | exports.refresh = 1; |
---|
281 | exports.save = 1; |
---|
282 | } |
---|
283 | break; |
---|
284 | |
---|
285 | case AW_Mouse_Drag: |
---|
286 | if (button == AW_BUTTON_LEFT) { |
---|
287 | double dfix1 = Distance(fixpoint, start); |
---|
288 | double dfix2 = Distance(fixpoint, world); |
---|
289 | |
---|
290 | if (dfix1>0 && dfix2>0) { |
---|
291 | double factor = dfix2/dfix1; |
---|
292 | double new_size = start_size*factor; |
---|
293 | |
---|
294 | elem->setDrawnSize(new_size); |
---|
295 | elem->sizeChanged(); |
---|
296 | |
---|
297 | exports.refresh = 1; |
---|
298 | } |
---|
299 | } |
---|
300 | break; |
---|
301 | |
---|
302 | case AW_Mouse_Release: |
---|
303 | sec_root->set_show_constraints(SEC_ANY_TYPE); |
---|
304 | exports.save = 1; |
---|
305 | break; |
---|
306 | |
---|
307 | default: sec_assert(0); break; |
---|
308 | } |
---|
309 | break; |
---|
310 | } |
---|
311 | case AWT_MODE_EDIT: // edit constraints |
---|
312 | if (button==AW_BUTTON_LEFT && event==AW_Mouse_Press) { |
---|
313 | error = change_constraints(elem); |
---|
314 | if (!error) { |
---|
315 | elem->sizeChanged(); |
---|
316 | exports.save = 1; |
---|
317 | } |
---|
318 | } |
---|
319 | break; |
---|
320 | |
---|
321 | case AWT_MODE_ROTATE: { // rotate branches/loops |
---|
322 | if (event == AW_Mouse_Release) { |
---|
323 | exports.save = 1; |
---|
324 | } |
---|
325 | else { |
---|
326 | static Angle startClick; // angle between fixpoint (of loop or helix) and first-click |
---|
327 | static bool rotateSubStructure; // whether to rotate the substructure below |
---|
328 | static vector<Angle> old; // old angles |
---|
329 | |
---|
330 | if (loop && loop->is_root_loop()) fixpoint = loop->get_center(); |
---|
331 | |
---|
332 | Angle fix2world(fixpoint, world); |
---|
333 | |
---|
334 | if (event == AW_Mouse_Press) { |
---|
335 | startClick = fix2world; |
---|
336 | old.clear(); |
---|
337 | rotateSubStructure = (button == AW_BUTTON_LEFT); |
---|
338 | |
---|
339 | if (loop) { |
---|
340 | old.push_back(loop->get_abs_angle()); |
---|
341 | if (!rotateSubStructure) { |
---|
342 | for (SEC_strand_iterator strand(loop); strand; ++strand) { |
---|
343 | if (strand->isRootsideFixpoint()) { |
---|
344 | old.push_back(strand->get_helix()->get_abs_angle()); |
---|
345 | } |
---|
346 | } |
---|
347 | } |
---|
348 | } |
---|
349 | else { |
---|
350 | old.push_back(helix->get_abs_angle()); |
---|
351 | old.push_back(helix->outsideLoop()->get_abs_angle()); |
---|
352 | } |
---|
353 | } |
---|
354 | else { |
---|
355 | sec_assert(event == AW_Mouse_Drag); |
---|
356 | Angle diff = fix2world-startClick; |
---|
357 | |
---|
358 | if (loop) { |
---|
359 | loop->set_abs_angle(old[0]+diff); |
---|
360 | if (!rotateSubStructure) { |
---|
361 | int idx = 1; |
---|
362 | for (SEC_strand_iterator strand(loop); strand; ++strand) { |
---|
363 | if (strand->isRootsideFixpoint()) { |
---|
364 | strand->get_helix()->set_abs_angle(old[idx++]); |
---|
365 | } |
---|
366 | } |
---|
367 | } |
---|
368 | } |
---|
369 | else { |
---|
370 | helix->set_abs_angle(old[0]+diff); |
---|
371 | if (!rotateSubStructure) helix->outsideLoop()->set_abs_angle(old[1]); |
---|
372 | } |
---|
373 | |
---|
374 | exports.refresh = 1; |
---|
375 | elem->orientationChanged(); |
---|
376 | } |
---|
377 | } |
---|
378 | break; |
---|
379 | } |
---|
380 | |
---|
381 | case AWT_MODE_SETROOT: // set-root-mode / reset angles |
---|
382 | if (event == AW_Mouse_Press) { |
---|
383 | if (button == AW_BUTTON_LEFT) { // set root |
---|
384 | if (loop) { |
---|
385 | sec_root->set_root(loop); |
---|
386 | exports.save = 1; |
---|
387 | } |
---|
388 | else error = "Please click on a loop to change the root"; |
---|
389 | } |
---|
390 | else { // reset angles |
---|
391 | sec_assert(button == AW_BUTTON_RIGHT); |
---|
392 | elem->reset_angles(); |
---|
393 | elem->orientationChanged(); |
---|
394 | exports.save = 1; |
---|
395 | } |
---|
396 | } |
---|
397 | break; |
---|
398 | |
---|
399 | case AWT_MODE_FOLD: { // fold/unfold helix |
---|
400 | if (event == AW_Mouse_Press) { |
---|
401 | if (button == AW_BUTTON_LEFT) { // fold helix |
---|
402 | if (loop) { |
---|
403 | const char *helix_nr = sec_root->helixNrAt(abspos); |
---|
404 | if (helix_nr) { |
---|
405 | const size_t *p = sec_root->getHelixPositions(helix_nr); |
---|
406 | error = sec_root->split_loop(p[0], p[1]+1, p[2], p[3]+1); |
---|
407 | |
---|
408 | if (!error) { |
---|
409 | sec_root->nail_position(abspos); |
---|
410 | exports.save = 1; |
---|
411 | } |
---|
412 | } |
---|
413 | else { |
---|
414 | error = GBS_global_string("No helix to fold at position %i", abspos); |
---|
415 | } |
---|
416 | } |
---|
417 | else { |
---|
418 | error = "Click on a loop region to fold a helix"; |
---|
419 | } |
---|
420 | } |
---|
421 | else { // unfold helix |
---|
422 | sec_assert(button == AW_BUTTON_RIGHT); |
---|
423 | if (helix) { |
---|
424 | error = sec_root->unsplit_loop(helix->strandToRoot()); |
---|
425 | if (!error) { |
---|
426 | sec_root->nail_position(abspos); |
---|
427 | exports.save = 1; |
---|
428 | } |
---|
429 | } |
---|
430 | else { |
---|
431 | error = "Right click on a helix to remove it"; |
---|
432 | } |
---|
433 | } |
---|
434 | } |
---|
435 | break; |
---|
436 | } |
---|
437 | case AWT_MODE_CURSOR: |
---|
438 | case AWT_MODE_PINFO: |
---|
439 | elem = 0; // handle element-independent |
---|
440 | break; |
---|
441 | default: sec_assert(0); break; |
---|
442 | } |
---|
443 | } |
---|
444 | |
---|
445 | // --------------------------------------- |
---|
446 | // action independent of element |
---|
447 | |
---|
448 | if (!elem) { |
---|
449 | switch (cmd) { |
---|
450 | case AWT_MODE_CURSOR: // set cursor in ARB_EDIT4 |
---|
451 | if (event == AW_Mouse_Press) { |
---|
452 | if (abspos >= 0 && size_t(abspos) < sec_root->max_index()) { |
---|
453 | // sequence position in AWAR_SET_CURSOR_POSITION is starting with 0! |
---|
454 | aw_root->awar_int(AWAR_SET_CURSOR_POSITION)->write_int(abspos); |
---|
455 | } |
---|
456 | } |
---|
457 | break; |
---|
458 | |
---|
459 | case AWT_MODE_PINFO: // display search pattern |
---|
460 | if (event == AW_Mouse_Press) { |
---|
461 | if (button == AW_BUTTON_LEFT) { |
---|
462 | if (abspos >= 0 && size_t(abspos) < sec_root->max_index()) { |
---|
463 | sec_root->paintSearchPatternStrings(device, abspos, world.xpos()+1, world.ypos()); |
---|
464 | } |
---|
465 | // don't refresh here! |
---|
466 | } |
---|
467 | else { |
---|
468 | sec_assert(button == AW_BUTTON_RIGHT); |
---|
469 | exports.refresh = 1; // simply refresh to remove drawn patterns |
---|
470 | } |
---|
471 | } |
---|
472 | break; |
---|
473 | |
---|
474 | default: |
---|
475 | break; |
---|
476 | } |
---|
477 | return 0; // no error |
---|
478 | } |
---|
479 | |
---|
480 | if (exports.save == 1) exports.refresh = 1; |
---|
481 | return error; |
---|
482 | } |
---|
483 | |
---|
484 | void SEC_graphic::handle_command(AW_device *device, AWT_graphic_event& event) { |
---|
485 | if (event.cmd() != AWT_MODE_EDIT && event.cmd() != AWT_MODE_STRETCH) sec_root->set_show_constraints(SEC_NO_TYPE); |
---|
486 | |
---|
487 | GB_ERROR error = 0; |
---|
488 | if (event.type() == AW_Keyboard_Press || event.type() == AW_Keyboard_Release) { |
---|
489 | error = handleKey(event.type(), event.key_modifier(), event.key_code(), event.key_char()); |
---|
490 | } |
---|
491 | else { |
---|
492 | if (event.button() != AW_BUTTON_MIDDLE && event.cmd() != AWT_MODE_ZOOM) { // don't handle scroll + zoom |
---|
493 | const AW_clicked_element *clicked = event.best_click(); |
---|
494 | if (clicked) { |
---|
495 | SEC_base *elem = reinterpret_cast<SEC_base*>(clicked->cd1()); |
---|
496 | int abspos = clicked->cd2(); |
---|
497 | |
---|
498 | Position world = device->rtransform(event.position()); |
---|
499 | error = handleMouse(device, event.type(), event.button(), event.cmd(), world, elem, abspos); |
---|
500 | } |
---|
501 | } |
---|
502 | } |
---|
503 | |
---|
504 | if (error) aw_message(error); |
---|
505 | } |
---|
506 | |
---|
507 | SEC_graphic::SEC_graphic(AW_root *aw_rooti, GBDATA *gb_maini) |
---|
508 | : update_requested(SEC_UPDATE_RELOAD), |
---|
509 | load_error(0), |
---|
510 | disp_device(0), |
---|
511 | gb_main(gb_maini), |
---|
512 | aw_root(aw_rooti), |
---|
513 | sec_root(new SEC_root), |
---|
514 | gb_struct(0), |
---|
515 | gb_struct_ref(0), |
---|
516 | last_saved(0) |
---|
517 | { |
---|
518 | exports.set_standard_default_padding(); |
---|
519 | } |
---|
520 | |
---|
521 | SEC_graphic::~SEC_graphic() { |
---|
522 | delete sec_root; |
---|
523 | delete load_error; |
---|
524 | } |
---|
525 | |
---|
526 | static void SEC_structure_changed_cb(GBDATA *gb_seq, SEC_graphic *gfx, GB_CB_TYPE type) { |
---|
527 | if (type == GB_CB_DELETE) { |
---|
528 | gfx->gb_struct = NULL; |
---|
529 | gfx->gb_struct_ref = NULL; |
---|
530 | |
---|
531 | gfx->request_update(SEC_UPDATE_RELOAD); |
---|
532 | } |
---|
533 | else if (GB_read_clock(gb_seq) > gfx->last_saved) { // not changed by secedit self |
---|
534 | gfx->request_update(SEC_UPDATE_RELOAD); |
---|
535 | } |
---|
536 | } |
---|
537 | |
---|
538 | GB_ERROR SEC_graphic::load(GBDATA *, const char *, AW_CL, AW_CL) { |
---|
539 | //! (Re-)Load secondary structure from database |
---|
540 | |
---|
541 | sec_assert(sec_root->get_db()->canDisplay()); // need a sequence loaded (to fix bugs in versions < 3) |
---|
542 | sec_root->nail_cursor(); |
---|
543 | |
---|
544 | GB_transaction ta(gb_main); |
---|
545 | // first check timestamp, do not load structure that we have saved !!!! |
---|
546 | if (gb_struct) { |
---|
547 | if (GB_read_clock(gb_struct) <= last_saved) return NULL; |
---|
548 | } |
---|
549 | |
---|
550 | // Reset structure: |
---|
551 | if (gb_struct) { |
---|
552 | GB_remove_callback(gb_struct, GB_CB_ALL, makeDatabaseCallback(SEC_structure_changed_cb, this)); gb_struct = NULL; |
---|
553 | GB_remove_callback(gb_struct_ref, GB_CB_ALL, makeDatabaseCallback(SEC_structure_changed_cb, this)); gb_struct_ref = NULL; |
---|
554 | } |
---|
555 | |
---|
556 | request_update(SEC_UPDATE_RECOUNT); |
---|
557 | |
---|
558 | if (gb_struct) { |
---|
559 | this->last_saved = GB_read_clock(gb_struct); // mark as loaded |
---|
560 | } |
---|
561 | |
---|
562 | |
---|
563 | |
---|
564 | // Setup new structure: |
---|
565 | GB_ERROR err = 0; |
---|
566 | GBDATA *gb_ali = 0; |
---|
567 | { |
---|
568 | char *helix_name = GBT_get_default_helix(gb_main); |
---|
569 | char *name = GBT_readOrCreate_string(gb_main, AWAR_HELIX_NAME, helix_name); |
---|
570 | sec_assert(name); |
---|
571 | |
---|
572 | GBDATA *gb_species = GBT_find_SAI(gb_main, name); |
---|
573 | if (!gb_species) { |
---|
574 | err = GB_export_errorf("Cannot find helix template SAI '%s'", name); |
---|
575 | } |
---|
576 | else { |
---|
577 | char *ali_name = GBT_get_default_alignment(gb_main); |
---|
578 | long ali_len = GBT_get_alignment_len(gb_main, ali_name); |
---|
579 | |
---|
580 | if (ali_len < 10) { |
---|
581 | err = GB_export_errorf("alignment '%s' to short to generate helix", ali_name); |
---|
582 | } |
---|
583 | else { |
---|
584 | gb_ali = GB_search(gb_species, ali_name, GB_FIND); |
---|
585 | if (!gb_ali) { |
---|
586 | err = GB_export_errorf("Your helix structure template '%s' has no valid sequence for alignment '%s'", name, ali_name); // no sequence for name in the database !!! |
---|
587 | } |
---|
588 | } |
---|
589 | free(ali_name); |
---|
590 | } |
---|
591 | |
---|
592 | free(name); |
---|
593 | free(helix_name); |
---|
594 | } |
---|
595 | |
---|
596 | // ------------------------ |
---|
597 | // read structure |
---|
598 | |
---|
599 | if (!err) { |
---|
600 | gb_struct = GB_search(gb_ali, NAME_OF_STRUCT_SEQ, GB_FIND); |
---|
601 | |
---|
602 | if (gb_struct) { |
---|
603 | gb_struct_ref = GB_search(gb_ali, NAME_OF_REF_SEQ, GB_STRING); |
---|
604 | |
---|
605 | char *strct = GB_read_string(gb_struct); |
---|
606 | char *ref = GB_read_string(gb_struct_ref); |
---|
607 | err = sec_root->read_data(strct, ref); |
---|
608 | if (err) { |
---|
609 | err = GBS_global_string("Defect structure in DB (read-error: '%s')", err); |
---|
610 | } |
---|
611 | #if defined(CHECK_INTEGRITY) |
---|
612 | else { |
---|
613 | sec_root->check_integrity(CHECK_STRUCTURE); |
---|
614 | } |
---|
615 | #endif // CHECK_INTEGRITY |
---|
616 | |
---|
617 | free(strct); |
---|
618 | free(ref); |
---|
619 | |
---|
620 | // on first load init structure toggler: |
---|
621 | if (!err) { |
---|
622 | sec_root->get_db()->init_toggler(); |
---|
623 | } |
---|
624 | } |
---|
625 | else { |
---|
626 | err = "no secondary structure was found in your database"; |
---|
627 | } |
---|
628 | |
---|
629 | if (err) { |
---|
630 | request_update(SEC_UPDATE_ZOOM_RESET); |
---|
631 | } |
---|
632 | else { |
---|
633 | // in the past one additional NAME_OF_STRUCT_SEQ-entry was added everytime the default bone was created |
---|
634 | // Fix: delete additional entries |
---|
635 | |
---|
636 | GBDATA *gb_add = gb_struct; |
---|
637 | do { |
---|
638 | sec_assert(GB_has_key(gb_add, NAME_OF_STRUCT_SEQ)); |
---|
639 | gb_add = GB_nextEntry(gb_add); |
---|
640 | if (gb_add) { |
---|
641 | err = GB_delete(gb_add); |
---|
642 | printf("* Deleting duplicated entry '%s' (%p)\n", NAME_OF_STRUCT_SEQ, gb_add); |
---|
643 | } |
---|
644 | } |
---|
645 | while (gb_add && !err); |
---|
646 | } |
---|
647 | } |
---|
648 | |
---|
649 | if (!err) { |
---|
650 | last_saved = GB_read_clock(gb_struct); // mark as loaded |
---|
651 | request_update(SEC_UPDATE_RECOUNT); |
---|
652 | if (load_error) { // previous load error? |
---|
653 | freenull(load_error); |
---|
654 | request_update(SEC_UPDATE_ZOOM_RESET); |
---|
655 | } |
---|
656 | } |
---|
657 | else { |
---|
658 | load_error = strdup(err); |
---|
659 | request_update(SEC_UPDATE_ZOOM_RESET); |
---|
660 | } |
---|
661 | |
---|
662 | // set structure-change-callbacks: |
---|
663 | if(gb_struct) GB_add_callback(gb_struct, GB_CB_ALL, makeDatabaseCallback(SEC_structure_changed_cb, this)); |
---|
664 | if(gb_struct_ref) GB_add_callback(gb_struct_ref, GB_CB_ALL, makeDatabaseCallback(SEC_structure_changed_cb, this)); |
---|
665 | |
---|
666 | return err; |
---|
667 | } |
---|
668 | |
---|
669 | GB_ERROR SEC_graphic::save(GBDATA *, const char *, AW_CL, AW_CL) { |
---|
670 | //! Save secondary structure to database |
---|
671 | |
---|
672 | if (!gb_struct) return 0; // not loaded, so don't save |
---|
673 | if (!sec_root) return 0; |
---|
674 | |
---|
675 | char *data = sec_root->buildStructureString(); |
---|
676 | GB_transaction ta(gb_main); |
---|
677 | GB_ERROR error = GB_write_string(gb_struct, data); |
---|
678 | if (!error) { |
---|
679 | const XString& xstr = sec_root->get_xString(); |
---|
680 | const char *x_string = xstr.get_x_string(); |
---|
681 | |
---|
682 | error = GB_write_string(gb_struct_ref, x_string); |
---|
683 | |
---|
684 | if (!error && xstr.alignment_too_short()) { |
---|
685 | aw_message("Your helix needs one gap at end. Please format your alignment!"); |
---|
686 | } |
---|
687 | } |
---|
688 | this->last_saved = GB_read_clock(gb_struct); |
---|
689 | if (error) { |
---|
690 | error = ta.close(error); |
---|
691 | aw_message(error); |
---|
692 | } |
---|
693 | return NULL; |
---|
694 | } |
---|
695 | |
---|
696 | GB_ERROR SEC_graphic::read_data_from_db(char **data, char **x_string) const { |
---|
697 | GB_ERROR error = 0; |
---|
698 | |
---|
699 | sec_assert(gb_struct && gb_struct_ref); |
---|
700 | *data = GB_read_string(gb_struct); |
---|
701 | if (!*data) error = GB_await_error(); |
---|
702 | else { |
---|
703 | *x_string = GB_read_string(gb_struct_ref); |
---|
704 | if (!*x_string) error = GB_await_error(); |
---|
705 | } |
---|
706 | return error; |
---|
707 | } |
---|
708 | |
---|
709 | GB_ERROR SEC_graphic::write_data_to_db(const char *data, const char *x_string) const { |
---|
710 | if (!gb_struct) return 0; |
---|
711 | if (!sec_root) return 0; |
---|
712 | |
---|
713 | GB_transaction ta(gb_main); |
---|
714 | GB_ERROR error = GB_write_string(gb_struct, data); |
---|
715 | if (!error) { |
---|
716 | error = GB_write_string(gb_struct_ref, x_string); |
---|
717 | } |
---|
718 | last_saved = 0; // force reload of data |
---|
719 | return ta.close(error); |
---|
720 | } |
---|
721 | |
---|
722 | int SEC_graphic::check_update(GBDATA *) { |
---|
723 | GB_transaction ta(gb_main); |
---|
724 | |
---|
725 | const SEC_db_interface *db = sec_root->get_db(); |
---|
726 | |
---|
727 | if (db && db->canDisplay()) { |
---|
728 | if (update_requested & SEC_UPDATE_RELOAD) { |
---|
729 | GB_ERROR error = load(0, 0, 0, 0); // sets change_flag |
---|
730 | if (error) { |
---|
731 | error = ta.close(error); |
---|
732 | aw_message(error); |
---|
733 | } |
---|
734 | |
---|
735 | update_requested = static_cast<SEC_update_request>((update_requested^SEC_UPDATE_RELOAD)|SEC_UPDATE_RECOUNT); // clear reload flag |
---|
736 | exports.refresh = 1; |
---|
737 | } |
---|
738 | |
---|
739 | if (update_requested & SEC_UPDATE_SHOWN_POSITIONS) { |
---|
740 | sec_root->update_shown_positions(); |
---|
741 | update_requested = static_cast<SEC_update_request>((update_requested^SEC_UPDATE_SHOWN_POSITIONS)|SEC_UPDATE_RECOUNT); // clear reload flag |
---|
742 | exports.refresh = 1; |
---|
743 | } |
---|
744 | |
---|
745 | if (update_requested & SEC_UPDATE_RECOUNT) { |
---|
746 | sec_root->invalidate_base_positions(); |
---|
747 | sec_root->relayout(); |
---|
748 | |
---|
749 | update_requested = static_cast<SEC_update_request>(update_requested^SEC_UPDATE_RECOUNT); // clear recount flag |
---|
750 | exports.refresh = 1; |
---|
751 | } |
---|
752 | |
---|
753 | sec_root->perform_autoscroll(); |
---|
754 | } |
---|
755 | |
---|
756 | int res = 0; |
---|
757 | if (update_requested & SEC_UPDATE_ZOOM_RESET) { |
---|
758 | res = 1; // report zoom reset |
---|
759 | update_requested = static_cast<SEC_update_request>(update_requested^SEC_UPDATE_ZOOM_RESET); // clear zoom reset flag |
---|
760 | } |
---|
761 | return res; |
---|
762 | } |
---|
763 | |
---|
764 | void SEC_graphic::update(GBDATA *) { |
---|
765 | } |
---|
766 | |
---|
767 | void SEC_graphic::show(AW_device *device) { |
---|
768 | const char *textToDisplay = 0; |
---|
769 | |
---|
770 | sec_assert(sec_root); |
---|
771 | sec_root->clear_last_drawed_cursor_position(); |
---|
772 | |
---|
773 | if (sec_root->canDisplay()) { |
---|
774 | if (sec_root->get_root_loop()) { |
---|
775 | GB_ERROR paint_error = sec_root->paint(device); |
---|
776 | if (paint_error) textToDisplay = GBS_global_string("Error: %s", paint_error); |
---|
777 | } |
---|
778 | else { |
---|
779 | if (load_error) textToDisplay = GBS_global_string("Load error: %s", load_error); |
---|
780 | else textToDisplay = "No structure loaded (yet)"; |
---|
781 | } |
---|
782 | } |
---|
783 | else { |
---|
784 | const SEC_db_interface *db = sec_root->get_db(); |
---|
785 | |
---|
786 | if (!db) textToDisplay = "Not connected to database"; |
---|
787 | else if (!db->helix()) textToDisplay = "No helix info"; |
---|
788 | else textToDisplay = "No species selected"; |
---|
789 | } |
---|
790 | |
---|
791 | if (textToDisplay) { // no structure |
---|
792 | sec_assert(strchr(textToDisplay, '\n') == 0); // linefeeds do not work here |
---|
793 | device->text(SEC_GC_ECOLI, textToDisplay, 0, 0, 0, AW_SCREEN, 0); |
---|
794 | sec_root->set_last_drawed_cursor_position(LineVector(Origin, ZeroVector)); |
---|
795 | } |
---|
796 | } |
---|
797 | |
---|
798 | void SEC_graphic::info(AW_device */*device*/, AW_pos /*x*/, AW_pos /*y*/, AW_clicked_line */*cl*/, AW_clicked_text */*ct*/) { |
---|
799 | aw_message("INFO MESSAGE"); |
---|
800 | } |
---|
801 | |
---|
802 | |
---|