source: branches/help/SECEDIT/SEC_graphic.cxx

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