source: tags/ms_r16q3/SECEDIT/SEC_graphic.cxx

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