source: tags/ms_r16q3/EDIT4/ED4_terminal.cxx

Last change on this file was 15288, 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: 49.9 KB
Line 
1// =============================================================== //
2//                                                                 //
3//   File      : ED4_terminal.cxx                                  //
4//   Purpose   :                                                   //
5//                                                                 //
6//   Institute of Microbiology (Technical University Munich)       //
7//   http://www.arb-home.de/                                       //
8//                                                                 //
9// =============================================================== //
10
11#include <ed4_extern.hxx>
12#include "ed4_class.hxx"
13#include "ed4_awars.hxx"
14#include "ed4_edit_string.hxx"
15#include "ed4_block.hxx"
16#include "ed4_nds.hxx"
17#include "ed4_ProteinViewer.hxx"
18#include "ed4_seq_colors.hxx"
19#include "ed4_flags.hxx"
20
21#include <arbdbt.h>
22#include <items.h>
23
24#include <aw_preset.hxx>
25#include <aw_awar.hxx>
26#include <aw_awar_defs.hxx>
27#include <aw_msg.hxx>
28#include <aw_root.hxx>
29#include <aw_question.hxx>
30
31#include <st_window.hxx>
32
33// -----------------------------------
34//      static terminal properties
35
36static ED4_objspec tree_terminal_spec(
37    PROP_IS_TERMINAL,  // static props
38    LEV_TREE,           // level
39    LEV_NONE,           // allowed children level
40    LEV_NONE,           // handled object
41    LEV_NONE            // restriction level
42    );
43
44static ED4_objspec bracket_terminal_spec(
45    PROP_IS_TERMINAL,  // static props
46    LEV_BRACKET,        // level
47    LEV_NONE,           // allowed children level
48    LEV_NONE,           // handled object
49    LEV_NONE            // restriction level
50    );
51
52static ED4_objspec species_name_terminal_spec(
53    ED4_properties(PROP_IS_TERMINAL | PROP_DYNA_RESIZE),  // static props
54    LEV_SPECIES_NAME,   // level
55    LEV_NONE,           // allowed children level
56    LEV_SPECIES,        // handled object
57    LEV_NONE            // restriction level
58    );
59
60static ED4_objspec flag_header_spec(
61    ED4_properties(PROP_IS_TERMINAL | PROP_DYNA_RESIZE),  // static props
62    LEV_FLAG_HEADER,    // level
63    LEV_NONE,           // allowed children level
64    LEV_NONE,           // handled object
65    LEV_NONE            // restriction level
66    );
67
68static ED4_objspec flag_spec(
69    ED4_properties(PROP_IS_TERMINAL | PROP_DYNA_RESIZE), // static props
70    LEV_FLAG,           // level
71    LEV_NONE,           // allowed children level
72    LEV_NONE,           // handled object
73    LEV_NONE            // restriction level
74    );
75
76static ED4_objspec sequence_info_terminal_spec(
77    ED4_properties(PROP_IS_TERMINAL | PROP_DYNA_RESIZE),  // static props
78    LEV_SEQUENCE_INFO,  // level
79    LEV_NONE,           // allowed children level
80    LEV_SEQUENCE,       // handled object
81    LEV_NONE            // restriction level
82    );
83
84static ED4_objspec sequence_terminal_spec(
85    PROP_IS_TERMINAL,     // static props
86    LEV_SEQUENCE_STRING,   // level
87    LEV_NONE,              // allowed children level
88    LEV_NONE,              // handled object
89    LEV_NONE               // restriction level
90    );
91
92static ED4_objspec orf_terminal_spec(
93    PROP_IS_TERMINAL,     // static props
94    LEV_ORF,               // level
95    LEV_NONE,              // allowed children level
96    LEV_NONE,              // handled object
97    LEV_NONE               // restriction level
98    );
99
100static ED4_objspec pure_text_terminal_spec(
101    PROP_IS_TERMINAL,     // static props
102    LEV_PURE_TEXT,         // level
103    LEV_NONE,              // allowed children level
104    LEV_NONE,              // handled object
105    LEV_NONE               // restriction level
106    );
107
108static ED4_objspec spacer_terminal_spec(
109    ED4_properties(PROP_IS_TERMINAL | PROP_DYNA_RESIZE), // static props
110    LEV_SPACER,            // level
111    LEV_NONE,              // allowed children level
112    LEV_NONE,              // handled object
113    LEV_NONE               // restriction level
114    );
115
116static ED4_objspec line_terminal_spec(
117    ED4_properties(PROP_IS_TERMINAL | PROP_DYNA_RESIZE), // static props
118    LEV_LINE,              // level
119    LEV_NONE,              // allowed children level
120    LEV_NONE,              // handled object
121    LEV_NONE               // restriction level
122    );
123
124static ED4_objspec column_stat_terminal_spec(
125    PROP_IS_TERMINAL,     // static props
126    LEV_COL_STAT,          // level
127    LEV_NONE,              // allowed children level
128    LEV_NONE,              // handled object
129    LEV_NONE               // restriction level
130    );
131
132
133char *ED4_terminal::resolve_pointer_to_string_copy(int *str_len) const {
134    int         len;
135    const char *s = resolve_pointer_to_char_pntr(&len);
136    char       *t = ARB_strduplen(s, len); // space for zero byte is allocated by ARB_strduplen
137
138    if (str_len) *str_len = len;
139    return t;
140}
141
142const char *ED4_terminal::resolve_pointer_to_char_pntr(int *str_len) const
143{
144    GB_TYPES    gb_type;
145    const char *db_pointer = NULL;
146    GBDATA     *gbd        = get_species_pointer();
147
148    if (!gbd) {
149        if (str_len) {
150            if (id) *str_len = strlen(id);
151            else *str_len    = 0;
152        }
153        return id; // if we don't have a link to the database we have to use our id
154    }
155
156    GB_push_transaction(GLOBAL_gb_main);
157
158    const char *copy_of = 0; // if set, return a copy of this string
159
160    gb_type = GB_read_type(gbd);
161#if defined(WARN_TODO)
162#warning temporary workaround - gb_type GB_INT and GB_FLOAT in the switch directive must not be displayed but ignored
163#endif
164    switch (gb_type)
165    {
166        case GB_STRING:
167            db_pointer = GB_read_char_pntr(gbd);
168            if (str_len) {
169                *str_len = GB_read_string_count(gbd);
170                e4_assert(*str_len == (int)strlen(db_pointer));
171            }
172            break;
173        case GB_BITS:
174            db_pointer = GB_read_bits_pntr(gbd, '.', '+');
175            if (str_len) {
176                *str_len = GB_read_bits_count(gbd);
177                e4_assert(*str_len == (int)strlen(db_pointer));
178            }
179            break;
180        case GB_BYTES:
181            db_pointer = GB_read_bytes_pntr(gbd);
182            if (str_len) {
183                *str_len = GB_read_bytes_count(gbd);
184                e4_assert(*str_len == (int)strlen(db_pointer));
185            }
186            break;
187        case GB_DB:
188            copy_of = "GB_DB";
189            break;
190        case GB_INT: // FIXME: temporary Workaround
191            copy_of = "GB_INT";
192            break;
193        case GB_INTS:
194            copy_of = "GB_INTS";
195            break;
196        case GB_FLOAT: // FIXME: temporary Workaround
197            copy_of = "GB_FLOAT";
198            break;
199        case GB_FLOATS:
200            copy_of = "GB_FLOATS";
201            break;
202        default:
203            printf("Unknown data type - Please contact administrator\n");
204            e4_assert(0);
205            break;
206    }
207
208    if (copy_of) {
209        e4_assert(db_pointer == 0);
210
211        int len    = strlen(copy_of);
212        db_pointer = ARB_strduplen(copy_of, len);
213
214        if (str_len) *str_len = len;
215    }
216
217    GB_pop_transaction(GLOBAL_gb_main);
218
219    return db_pointer;
220}
221
222GB_ERROR ED4_terminal::write_sequence(const char *seq, int seq_len)
223{
224    GB_ERROR err = 0;
225    GBDATA *gbd = get_species_pointer();
226    e4_assert(gbd); // we must have a link to the database!
227
228    GB_push_transaction(GLOBAL_gb_main);
229
230    int   old_seq_len;
231    char *old_seq = resolve_pointer_to_string_copy(&old_seq_len);
232
233    bool allow_write_data = true;
234    if (ED4_ROOT->aw_root->awar(ED4_AWAR_ANNOUNCE_CHECKSUM_CHANGES)->read_int()) {
235        long old_checksum = GBS_checksum(old_seq, 1, "-.");
236        long new_checksum = GBS_checksum(seq, 1, "-.");
237
238        if (old_checksum != new_checksum) {
239            if (aw_question(NULL, "Checksum changed!", "Allow, Reject") == 1) {
240                allow_write_data = false;
241            }
242
243        }
244    }
245
246    if (allow_write_data) {
247        GB_TYPES gb_type = GB_read_type(gbd);
248        switch (gb_type) {
249            case GB_STRING: {
250                err = GB_write_string(gbd, seq);
251                break;
252            }
253            case GB_BITS: {
254                err = GB_write_bits(gbd, seq, seq_len, ".-");
255                break;
256            }
257            default: {
258                e4_assert(0);
259                break;
260            }
261        }
262    }
263
264    GB_pop_transaction(GLOBAL_gb_main);
265
266    if (!err && has_property(PROP_CONSENSUS_RELEVANT)) {
267        if (old_seq) {
268            curr_timestamp = GB_read_clock(GLOBAL_gb_main);
269
270            get_parent(LEV_MULTI_SPECIES)->to_multi_species_manager()
271                ->update_bases_and_rebuild_consensi(old_seq, old_seq_len, get_parent(LEV_SPECIES)->to_species_manager(), ED4_U_UP); // bases_check
272        }
273        else {
274            aw_message("Couldn't read old sequence data");
275        }
276
277        request_refresh();
278    }
279
280    if (old_seq) free(old_seq);
281
282    return err;
283}
284
285
286ED4_returncode ED4_terminal::remove_callbacks()                     // removes callbacks and gb_alignment
287{
288    if (get_species_pointer()) {
289        set_species_pointer(0);
290        tflag.deleted = 1; // @@@ why ?
291        clr_property(PROP_CURSOR_ALLOWED);
292        request_refresh();
293    }
294    return ED4_R_OK;
295}
296
297#if 0
298static ARB_ERROR ed4_remove_species_manager_callbacks(ED4_base *base) { // @@@ unused since [8286]
299    if (base->is_species_manager()) {
300        base->to_species_manager()->remove_all_callbacks();
301    }
302    return NULL;
303}
304#endif
305
306inline void remove_from_consensus(ED4_manager *group_or_species_man) {
307    GB_transaction ta(GLOBAL_gb_main);
308    ED4_manager *parent_manager = group_or_species_man->parent;
309    parent_manager->update_consensus(parent_manager, NULL, group_or_species_man);
310    parent_manager->rebuild_consensi(parent_manager, ED4_U_UP);
311}
312
313ED4_returncode ED4_terminal::kill_object() {
314    ED4_species_manager *species_manager = get_parent(LEV_SPECIES)->to_species_manager();
315
316    if (species_manager->is_consensus_manager()) { // kill whole group
317        if (ED4_find_MoreSequences_manager()==species_manager->parent) {
318            aw_message("This group has to exist - deleting it isn't allowed");
319            return ED4_R_IMPOSSIBLE;
320        }
321
322        ED4_manager *group_manager = species_manager->get_parent(LEV_GROUP)->to_group_manager();
323        remove_from_consensus(group_manager);
324        group_manager->Delete();
325    }
326    else { // kill single species/SAI
327        remove_from_consensus(species_manager);
328        species_manager->Delete();
329    }
330
331    return ED4_R_OK;
332}
333
334ED4_base *ED4_terminal::get_competent_clicked_child(AW_pos /* x */, AW_pos /* y */, ED4_properties /* relevant_prop */)
335{
336    e4_assert(0);
337    return NULL;
338}
339
340ED4_returncode   ED4_terminal::handle_move(ED4_move_info * /* moveinfo */)
341{
342    e4_assert(0);
343    return ED4_R_IMPOSSIBLE;
344}
345
346ED4_returncode  ED4_terminal::move_requested_by_child(ED4_move_info * /* moveinfo */)
347{
348    e4_assert(0);
349    return ED4_R_IMPOSSIBLE;
350}
351
352
353ED4_base *ED4_terminal::get_competent_child(AW_pos /* x */, AW_pos /* y */, ED4_properties /* relevant_prop */)
354{
355    e4_assert(0);
356    return NULL;
357}
358
359ED4_returncode ED4_terminal::draw_drag_box(AW_pos x, AW_pos y, GB_CSTR text, int cursor_y) {
360    // draws drag box of object at location abs_x, abs_y
361
362    if (cursor_y!=-1) {
363        ED4_base *drag_target = NULL;
364        {
365            ED4_extension location;
366            location.position[X_POS] = 0;
367            location.position[Y_POS] = (AW_pos)cursor_y;           // cursor_y is already in world coordinates
368
369            ED4_ROOT->get_device_manager()->search_target_species(&location, PROP_HORIZONTAL, &drag_target, LEV_NONE);
370        }
371
372        if (drag_target) {
373            AW_pos target_x, target_y;
374
375            drag_target->calc_world_coords (&target_x, &target_y);
376            current_ed4w()->world_to_win_coords(&target_x, &target_y);
377
378#define ARROW_LENGTH 3
379            AW_pos drag_line_x0[3], drag_line_y0[3];
380            AW_pos drag_line_x1[3], drag_line_y1[3];
381
382            drag_line_x0[0] = target_x + 5;                                                 // horizontal
383            drag_line_y0[0] = target_y + drag_target->extension.size[HEIGHT];
384            drag_line_x1[0] = drag_line_x0[0] + 50;
385            drag_line_y1[0] = target_y + drag_target->extension.size[HEIGHT];
386
387            drag_line_x0[1] = drag_line_x0[0] -ARROW_LENGTH;                                // arrow
388            drag_line_y0[1] = drag_line_y0[0] -ARROW_LENGTH;
389            drag_line_x1[1] = drag_line_x0[0];
390            drag_line_y1[1] = drag_line_y0[0];
391
392            drag_line_x0[2] = drag_line_x0[0] -ARROW_LENGTH;                                // arrow
393            drag_line_y0[2] = drag_line_y0[0] + ARROW_LENGTH;
394            drag_line_x1[2] = drag_line_x0[0];
395            drag_line_y1[2] = drag_line_y0[0];
396#undef ARROW_LENGTH
397
398            for (ED4_index i = 0; i <= 2; i++) {
399                current_device()->line(ED4_G_DRAG, drag_line_x0[i], drag_line_y0[i], drag_line_x1[i], drag_line_y1[i], AW_SCREEN);
400            }
401        }
402    }
403
404    if (text != NULL) {
405        current_device()->text(ED4_G_DRAG, text, (x + 20), (y + INFO_TERM_TEXT_YOFFSET), 0, AW_SCREEN);
406    }
407
408    return ED4_R_OK;
409}
410
411ED4_returncode  ED4_terminal::move_requested_by_parent(ED4_move_info *) { // handles a move request coming from parent
412    e4_assert(0);
413    return (ED4_R_IMPOSSIBLE);
414}
415
416void ED4_multi_species_manager::toggle_selected_species() {
417    if (all_are_selected()) deselect_all_species_and_SAI();
418    else select_all(false); // species and SAI
419
420    ED4_correctBlocktypeAfterSelection();
421}
422
423#if defined(DEBUG) && 1
424static inline void dumpEvent(const char *where, AW_event *event) {
425    printf("%s: x=%i y=%i\n", where, event->x, event->y);
426}
427#else
428#define dumpEvent(w, e)
429#endif
430
431ED4_returncode ED4_terminal::event_sent_by_parent(AW_event *event, AW_window *aww) {
432    // handles an input event coming from parent
433
434    // static data to move terminal:
435    static ED4_species_name_terminal *dragged_name_terminal = 0;
436
437    static bool pressed_left_button  = false;
438    static int  other_x, other_y;                                    // coordinates of last event
439    static bool dragged_was_selected = false;                        // the dragged terminal is temp. added to selected
440
441    // ----------------------------
442    //      drag/drop terminal
443    if (dragged_name_terminal) {
444        if (event->button == AW_BUTTON_LEFT) {
445            switch (event->type) {
446                case AW_Mouse_Drag: {
447                    ED4_selection_entry *sel_info = dragged_name_terminal->selection_info;
448
449                    if (pressed_left_button) {
450                        AW_pos world_x, world_y;
451
452                        dragged_name_terminal->calc_world_coords(&world_x, &world_y);
453                        current_ed4w()->world_to_win_coords(&world_x, &world_y);
454
455                        sel_info->drag_old_x = world_x;
456                        sel_info->drag_old_y = world_y;
457                        sel_info->drag_off_x = world_x-other_x;
458                        sel_info->drag_off_y = world_y-other_y;
459                        sel_info->old_event_y = -1;
460
461                        pressed_left_button = false;
462                    }
463
464                    GB_CSTR text = dragged_name_terminal->get_displayed_text();
465
466                    if (dragged_name_terminal->dragged) {
467                        dragged_name_terminal->draw_drag_box(sel_info->drag_old_x, sel_info->drag_old_y, text, sel_info->old_event_y);
468                    }
469
470                    AW_pos new_x = sel_info->drag_off_x + event->x;
471                    AW_pos new_y = sel_info->drag_off_y + event->y;
472
473                    dragged_name_terminal->draw_drag_box(new_x, new_y, text, event->y); // @@@ event->y ist falsch, falls vertikal gescrollt ist!
474
475                    sel_info->drag_old_x = new_x;
476                    sel_info->drag_old_y = new_y;
477                    sel_info->old_event_y = event->y;
478
479                    dragged_name_terminal->dragged = true;
480                    break;
481                }
482                case AW_Mouse_Release: {
483                    if (dragged_name_terminal->dragged) {
484                        {
485                            char                *db_pointer = dragged_name_terminal->resolve_pointer_to_string_copy();
486                            ED4_selection_entry *sel_info   = dragged_name_terminal->selection_info;
487
488                            dragged_name_terminal->draw_drag_box(sel_info->drag_old_x, sel_info->drag_old_y, db_pointer, sel_info->old_event_y);
489                            dragged_name_terminal->dragged = false;
490
491                            free(db_pointer);
492                        }
493                        {
494                            ED4_move_info mi;
495
496                            mi.object = dragged_name_terminal;
497                            mi.end_x = event->x;
498                            mi.end_y = event->y;
499                            mi.mode = ED4_M_FREE;
500                            mi.preferred_parent = LEV_NONE;
501
502                            dragged_name_terminal->parent->move_requested_by_child(&mi);
503                        }
504                        {
505                            ED4_device_manager *device_manager = ED4_ROOT->get_device_manager();
506
507                            for (int i=0; i<device_manager->members(); i++) { // when moving species numbers have to be recalculated
508                                ED4_base *member = device_manager->member(i);
509
510                                if (member->is_area_manager()) {
511                                    member->to_area_manager()->get_multi_species_manager()->update_requested_by_child();
512                                }
513                            }
514                        }
515                    }
516                    if (!dragged_was_selected) {
517                        ED4_ROOT->remove_from_selected(dragged_name_terminal);
518                    }
519
520                    pressed_left_button = false;
521                    dragged_name_terminal = 0;
522                    break;
523                }
524                default:
525                    break;
526            }
527        }
528    }
529    else {
530        switch (event->button) {
531            case AW_BUTTON_LEFT: {
532                if (is_species_name_terminal()) {
533                    switch (ED4_ROOT->species_mode) {
534                        case ED4_SM_KILL: {
535                            if (event->type == AW_Mouse_Press) {
536                                if (containing_species_manager()->is_selected()) ED4_ROOT->remove_from_selected(this->to_species_name_terminal());
537                                kill_object();
538                                return ED4_R_BREAK;
539                            }
540                            break;
541                        }
542                        case ED4_SM_MOVE: {
543                            if (event->type == AW_Mouse_Press) {
544                                dragged_name_terminal = to_species_name_terminal();
545                                pressed_left_button   = true;
546
547                                other_x = event->x;
548                                other_y = event->y;
549
550                                dragged_was_selected = containing_species_manager()->is_selected();
551                                if (!dragged_was_selected) {
552                                    ED4_ROOT->add_to_selected(dragged_name_terminal);
553                                    ED4_trigger_instant_refresh();
554                                }
555                            }
556                            break;
557                        }
558                        case ED4_SM_INFO:
559                        case ED4_SM_MARK: {
560                            static ED4_species_manager *prev_clicked_species_man = NULL;
561                            ED4_species_manager        *species_man              = get_parent(LEV_SPECIES)->to_species_manager();
562
563                            GBDATA *gbd = species_man->get_species_pointer();
564                            if (gbd) {
565                                bool       acceptClick = false;
566                                static int markHow     = -1;  // -1=invert, 0=unmark, 1=mark
567                                {
568                                    switch (event->type) {
569                                        case AW_Mouse_Press:
570                                            acceptClick = true;
571                                            markHow     = -1;
572                                            break;
573
574                                        case AW_Mouse_Drag:
575                                            acceptClick = prev_clicked_species_man != species_man;
576                                            break;
577
578                                        case AW_Mouse_Release:
579                                            acceptClick              = prev_clicked_species_man != species_man;
580                                            prev_clicked_species_man = NULL;
581                                            break;
582
583                                        case AW_Keyboard_Press:
584                                        case AW_Keyboard_Release:
585                                            e4_assert(0); // impossible
586                                            break;
587                                    }
588                                }
589
590                                if (acceptClick) {
591                                    if (ED4_ROOT->species_mode == ED4_SM_MARK) {
592                                        if (markHow<0) markHow = !GB_read_flag(gbd);
593                                        GB_write_flag(gbd, markHow);
594                                        request_refresh();
595                                        if (ED4_ROOT->alignment_type ==  GB_AT_DNA) PV_RefreshWindow(aww->get_root()); // ProtView: Refreshing orf terminals (@@@ weird place to perform refresh)
596                                    }
597                                    else {
598                                        e4_assert(ED4_ROOT->species_mode == ED4_SM_INFO);
599
600                                        const char *name = GBT_read_name(gbd);
601                                        if (name) {
602                                            const char *awar_select = species_man->inside_SAI_manager() ? AWAR_SAI_NAME : AWAR_SPECIES_NAME;
603                                            ED4_ROOT->aw_root->awar(awar_select)->write_string(name);
604                                        }
605                                    }
606                                    prev_clicked_species_man = species_man;
607                                }
608                            }
609                            else {
610                                prev_clicked_species_man = NULL;
611                            }
612                            break;
613                        }
614                    }
615                }
616                else if (is_bracket_terminal()) { // fold/unfold group
617                    if (event->type == AW_Mouse_Press) {
618                        to_bracket_terminal()->toggle_folding();
619                    }
620                }
621                else if (is_sequence_terminal()) {
622                    if (has_property(PROP_CURSOR_ALLOWED)) {
623                        ED4_no_dangerous_modes();
624                        current_cursor().show_clicked_cursor(event->x, this);
625                    }
626                }
627                else if (is_flag_terminal()) {
628                    if (event->type == AW_Mouse_Press) {
629                        to_flag_terminal()->handle_left_click(AW::Position(event->x, event->y));
630                    }
631                }
632
633                break;
634            }
635            case AW_BUTTON_RIGHT: {
636                // static data for block-selection:
637                static bool select_started_on_seqterm = false;
638
639                switch (event->type) {
640                    case AW_Mouse_Press: {
641                        select_started_on_seqterm = false;
642                        if (is_species_name_terminal()) {
643                            ED4_species_manager *species_man = get_parent(LEV_SPECIES)->to_species_manager();
644
645                            if (species_man->is_consensus_manager()) { // click on consensus-name
646                                ED4_multi_species_manager *multi_man = species_man->get_parent(LEV_MULTI_SPECIES)->to_multi_species_manager();
647                                multi_man->toggle_selected_species();
648                            }
649                            else { // click on species or SAI name
650                                if (!species_man->is_selected()) { // select if not selected
651                                    if (ED4_ROOT->add_to_selected(this->to_species_name_terminal()) == ED4_R_OK) ED4_correctBlocktypeAfterSelection();
652                                }
653                                else { // deselect if already selected
654                                    ED4_ROOT->remove_from_selected(this->to_species_name_terminal());
655                                    ED4_correctBlocktypeAfterSelection();
656                                }
657                            }
658                        }
659                        else if (is_bracket_terminal()) {
660                            ED4_base *group = get_parent(LEV_GROUP);
661                            if (group) {
662                                group->to_group_manager()->get_multi_species_manager()->toggle_selected_species();
663                            }
664                        }
665                        else if (is_sequence_terminal()) {
666                            ED4_no_dangerous_modes();
667                            ED4_setColumnblockCorner(event, to_sequence_terminal()); // mark columnblock
668                            select_started_on_seqterm = true;
669                        }
670                        break;
671                    }
672
673                    case AW_Mouse_Drag:
674                    case AW_Mouse_Release:
675                        if (select_started_on_seqterm && is_sequence_terminal()) {
676                            ED4_no_dangerous_modes();
677                            ED4_setColumnblockCorner(event, to_sequence_terminal()); // mark columnblock
678                        }
679                        break;
680
681                    default:
682                        break;
683                }
684                break;
685            }
686
687            default: break;
688        }
689    }
690
691    return (ED4_R_OK);
692}
693
694void ED4_terminal::update_requested_children() {}
695
696bool ED4_terminal::calc_bounding_box() {
697    // calculates the smallest rectangle containing the object.
698    // requests refresh and returns true if bounding box has changed.
699
700    bool bb_changed = false;
701
702    if (width_link) {
703        bb_changed = extension.set_size_does_change(WIDTH, width_link->extension.size[WIDTH]) || bb_changed;
704    }
705
706    if (height_link) {
707        bb_changed = extension.set_size_does_change(HEIGHT, height_link->extension.size[HEIGHT]) || bb_changed;
708    }
709
710
711    if (bb_changed) {
712        request_resize_of_linked();
713        request_refresh();
714    }
715    return bb_changed;
716}
717
718void ED4_terminal::resize_requested_children() {
719    if (update_info.resize) { // likes to resize?
720        if (calc_bounding_box()) request_resize();
721    }
722}
723
724
725void ED4_terminal::request_refresh(int clear) {
726    update_info.set_refresh(1);
727    update_info.set_clear_at_refresh(clear);
728    if (parent) parent->refresh_requested_by_child();
729}
730
731
732ED4_base* ED4_terminal::search_ID(const char *temp_id) {
733    if (id && strcmp(temp_id, id) == 0) return (this);
734    return (NULL);
735}
736
737void ED4_terminal::Show(bool IF_ASSERTION_USED(refresh_all), bool is_cleared) {
738    e4_assert(update_info.refresh || refresh_all);
739    current_device()->push_clip_scale();
740    if (adjust_clipping_rectangle()) {
741        if (update_info.clear_at_refresh && !is_cleared) {
742            clear_background();
743        }
744        draw();
745    }
746    current_device()->pop_clip_scale();
747}
748
749ED4_terminal::ED4_terminal(const ED4_objspec& spec_, GB_CSTR temp_id, AW_pos width, AW_pos height, ED4_manager *temp_parent) :
750    ED4_base(spec_, temp_id, width, height, temp_parent)
751{
752    memset((char*)&tflag, 0, sizeof(tflag));
753    curr_timestamp = 0;
754}
755
756
757ED4_terminal::~ED4_terminal() {
758    for (ED4_window *window = ED4_ROOT->first_window; window; window=window->next) {
759        ED4_cursor& cursor = window->cursor;
760        if (this == cursor.owner_of_cursor) {
761            cursor.init();
762        }
763    }
764}
765
766ED4_tree_terminal::ED4_tree_terminal(const char *temp_id, AW_pos width, AW_pos height, ED4_manager *temp_parent)
767    : ED4_terminal(tree_terminal_spec, temp_id, width, height, temp_parent)
768{
769}
770
771void ED4_tree_terminal::draw() {
772    AW_pos  x, y;
773    AW_pos  text_x, text_y;
774    char   *db_pointer;
775
776    calc_world_coords(&x, &y);
777    current_ed4w()->world_to_win_coords(&x, &y);
778
779    text_x = x + CHARACTEROFFSET;                           // don't change
780    text_y = y + SEQ_TERM_TEXT_YOFFSET;
781
782    db_pointer = resolve_pointer_to_string_copy();
783    current_device()->text(ED4_G_STANDARD, db_pointer, text_x, text_y, 0, AW_SCREEN);
784    free(db_pointer);
785}
786
787ED4_bracket_terminal::ED4_bracket_terminal(const char *temp_id, AW_pos width, AW_pos height, ED4_manager *temp_parent)
788    : ED4_terminal(bracket_terminal_spec, temp_id, width, height, temp_parent)
789{
790}
791
792void ED4_bracket_terminal::draw() {
793    using namespace AW;
794
795    Rectangle  term_area = get_win_area(current_ed4w());
796    AW_device *device    = current_device();
797
798    ED4_multi_species_manager *multi_man = get_parent(LEV_GROUP)->to_group_manager()->get_multi_species_manager();
799    if (multi_man->get_no_of_selected_species()) {  // if multi_species_manager contains selected species
800#if defined(DEBUG) && 0
801        static bool toggle = false;
802        toggle             = !toggle;
803        device->box(toggle ? ED4_G_SELECTED : ED4_G_SELECTED+1, AW::FillStyle::SOLID, term_area);
804#else // !defined(DEBUG)
805        device->box(ED4_G_SELECTED, AW::FillStyle::SOLID, term_area);
806#endif
807    }
808
809    e4_assert(parent->is_group_manager());
810    if (parent->has_property(PROP_IS_FOLDED)) { // for folded group, paint triangle pointing rightwards
811        Position t = term_area.upper_left_corner()+Vector(4,4);
812        Position b = t+Vector(0,12);
813
814        for (int i = 0; i<6; ++i) {
815            device->line(ED4_G_STANDARD, t, b, AW_SCREEN);
816            t += Vector(1,  1);
817            b += Vector(1, -1);
818        }
819        e4_assert(nearlyEqual(t, b));
820        device->line(ED4_G_STANDARD, t, b, AW_SCREEN); // arrowhead
821    }
822    else { // for unfolded group, paint triangle pointing downwards
823        Position l = term_area.upper_left_corner()+Vector(4,5);
824        Position r = l+Vector(6,0);
825
826        for (int i = 0; i<3; ++i) {
827            device->line(ED4_G_STANDARD, l, r, AW_SCREEN);
828            l += Vector( 0, 1);
829            r += Vector( 0, 1);
830            device->line(ED4_G_STANDARD, l, r, AW_SCREEN);
831            l += Vector( 1, 1);
832            r += Vector(-1, 1);
833        }
834        e4_assert(nearlyEqual(l, r));
835        device->line(ED4_G_STANDARD, l, r+Vector(0,1), AW_SCREEN); // arrowhead
836    }
837
838    {
839        Rectangle bracket(term_area.upper_left_corner()+Vector(2,2), term_area.diagonal()+Vector(-2,-4));
840
841        device->line(ED4_G_STANDARD, bracket.upper_edge(), AW_SCREEN);
842        device->line(ED4_G_STANDARD, bracket.lower_edge(), AW_SCREEN);
843        device->line(ED4_G_STANDARD, bracket.left_edge(), AW_SCREEN);
844    }
845}
846
847ED4_species_name_terminal::ED4_species_name_terminal(GB_CSTR temp_id, AW_pos width, AW_pos height, ED4_manager *temp_parent) :
848    ED4_text_terminal(species_name_terminal_spec, temp_id, width, height, temp_parent),
849    selection_info(NULL),
850    dragged(false)
851{
852}
853
854#define MAXNAMELEN MAXNAME_WIDTH // @@@ seems wrong (MAXNAME_WIDTH contains pixel)
855#define BUFFERSIZE (MAXNAMELEN<<1)
856GB_CSTR ED4_species_name_terminal::get_displayed_text() const
857{
858    static char *real_name;
859    static int allocatedSize;
860
861    if (!real_name || allocatedSize<(BUFFERSIZE+1)) {
862        free(real_name);
863        allocatedSize = BUFFERSIZE+1;
864        ARB_alloc(real_name, allocatedSize);
865    }
866    memset(real_name, 0, allocatedSize);
867
868    ED4_species_manager *spec_man = get_parent(LEV_SPECIES)->to_species_manager();
869
870    if (spec_man->is_consensus_manager()) {
871        char *db_pointer = resolve_pointer_to_string_copy();
872        char *bracket = strchr(db_pointer, '(');
873
874        if (bracket) {
875            int bracket_len = strlen(bracket);
876            int name_len = bracket-db_pointer;
877
878            if (bracket[-1]==' ') {
879                name_len--;
880            }
881
882            if ((name_len+1+bracket_len)<=MAXNAMELEN) {
883                strcpy(real_name, db_pointer);
884            }
885            else {
886                int short_name_len = MAXNAMELEN-bracket_len-1;
887
888                memcpy(real_name, db_pointer, short_name_len);
889                real_name[short_name_len] = ' ';
890                strcpy(real_name+short_name_len+1, bracket);
891            }
892        }
893        else {
894            strncpy(real_name, db_pointer, BUFFERSIZE);
895        }
896
897        free(db_pointer);
898    }
899    else if (spec_man->is_SAI_manager()) {
900        char *db_pointer = resolve_pointer_to_string_copy();
901
902        strcpy(real_name, "SAI: ");
903        if (strcmp(db_pointer, "ECOLI")==0) {
904            const char *name_for_ecoli = ED4_ROOT->aw_root->awar(ED4_AWAR_NDS_ECOLI_NAME)->read_char_pntr();
905            if (name_for_ecoli[0]==0) name_for_ecoli = db_pointer;
906            strncpy(real_name+5, name_for_ecoli, BUFFERSIZE-5);
907        }
908        else {
909            strncpy(real_name+5, db_pointer, BUFFERSIZE-5);
910        }
911        free(db_pointer);
912    }
913    else { // normal species
914        char *result = ED4_get_NDS_text(spec_man);
915        strncpy(real_name, result, BUFFERSIZE);
916        free(result);
917    }
918
919    return real_name;
920}
921#undef MAXNAMELEN
922#undef BUFFERSIZE
923
924
925ED4_sequence_info_terminal::ED4_sequence_info_terminal(const char *temp_id, AW_pos width, AW_pos height, ED4_manager *temp_parent)
926    : ED4_text_terminal(sequence_info_terminal_spec, temp_id, width, height, temp_parent)
927{
928}
929
930ED4_consensus_sequence_terminal::ED4_consensus_sequence_terminal(const char *temp_id, AW_pos width, AW_pos height, ED4_manager *temp_parent)
931    : ED4_sequence_terminal(temp_id, width, height, temp_parent, false),
932      temp_cons_seq(NULL)
933{
934    species_name = NULL;
935}
936
937char *ED4_consensus_sequence_terminal::get_sequence_copy(int *str_len) const {
938    return get_group_manager()->build_consensus_string(str_len);
939}
940
941int ED4_consensus_sequence_terminal::get_length() const {
942    return get_char_table().size();
943}
944
945
946ED4_abstract_sequence_terminal::ED4_abstract_sequence_terminal(const ED4_objspec& spec_, const char *temp_id, AW_pos width, AW_pos height, ED4_manager *temp_parent)
947    : ED4_text_terminal(spec_, temp_id, width, height, temp_parent)
948{
949    species_name = NULL;
950}
951
952ED4_abstract_sequence_terminal::~ED4_abstract_sequence_terminal() {
953    free(species_name);
954}
955
956ED4_orf_terminal::ED4_orf_terminal(const char *temp_id, AW_pos width, AW_pos height, ED4_manager *temp_parent)
957    : ED4_abstract_sequence_terminal(orf_terminal_spec, temp_id, width, height, temp_parent)
958{
959    aaSequence   = 0;
960    aaSeqLen     = 0;
961    aaColor      = 0;
962    aaStartPos   = 0;
963    aaStrandType = 0;
964}
965
966GB_alignment_type ED4_orf_terminal::GetAliType()
967{
968    return (GB_alignment_type) GB_AT_AA;
969}
970
971ED4_orf_terminal::~ED4_orf_terminal()
972{
973    free(aaSequence);
974    free(aaColor);
975}
976
977ED4_sequence_terminal::ED4_sequence_terminal(const char *temp_id, AW_pos width, AW_pos height, ED4_manager *temp_parent, bool shall_display_secstruct_info_)
978    : ED4_abstract_sequence_terminal(sequence_terminal_spec, temp_id, width, height, temp_parent),
979      shall_display_secstruct_info(shall_display_secstruct_info_)
980{
981    st_ml_node = NULL;
982}
983
984GB_alignment_type ED4_sequence_terminal::GetAliType()
985{
986    return ED4_ROOT->alignment_type;
987}
988
989ED4_pure_text_terminal::ED4_pure_text_terminal(const char *temp_id, AW_pos width, AW_pos height, ED4_manager *temp_parent)
990    : ED4_text_terminal(pure_text_terminal_spec, temp_id, width, height, temp_parent)
991{
992}
993
994#if defined(DEVEL_RALF) && 0
995// # define DEBUG_SPACER_TERMINALS 0 // show placeholder-spacers (normally not drawn)
996// # define DEBUG_SPACER_TERMINALS 1 // show erasing spacers (normally area gets erased)
997# define DEBUG_SPACER_TERMINALS 2 // show all spacers
998#endif
999
1000void ED4_spacer_terminal::Show(bool /*refresh_all*/, bool is_cleared) {
1001#if defined(DEBUG_SPACER_TERMINALS)
1002    if (DEBUG_SPACER_TERMINALS == 1) {
1003        if (shallDraw) {
1004            draw();
1005        }
1006        else if (update_info.clear_at_refresh && !is_cleared) {
1007            clear_background(0);
1008        }
1009    }
1010    else {
1011        draw();
1012    }
1013#else // !DEBUG_SPACER_TERMINALS
1014    if (shallDraw || (update_info.clear_at_refresh && !is_cleared)) {
1015        draw();
1016    }
1017#endif
1018}
1019
1020
1021void ED4_spacer_terminal::draw() {
1022    int gc = 0;
1023#if defined(DEBUG_SPACER_TERMINALS)
1024    const int GC_COUNT = ED4_G_LAST_COLOR_GROUP - ED4_G_FIRST_COLOR_GROUP + 1;
1025    gc                 = ((long(this)/32)%GC_COUNT)+ED4_G_FIRST_COLOR_GROUP; // draw colored spacers to make them visible
1026
1027    if (DEBUG_SPACER_TERMINALS != 2) {
1028        bool highlight     = bool(DEBUG_SPACER_TERMINALS) == shallDraw;
1029        if (!highlight) gc = 0;
1030    }
1031#endif // DEBUG_SPACER_TERMINALS
1032    clear_background(gc);
1033}
1034
1035ED4_spacer_terminal::ED4_spacer_terminal(const char *temp_id, bool shallDraw_, AW_pos width, AW_pos height, ED4_manager *temp_parent)
1036    : ED4_terminal(spacer_terminal_spec, temp_id, width, height, temp_parent),
1037      shallDraw(shallDraw_)
1038{
1039    // 'shallDraw_'==true is only needed in very special cases,
1040    // eg. for 'Top_Middle_Spacer' (to remove overlapping relicts from half-displayed species below)
1041}
1042
1043void ED4_line_terminal::draw() {
1044    AW_pos x1, y1;
1045    calc_world_coords(&x1, &y1);
1046    current_ed4w()->world_to_win_coords(&x1, &y1);
1047
1048    AW_pos x2 = x1+extension.size[WIDTH]-1;
1049    AW_pos y2 = y1+extension.size[HEIGHT]-1;
1050
1051    AW_device *device = current_device();
1052
1053    device->line(ED4_G_STANDARD, x1, y1, x2, y1);
1054#if defined(DEBUG)
1055    device->box(ED4_G_MARKED, AW::FillStyle::SOLID, x1, y1+1, x2-x1+1, y2-y1-1);
1056#else
1057    device->clear_part(x1, y1+1, x2-x1+1, y2-y1-1, AW_ALL_DEVICES);
1058#endif // DEBUG
1059    device->line(ED4_G_STANDARD, x1, y2, x2, y2);
1060}
1061
1062ED4_line_terminal::ED4_line_terminal(const char *temp_id, AW_pos width, AW_pos height, ED4_manager *temp_parent)
1063    : ED4_terminal(line_terminal_spec, temp_id, width, height, temp_parent)
1064{
1065}
1066
1067// ---------------------------------
1068//      ED4_columnStat_terminal
1069
1070inline char stat2display(int val, bool is_upper_digit) {
1071    if (val<0) {
1072        e4_assert(val==-1); // -1 indicates that no statistic is existing for that column
1073        return '?';
1074    }
1075    if (val==20) return ' '; // value if ACGT and - are distributed equally
1076    if (val==100) return '^'; // we have only 2 characters to display likelihood (100 cannot be displayed)
1077
1078    e4_assert(val>=0 && val<100);
1079
1080    return '0' + (is_upper_digit ? (val/10) : (val%10));
1081}
1082
1083inline int find_significant_positions(int sig, int like_A, int like_C, int like_G, int like_TU, int *sumPtr) {
1084    // result == 0      -> no base-char has a significant likelihood (>=sig)
1085    // result == 1, 2, 4, 8     -> A, C, G, T/U has a significant likelihood
1086    // else             -> the sum two of the likelihoods >= sig (bit-or-ed as in line above)
1087
1088    int like[4];
1089    like[0] = like_A;
1090    like[1] = like_C;
1091    like[2] = like_G;
1092    like[3] = like_TU;
1093
1094    int bestSum = 0;
1095    int bestResult = 0;
1096
1097    int b, c;
1098    for (b=0; b<4; b++) {
1099        int sum = like[b];
1100        if (sum>=sig && sum>=bestSum) {
1101            bestSum = sum;
1102            bestResult = 1<<b;
1103        }
1104    }
1105
1106    if (!bestResult) {
1107        for (b=0; b<4; b++) {
1108            for (c=b+1; c<4; c++) {
1109                int sum = like[b]+like[c];
1110                if (sum>=sig && sum>=bestSum) {
1111                    bestSum = sum;
1112                    bestResult = (1<<b)|(1<<c);
1113                }
1114            }
1115        }
1116    }
1117
1118    if (bestResult) {
1119        if (sumPtr) *sumPtr = bestSum;
1120        return bestResult;
1121    }
1122
1123    return 0;
1124}
1125
1126void ED4_columnStat_terminal::draw() {
1127    AW_pos x, y;
1128    calc_world_coords(&x, &y);
1129    current_ed4w()->world_to_win_coords(&x, &y);
1130
1131    AW_pos term_height = extension.size[HEIGHT];
1132    AW_pos font_height = ED4_ROOT->font_group.get_height(ED4_G_SEQUENCES);
1133    AW_pos font_width  = ED4_ROOT->font_group.get_width(ED4_G_SEQUENCES);
1134
1135    AW_pos text_x = x + CHARACTEROFFSET;
1136    AW_pos text_y = y + term_height - font_height;
1137
1138    AW_device *device = current_device();
1139
1140    if (!update_likelihood()) {
1141        const char *warning = "Failed to calculate likelihood";
1142        size_t      len     = strlen(warning);
1143
1144        device->text(ED4_G_STANDARD, warning, text_x, text_y, 0, AW_SCREEN, len);
1145        return;
1146    }
1147
1148    ED4_sequence_terminal *seq_term = corresponding_sequence_terminal();
1149    const ED4_remap       *rm       = ED4_ROOT->root_group_man->remap();
1150
1151    PosRange index_range = rm->clip_screen_range(seq_term->calc_update_interval());
1152    {
1153        int max_seq_len = seq_term->get_length();
1154        int max_seq_pos = rm->sequence_to_screen(max_seq_len);
1155
1156        index_range = ExplicitRange(index_range, max_seq_pos);
1157        if (index_range.is_empty()) return; // nothing to draw
1158    }
1159
1160    const int left  = index_range.start();
1161    const int right = index_range.end();
1162
1163    char *sbuffer = new char[right+2];  // used to build displayed terminal content  (values = '0'-'9')
1164    memset(sbuffer, ' ', right+1);
1165    sbuffer[right+1] = 0; // eos
1166
1167    AW_pos y2;
1168    int r;
1169
1170    // Set background:
1171    {
1172        int significance = int(get_threshold());
1173        // normal columns are colored in ED4_G_STANDARD
1174        // all columns with one (or sum of two) probability above 'significance' are back-colored in ED4_G_CBACK_0
1175        // the responsible probabilities (one or two) are back-colored in ED4_G_CBACK_1..ED4_G_CBACK_9
1176
1177        int old_color = ED4_G_STANDARD;
1178
1179        AW_pos x2     = text_x + font_width*left + 1;
1180        AW_pos old_x2 = x2;
1181
1182        PosRange selection;
1183        bool     is_selected = ED4_get_selected_range(seq_term, selection);
1184
1185        for (int i=left; i<=right; i++, x2+=font_width) { // colorize significant columns in ALL rows
1186            int p = rm->screen_to_sequence(i);
1187            int found = find_significant_positions(significance, likelihood[0][p], likelihood[1][p], likelihood[2][p], likelihood[3][p], 0);
1188
1189            int color;
1190            if (is_selected && selection.contains(p)) {
1191                color = ED4_G_SELECTED;
1192            }
1193            else {
1194                color = found ? ED4_G_CBACK_0 : ED4_G_STANDARD;
1195            }
1196
1197            if (color!=old_color) {
1198                if (x2>old_x2 && old_color!=ED4_G_STANDARD) {
1199                    device->box(old_color, AW::FillStyle::SOLID, old_x2, y, x2-old_x2, term_height);
1200                }
1201                old_color = color;
1202                old_x2 = x2;
1203            }
1204        }
1205        if (x2>old_x2 && old_color!=ED4_G_STANDARD) {
1206            device->box(old_color, AW::FillStyle::SOLID, old_x2, y, x2-old_x2, term_height);
1207        }
1208
1209        x2 = text_x + font_width*left + 1;
1210
1211        for (int i=left; i<=right; i++, x2+=font_width) { // colorize significant columns in SINGLE rows
1212            int p = rm->screen_to_sequence(i);
1213            int sum;
1214            int found = find_significant_positions(significance, likelihood[0][p], likelihood[1][p], likelihood[2][p], likelihood[3][p], &sum);
1215
1216            if (found && significance<100) {
1217                e4_assert(sum>=significance && sum<=100);
1218                int color = ED4_G_CBACK_1+((sum-significance)*(ED4_G_CBACK_9-ED4_G_CBACK_1))/(100-significance);
1219                e4_assert(color>=ED4_G_CBACK_1 && color<=ED4_G_CBACK_9);
1220
1221                if (color!=ED4_G_STANDARD) {
1222                    int bit;
1223
1224                    for (r=3, y2=text_y+1, bit=1<<3;
1225                         r>=0;
1226                         r--, y2-=COLUMN_STAT_ROW_HEIGHT(font_height), bit>>=1)
1227                    {
1228                        if (found&bit) {
1229                            device->box(color, AW::FillStyle::SOLID, x2, y2-2*font_height+1, font_width, 2*font_height);
1230                        }
1231                    }
1232                }
1233            }
1234        }
1235    }
1236
1237    // Draw text:
1238    for (r=3, y2=text_y;
1239         r>=0;
1240         r--, y2-=COLUMN_STAT_ROW_HEIGHT(font_height)) { // 4 rows (one for T/U, G, C and A)
1241
1242        int gc = ED4_ROOT->sequence_colors->char_2_gc[(unsigned char)"ACGU"[r]];
1243        int i;
1244        for (i=left; i<=right; i++) {
1245            int p = rm->screen_to_sequence(i);
1246            int val = likelihood[r][p];
1247            sbuffer[i] = stat2display(val, 0); // calc lower digit
1248        }
1249        device->text(gc, sbuffer, text_x+font_width*0.2, y2, 0, AW_SCREEN, right); // draw lower-significant digit (shifted a bit to the right)
1250
1251        for (i=left; i<=right; i++) {
1252            int p = rm->screen_to_sequence(i);
1253            int val = likelihood[r][p];
1254            sbuffer[i] = stat2display(val, 1); // calc upper digit
1255        }
1256        device->text(gc, sbuffer, text_x, y2-font_height, 0, AW_SCREEN, right); // draw higher-significant digit
1257    }
1258
1259    delete [] sbuffer;
1260}
1261
1262int ED4_columnStat_terminal::update_likelihood() {
1263    ED4_sequence_terminal *seq_term = corresponding_sequence_terminal();
1264
1265    return STAT_update_ml_likelihood(ED4_ROOT->st_ml, likelihood, latest_update, 0, seq_term->st_ml_node);
1266}
1267
1268ED4_columnStat_terminal::ED4_columnStat_terminal(GB_CSTR temp_id, AW_pos width, AW_pos height, ED4_manager *temp_parent) :
1269    ED4_text_terminal(column_stat_terminal_spec, temp_id, width, height, temp_parent)
1270{
1271    for (int i=0; i<4; i++) likelihood[i] = 0;
1272    latest_update = 0;
1273}
1274
1275ED4_columnStat_terminal::~ED4_columnStat_terminal()
1276{
1277    for (int i=0; i<4; i++) free(likelihood[i]);
1278}
1279
1280// ------------------------
1281//      flag terminals
1282
1283ED4_flag_header_terminal::ED4_flag_header_terminal(GB_CSTR id_, AW_pos width, AW_pos height, ED4_manager *parent_) :
1284    ED4_text_terminal(flag_header_spec, id_, width, height, parent_)
1285{}
1286
1287GB_CSTR ED4_flag_header_terminal::get_displayed_text() const {
1288    return SpeciesFlags::instance().get_header_text();
1289}
1290int ED4_flag_header_terminal::get_length() const {
1291    return SpeciesFlags::instance().get_header_length();
1292}
1293
1294ED4_flag_terminal::ED4_flag_terminal(const char *id_, AW_pos width, AW_pos height, ED4_manager *parent_) :
1295    ED4_terminal(flag_spec, id_, width, height, parent_)
1296{}
1297
1298using namespace AW;
1299
1300class FlagLayout {
1301    double    flag_centerx; // flag x-position relative to terminal
1302    Rectangle box;          // box at flag_centerx
1303
1304public:
1305    FlagLayout(const Rectangle& area, const SpeciesFlags& flags) {
1306        double boxsize = std::max(1.0, std::min(double(flags.get_min_flag_distance()), area.height()*0.95));
1307        Vector box_diag(boxsize, -boxsize);
1308
1309        SpeciesFlagCiter curr_flag  = flags.begin();
1310        flag_centerx                = curr_flag->center_xpos();
1311        Position         box_center = area.left_edge().centroid() + Vector(flag_centerx, 0);
1312        box                         = Rectangle(box_center-box_diag/2, box_diag);
1313    }
1314
1315    void move_box(double new_flag_centerx) {
1316        box.move(Vector(new_flag_centerx - flag_centerx, 0));
1317        flag_centerx = new_flag_centerx;
1318    }
1319
1320    const Rectangle& get_box() const { return box; }
1321};
1322
1323void ED4_flag_terminal::draw() {
1324    const SpeciesFlags& flags = SpeciesFlags::instance();
1325
1326    int boxes = flags.size();
1327    if (boxes>0) {
1328        FlagLayout layout(get_win_area(current_ed4w()), flags);
1329
1330        SpeciesFlagCiter curr_flag = flags.begin();
1331        SpeciesFlagCiter end       = flags.end();
1332
1333        AW_device *device = current_device();
1334
1335        GBDATA   *gb_species = get_species();
1336        GB_ERROR  error      = NULL;
1337
1338        for (int b = 0; b<boxes && !error; ++b) {
1339            bool filled = false;
1340            {
1341                GBDATA *gb_field = GB_entry(gb_species, curr_flag->get_fieldname().c_str());
1342                if (gb_field) {
1343                    uint8_t as_byte  = GB_read_lossless_byte(gb_field, error);
1344                    if (error) error = GBS_global_string("Failed to read flag value (Reason: %s)", error);
1345                    else    filled   = as_byte;
1346                }
1347            }
1348
1349            if (filled) device->box(ED4_G_FLAG_FILL,  FillStyle::SOLID, layout.get_box(), AW_SCREEN); // filled?
1350            device->box(            ED4_G_FLAG_FRAME, FillStyle::EMPTY, layout.get_box(), AW_SCREEN); // frame
1351
1352            ++curr_flag;
1353            if (curr_flag != end) layout.move_box(curr_flag->center_xpos());
1354        }
1355
1356        aw_message_if(error);
1357    }
1358}
1359
1360void ED4_flag_terminal::handle_left_click(const Position& click) {
1361    const SpeciesFlags& flags = SpeciesFlags::instance();
1362
1363    int boxes = flags.size();
1364    if (boxes>0) {
1365        FlagLayout layout(get_win_area(current_ed4w()), flags);
1366
1367        SpeciesFlagCiter curr_flag = flags.begin();
1368        SpeciesFlagCiter end       = flags.end();
1369
1370        for (int b = 0; b<boxes; ++b) {
1371            if (layout.get_box().contains(click)) break;
1372            ++curr_flag;
1373            if (curr_flag != end) layout.move_box(curr_flag->center_xpos());
1374        }
1375
1376        if (curr_flag != end) {
1377            GBDATA   *gb_species = get_species();
1378            GBDATA   *gb_field   = GB_entry(gb_species, curr_flag->get_fieldname().c_str());
1379            GB_ERROR  error      = GB_incur_error_if(!gb_field);
1380
1381            if (!error && !gb_field) {
1382                const char *key   = curr_flag->prepare_itemfield(); // impl using prepare_and_get_selected_itemfield
1383                if (key) gb_field = GBT_searchOrCreate_itemfield_according_to_changekey(gb_species, key, SPECIES_get_selector().change_key_path);
1384                error             = GB_incur_error_if(!gb_field);
1385            }
1386
1387            if (gb_field) {
1388                uint8_t val       = GB_read_lossless_byte(gb_field, error);
1389                if (!error) error = GB_write_lossless_byte(gb_field, !val);
1390            }
1391
1392            aw_message_if(error);
1393            if (!error) request_refresh();
1394        }
1395    }
1396}
1397
1398// ---------------------------------
1399//      ED4_reference_terminals
1400
1401void ED4_reference_terminals::clear()
1402{
1403    delete ref_sequence_info;
1404    delete ref_sequence;
1405    delete ref_column_stat;
1406    delete ref_column_stat_info;
1407    null();
1408}
1409
1410void ED4_reference_terminals::init(ED4_sequence_info_terminal *ref_sequence_info_,
1411                                   ED4_sequence_terminal *ref_sequence_,
1412                                   ED4_sequence_info_terminal *ref_column_stat_info_,
1413                                   ED4_columnStat_terminal *ref_column_stat_)
1414{
1415    clear();
1416    ref_sequence_info    = ref_sequence_info_;
1417    ref_sequence     = ref_sequence_;
1418    ref_column_stat_info = ref_column_stat_info_;
1419    ref_column_stat      = ref_column_stat_;
1420}
Note: See TracBrowser for help on using the repository browser.