source: tags/ms_r18q1/EDIT4/ED4_terminal.cxx

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