source: tags/arb_5.3/EDIT4/ED4_cursor.cxx

Last change on this file was 6358, checked in by westram, 14 years ago
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 55.3 KB
Line 
1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4#include <ctype.h>
5#include <limits.h>
6
7#include <aw_keysym.hxx>
8#include <arbdb.h>
9#include <arbdbt.h>
10#include <aw_root.hxx>
11#include <aw_awars.hxx>
12#include <aw_window.hxx>
13#include <AW_helix.hxx>
14
15#include <ed4_extern.hxx>
16
17#include "ed4_class.hxx"
18#include "ed4_edit_string.hxx"
19#include "ed4_tools.hxx"
20#include "ed4_awars.hxx"
21#include "ed4_ProteinViewer.hxx"
22
23/* --------------------------------------------------------------------------------
24   CursorShape
25   -------------------------------------------------------------------------------- */
26
27#define MAXLINES  30
28#define MAXPOINTS (2*MAXLINES)
29
30class ED4_CursorShape {
31    int points;
32    int xpos[MAXPOINTS];
33    int ypos[MAXPOINTS];
34
35    int lines;
36    int start[MAXLINES];
37    int end[MAXLINES];
38
39    int char_width;
40
41    bool reverse;
42
43    int point(int x, int y) {
44        e4_assert(points<MAXPOINTS);
45        if (reverse) {
46            xpos[points] = char_width-x;
47        }
48        else {
49            xpos[points] = x;
50        }
51        ypos[points] = y;
52        return points++;
53    }
54    int line(int p1, int p2) {
55        e4_assert(p1>=0 && p1<points);
56        e4_assert(p2>=0 && p2<points);
57
58        e4_assert(lines<MAXLINES);
59        start[lines] = p1;
60        end[lines] = p2;
61
62        return lines++;
63    }
64    int horizontal_line(int x, int y, int half_width) {
65        return line(point(x-half_width, y), point(x+half_width, y));
66    }
67
68public:
69
70    ED4_CursorShape(ED4_CursorType type, /*int x, int y, */int term_height, int character_width, bool reverse_cursor);
71    ~ED4_CursorShape() {}
72
73    void draw(AW_device *device, int x, int y) const {
74        e4_assert(lines);
75        for (int l=0; l<lines; l++) {
76            int p1 = start[l];
77            int p2 = end[l];
78            device->line(ED4_G_CURSOR, xpos[p1]+x, ypos[p1]+y, xpos[p2]+x, ypos[p2]+y, 1, 0, 0);
79        }
80        device->flush();
81    }
82
83    void get_bounding_box(int x, int y, int &xmin, int &ymin, int &xmax, int &ymax) const {
84        e4_assert(points);
85        xmin = ymin = INT_MAX;
86        xmax = ymax = INT_MIN;
87        for (int p=0; p<points; p++) {
88            if (xpos[p]<xmin)      { xmin = xpos[p]; }
89            else if (xpos[p]>xmax) { xmax = xpos[p]; }
90            if (ypos[p]<ymin)      { ymin = ypos[p]; }
91            else if (ypos[p]>ymax) { ymax = ypos[p]; }
92        }
93
94        xmin += x; xmax +=x;
95        ymin += y; ymax +=y;
96    }
97
98
99};
100
101ED4_CursorShape::ED4_CursorShape(ED4_CursorType typ, /*int x, int y, */int term_height, int character_width, bool reverse_cursor)
102{
103    lines      = 0;
104    points     = 0;
105    reverse    = reverse_cursor;
106    char_width = character_width;
107
108    int x = 0;
109    int y = 0;
110
111    switch (typ) {
112#define UPPER_OFFSET    (-1)
113#define LOWER_OFFSET    (term_height-1)
114#define CWIDTH          (character_width)
115
116        case ED4_RIGHT_ORIENTED_CURSOR_THIN:
117        case ED4_RIGHT_ORIENTED_CURSOR: {
118            // --CWIDTH--
119            //
120            // 0--------1               UPPER_OFFSET (from top)
121            // |3-------4
122            // ||
123            // ||
124            // ||
125            // ||
126            // ||
127            // ||
128            // 25                       LOWER_OFFSET (from top)
129            //
130            //
131            //  x
132
133            if (typ == ED4_RIGHT_ORIENTED_CURSOR) { // non-thin version
134                int p0 = point(x-1, y+UPPER_OFFSET);
135
136                line(p0, point(x+CWIDTH-1, y+UPPER_OFFSET)); // 0->1
137                line(p0, point(x-1, y+LOWER_OFFSET)); // 0->2
138            }
139
140            int p3 = point(x, y+UPPER_OFFSET+1);
141
142            line(p3, point(x+CWIDTH-1, y+UPPER_OFFSET+1)); // 3->4
143            line(p3, point(x, y+LOWER_OFFSET)); // 3->5
144
145            break;
146
147#undef UPPER_OFFSET
148#undef LOWER_OFFSET
149#undef CWIDTH
150
151        }
152        case ED4_TRADITIONAL_CURSOR_CONNECTED:
153        case ED4_TRADITIONAL_CURSOR_BOTTOM:
154        case ED4_TRADITIONAL_CURSOR: {
155            int small_version = (term_height <= 10) ? 1 : 0;
156
157
158#define UPPER_OFFSET    0
159#define LOWER_OFFSET    (term_height-1)
160#define CWIDTH          3
161
162            //  -----2*CWIDTH----
163            //
164            //  0---------------1       UPPER_OFFSET (from top)
165            //     4---------5
166            //        8---9
167            //         C/C
168            //
169            //         D/D
170            //        A---B
171            //     6---------7
172            //  2---------------3       LOWER_OFFSET (from top)
173
174            bool draw_upper = typ != ED4_TRADITIONAL_CURSOR_BOTTOM;
175
176            if (draw_upper) horizontal_line(x, y+UPPER_OFFSET, CWIDTH-small_version); // 0/1
177            horizontal_line(x, y+LOWER_OFFSET, CWIDTH-small_version); // 2/3
178
179            if (draw_upper) horizontal_line(x, y+UPPER_OFFSET+1, (CWIDTH*2)/3-small_version); // 4/5
180            horizontal_line(x, y+LOWER_OFFSET-1, (CWIDTH*2)/3-small_version); // 6/7
181
182            if (!small_version) {
183                if (draw_upper) horizontal_line(x, y+UPPER_OFFSET+2, CWIDTH/3); // 8/9
184                horizontal_line(x, y+LOWER_OFFSET-2, CWIDTH/3); // A/B
185            }
186
187            int pu = point(x, y+UPPER_OFFSET+3-small_version);
188            int pl = point(x, y+LOWER_OFFSET-3+small_version);
189
190            if (draw_upper) line(pu,pu);    // C/C
191            line(pl,pl);    // D/D
192
193            if (typ == ED4_TRADITIONAL_CURSOR_CONNECTED) {
194                int pu2 = point(x, y+UPPER_OFFSET+5-small_version);
195                int pl2 = point(x, y+LOWER_OFFSET-5+small_version);
196                line(pu2, pl2);
197            }
198
199            break;
200
201#undef UPPER_OFFSET
202#undef LOWER_OFFSET
203#undef CWIDTH
204
205        }
206        case ED4_FUCKING_BIG_CURSOR: {
207
208#define OUTER_HEIGHT    (term_height/4)
209#define INNER_HEIGHT    (term_height-1)
210#define CWIDTH          12
211#define STEPS           6
212#define THICKNESS       2
213
214#if (2*STEPS+THICKNESS > MAXLINES)
215#error Bad definitions!
216#endif
217
218            //          2               3               |
219            //            \           /                 | OUTER_HEIGHT
220            //               \     /                    |
221            //                  0               |       |
222            //                  |               | INNER_HEIGHT
223            //                  |               |
224            //                  1               |
225            //                /    \                    --
226            //             /          \                 --
227            //          4               5
228            //
229            //          -----------------
230            //                2*WIDTH
231
232            int s;
233            for (s=0; s<STEPS; s++) {
234                int size = ((STEPS-s)*CWIDTH)/STEPS;
235
236                horizontal_line(x, y-OUTER_HEIGHT+s,                    size);
237                horizontal_line(x, y+INNER_HEIGHT+OUTER_HEIGHT-s,       size);
238            }
239
240            int y_upper = ypos[s-4];
241            int y_lower = ypos[s-2];
242
243            int t;
244            for (t=0; t<THICKNESS; t++) {
245                int xp = x-(THICKNESS/2)+t+1;
246                line(point(xp, y_upper), point(xp, y_lower));
247            }
248
249            break;
250
251#undef OUTER_HEIGHT
252#undef INNER_HEIGHT
253#undef CWIDTH
254#undef STEPS
255#undef THICKNESS
256
257        }
258        default: {
259            e4_assert(0);
260            break;
261        }
262    }
263}
264
265/* --------------------------------------------------------------------------------
266   ED4_cursor
267   -------------------------------------------------------------------------------- */
268
269ED4_returncode ED4_cursor::draw_cursor(AW_pos x, AW_pos y)
270{
271    if (cursor_shape) {
272        delete cursor_shape;
273        cursor_shape = 0;
274    }
275
276    cursor_shape = new ED4_CursorShape(ctype,
277                                       SEQ_TERM_TEXT_YOFFSET+2,
278                                       ED4_ROOT->font_group.get_width(ED4_G_SEQUENCES),
279                                       !awar_edit_direction);
280
281    cursor_shape->draw(ED4_ROOT->get_device(), int(x), int(y));
282
283#if defined(DEBUG) && 0
284    printf("draw_cursor(%i, %i)\n", int(x), int(y));
285#endif // DEBUG
286
287    return ED4_R_OK;
288}
289
290ED4_returncode ED4_cursor::delete_cursor(AW_pos del_mark, ED4_base *target_terminal)
291{
292    AW_pos x, y;
293    ED4_base *temp_parent;
294
295    target_terminal->calc_world_coords( &x, &y );
296    temp_parent = target_terminal->get_parent( ED4_L_SPECIES );
297    if (!temp_parent || temp_parent->flag.hidden || !is_partly_visible()) {
298        return ED4_R_BREAK;
299    }
300    x = del_mark;
301    ED4_ROOT->world_to_win_coords(ED4_ROOT->get_aww(), &x, &y);
302
303    // refresh own terminal + terminal above + terminal below
304
305    target_terminal->set_refresh();
306    target_terminal->parent->refresh_requested_by_child();
307
308    {
309        ED4_terminal *term = target_terminal->to_terminal();
310        int backward = 1;
311
312        while (1) {
313            int done = 0;
314
315            term = backward ? term->get_prev_terminal() : term->get_next_terminal();
316            if (!term) {
317                done = 1;
318            }
319            else if ((term->is_sequence_terminal()) && !term->is_in_folded_group()) {
320                term->set_refresh();
321                term->parent->refresh_requested_by_child();
322                done = 1;
323            }
324
325            if (done) {
326                if (!backward) {
327                    break;
328                }
329                backward = 0;
330                term = target_terminal->to_terminal();
331            }
332        }
333
334        term = target_terminal->to_terminal();
335        while(1) {
336            term = term->get_next_terminal();
337            if (!term) {
338                break;
339            }
340
341        }
342    }
343
344    // clear rectangle where cursor is displayed
345
346    AW_device *dev = ED4_ROOT->get_device();
347    dev->push_clip_scale();
348
349    int xmin, xmax, ymin, ymax;
350
351    e4_assert(cursor_shape);
352    cursor_shape->get_bounding_box(int(x), int(y), xmin, ymin, xmax, ymax);
353
354    dev->clear_part(xmin, ymin, xmax-xmin+1, ymax-ymin+1, (AW_bitset)-1);
355
356#if defined(DEBUG) && 0
357    printf("delete_cursor(%i, %i)\n", int(x), int(y));
358#endif // DEBUG
359
360    dev->set_top_font_overlap(1);
361    dev->set_bottom_font_overlap(1);
362    dev->set_left_font_overlap(1);
363    dev->set_right_font_overlap(1);
364
365#define EXPAND_SIZE 0
366    if (ED4_ROOT->get_device()->reduceClipBorders(ymin-EXPAND_SIZE, ymax+1+EXPAND_SIZE, xmin-EXPAND_SIZE, xmax+1+EXPAND_SIZE)) {
367        // refresh terminal
368        int old_allowed_to_draw = allowed_to_draw;
369        allowed_to_draw = 0;
370        ED4_ROOT->refresh_window(1);
371        allowed_to_draw = old_allowed_to_draw;
372    }
373    dev->pop_clip_scale();
374
375    return ( ED4_R_OK );
376}
377
378
379ED4_cursor::ED4_cursor()
380{
381    init();
382    allowed_to_draw = 1;
383    cursor_shape    = 0;
384
385    ctype = (ED4_CursorType)(ED4_ROOT->aw_root->awar(ED4_AWAR_CURSOR_TYPE)->read_int()%ED4_CURSOR_TYPES);
386}
387void ED4_cursor::init() // used by ED4_terminal-d-tor
388{
389    owner_of_cursor   = NULL;
390    cursor_abs_x      = 0;
391    screen_position   = 0;
392}
393ED4_cursor::~ED4_cursor()
394{
395    delete cursor_shape;
396}
397
398ED4_window *ED4_cursor::window() const
399{
400    ED4_window *win;
401
402    for (win=ED4_ROOT->first_window; win; win=win->next) {
403        if (&win->cursor==this) {
404            break;
405        }
406    }
407    e4_assert(win);
408    return win;
409}
410
411int ED4_cursor::get_sequence_pos() const
412{
413    ED4_remap *remap = ED4_ROOT->root_group_man->remap();
414    size_t max_scrpos = remap->get_max_screen_pos();
415
416    return remap->screen_to_sequence(size_t(screen_position)<=max_scrpos ? screen_position : max_scrpos);
417}
418
419bool ED4_species_manager::setCursorTo(ED4_cursor *cursor, int seq_pos, bool unfold_groups, ED4_CursorJumpType jump_type)
420{
421    ED4_group_manager *group_manager_to_unfold = is_in_folded_group();
422
423    if (unfold_groups) {
424        bool unfolded = false;
425
426        while (group_manager_to_unfold && unfold_groups) {
427            ED4_base *base = group_manager_to_unfold->search_spec_child_rek(ED4_L_BRACKET);
428            if (!base) break;
429            ED4_bracket_terminal *bracket = base->to_bracket_terminal();
430            group_manager_to_unfold->unfold_group(bracket->id);
431            unfolded = true;
432            group_manager_to_unfold = is_in_folded_group();
433        }
434
435        if (unfolded) ED4_ROOT->refresh_all_windows(1);
436    }
437
438    if (!group_manager_to_unfold) { // species manager is visible (now)
439        ED4_terminal *terminal = search_spec_child_rek(ED4_L_SEQUENCE_STRING)->to_terminal();
440        if (terminal) {
441            if (seq_pos == -1) seq_pos = cursor->get_sequence_pos();
442            cursor->set_to_terminal(ED4_ROOT->get_aww(), terminal, seq_pos, jump_type);
443            return true;
444        }
445    }
446
447    return false;
448}
449
450static void jump_to_species(ED4_species_name_terminal *name_term, int seq_pos, bool unfold_groups, ED4_CursorJumpType jump_type)
451{
452    ED4_species_manager *species_manager = name_term->get_parent(ED4_L_SPECIES)->to_species_manager();
453    ED4_cursor *cursor = &ED4_ROOT->get_ed4w()->cursor;
454    bool jumped = false;
455
456    if (species_manager) jumped = species_manager->setCursorTo(cursor, seq_pos, unfold_groups, jump_type);
457    if (!jumped) cursor->HideCursor();
458}
459
460static bool ignore_selected_species_changes_cb = false;
461static bool ignore_selected_SAI_changes_cb     = false;
462
463static void select_named_sequence_terminal(const char *name) {
464    GB_transaction ta(GLOBAL_gb_main);
465    ED4_species_name_terminal *name_term = ED4_find_species_name_terminal(name);
466    if (name_term) {
467        // lookup current name term
468        ED4_species_name_terminal *cursor_name_term = 0;
469        {
470            ED4_cursor *cursor = &ED4_ROOT->get_ed4w()->cursor;
471            if (cursor) {
472                ED4_sequence_terminal *cursor_seq_term = 0;
473
474                ED4_terminal *cursor_term = cursor->owner_of_cursor->to_text_terminal();;
475                if (cursor_term->is_sequence_terminal()) {
476                    cursor_seq_term = cursor_term->to_sequence_terminal();
477                }
478                else {          // user clicked into a non-sequence text terminal
479                    // search for corresponding sequence terminal
480                    ED4_multi_sequence_manager *seq_man = cursor_term->get_parent(ED4_L_MULTI_SEQUENCE)->to_multi_sequence_manager();
481                    if (seq_man) {
482                        cursor_seq_term = seq_man->search_spec_child_rek(ED4_L_SEQUENCE_STRING)->to_sequence_terminal();
483                    }
484                }
485
486                if (cursor_seq_term) {
487                    cursor_name_term = cursor_seq_term->corresponding_species_name_terminal();
488                }
489            }
490        }
491        if (name_term!=cursor_name_term) { // do not change if already there!
492#if defined(DEBUG) && 1
493            printf("Jumping to species/SAI '%s'\n", name);
494#endif
495            jump_to_species(name_term, -1, false, ED4_JUMP_KEEP_POSITION);
496        }
497        else {
498#if defined(DEBUG) && 1
499            printf("Change ignored because same name term!\n");
500#endif
501        }
502    }
503}
504
505void ED4_selected_SAI_changed_cb(AW_root */*aw_root*/)
506{
507    ED4_update_global_cursor_awars_allowed = false;
508
509    if (!ignore_selected_SAI_changes_cb) {
510        char *name = GBT_read_string(GLOBAL_gb_main,AWAR_SAI_NAME);
511
512        if (name && name[0]) {
513#if defined(DEBUG)
514            printf("Selected SAI is '%s'\n", name);
515#endif // DEBUG
516
517            select_named_sequence_terminal(name);
518            free(name);
519        }
520    }
521    ignore_selected_SAI_changes_cb = false;
522    ED4_update_global_cursor_awars_allowed = true;
523}
524
525void ED4_selected_species_changed_cb(AW_root */*aw_root*/)
526{
527    ED4_update_global_cursor_awars_allowed = false;
528
529    if (!ignore_selected_species_changes_cb) {
530        char *name = GBT_read_string(GLOBAL_gb_main,AWAR_SPECIES_NAME);
531        if (name && name[0]) {
532#if defined(DEBUG) && 1
533            printf("Selected species is '%s'\n", name);
534#endif
535            select_named_sequence_terminal(name);
536            free(name);
537        }
538    }
539    else {
540#if defined(DEBUG) && 1
541        printf("Change ignored because ignore_selected_species_changes_cb!\n");
542#endif
543    }
544    ignore_selected_species_changes_cb = false;
545    ED4_update_global_cursor_awars_allowed = true;
546}
547
548void ED4_jump_to_current_species(AW_window */*aw*/, AW_CL)
549{
550    char *name = GBT_read_string(GLOBAL_gb_main, AWAR_SPECIES_NAME);
551    if (name && name[0]) {
552        GB_transaction dummy(GLOBAL_gb_main);
553#if defined(DEBUG) && 1
554        printf("Jump to selected species (%s)\n", name);
555#endif
556        ED4_species_name_terminal *name_term = ED4_find_species_name_terminal(name);
557
558        if (name_term) {
559            jump_to_species(name_term, -1, true, ED4_JUMP_KEEP_POSITION);
560        }
561        else {
562            aw_message(GBS_global_string("Species '%s' is not loaded - use GET to load it.", name));
563        }
564    }
565    else {
566        aw_message("Please select a species");
567    }
568}
569
570static int multi_species_man_consensus_id_starts_with(ED4_base *base, AW_CL cl_start) { // TRUE if consensus id starts with 'start'
571    ED4_multi_species_manager *ms_man = base->to_multi_species_manager();
572    char *start = (char*)cl_start;
573    ED4_base *consensus = ms_man->search_spec_child_rek(ED4_L_SPECIES);
574
575    if (consensus) {
576        ED4_base *consensus_name = consensus->search_spec_child_rek(ED4_L_SPECIES_NAME);
577
578        if (consensus_name) {
579            if (strncmp(consensus_name->id, start, strlen(start))==0) {
580                ED4_multi_species_manager *cons_ms_man = consensus_name->get_parent(ED4_L_MULTI_SPECIES)->to_multi_species_manager();
581                return cons_ms_man==ms_man;
582            }
583        }
584    }
585
586    return 0;
587}
588
589ED4_multi_species_manager *ED4_new_species_multi_species_manager(void) { // returns manager into which new species should be inserted
590    ED4_base *manager = ED4_ROOT->root_group_man->find_first_that(ED4_L_MULTI_SPECIES, multi_species_man_consensus_id_starts_with, (AW_CL)"More Sequences");
591    return manager ? manager->to_multi_species_manager() : 0;
592}
593
594void ED4_init_notFoundMessage() {
595    not_found_counter = 0;
596    not_found_message = GBS_stropen(10000);
597    // GBS_strcat(not_found_message,"Species not found: ");
598}
599void ED4_finish_and_show_notFoundMessage() {
600    if (not_found_counter != 0) {
601        GBS_strcat(not_found_message, GBS_global_string("(skipped display of %zu more species)\n", not_found_counter-MAX_SHOWN_MISSING_SPECIES));
602        char *out_message = GBS_strclose(not_found_message);
603        aw_message(out_message);
604        aw_message(GBS_global_string("Couldn't load %zu species:", not_found_counter));
605        free(out_message);
606    }
607    else {
608        GBS_strforget(not_found_message);
609    }
610    not_found_message = 0;
611}
612
613void ED4_get_and_jump_to_species(GB_CSTR species_name)
614{
615    e4_assert(species_name && species_name[0]);
616
617    GB_transaction dummy(GLOBAL_gb_main);
618    ED4_species_name_terminal *name_term = ED4_find_species_name_terminal(species_name);
619    int loaded = 0;
620
621    if (!name_term) { // insert new species
622        ED4_multi_species_manager *insert_into_manager = ED4_new_species_multi_species_manager();
623        ED4_group_manager         *group_man           = insert_into_manager->get_parent(ED4_L_GROUP)->to_group_manager();
624        char                      *string              = (char*)GB_calloc(strlen(species_name)+3, sizeof(*string));
625        int                        index               = 0;
626        ED4_index                  y                   = 0;
627        ED4_index                  lot                 = 0;
628
629        ED4_init_notFoundMessage();
630
631        sprintf(string, "-L%s", species_name);
632        ED4_ROOT->database->fill_species(insert_into_manager,
633                                         ED4_ROOT->ref_terminals.get_ref_sequence_info(), ED4_ROOT->ref_terminals.get_ref_sequence(),
634                                         string, &index, &y, 0, &lot, insert_into_manager->calc_group_depth());
635        loaded = 1;
636
637        ED4_finish_and_show_notFoundMessage();
638
639        {
640            GBDATA *gb_species = GBT_find_species(GLOBAL_gb_main, species_name);
641            GBDATA *gbd = GBT_read_sequence(gb_species, ED4_ROOT->alignment_name);
642
643            if (gbd) {
644                char *data = GB_read_string(gbd);
645                int len = GB_read_string_count(gbd);
646                group_man->table().add(data, len);
647            }
648        }
649
650        name_term = ED4_find_species_name_terminal(species_name);
651        if (name_term) {
652            /* new AAseqTerminals should be created if it is in ProtView mode */
653            if(ED4_ROOT->alignment_type == GB_AT_DNA) {
654                PV_AddCorrespondingAAseqTerminals(name_term);
655            }
656            ED4_ROOT->main_manager->update_info.set_resize(1);
657            ED4_ROOT->main_manager->resize_requested_by_parent();
658            /* it should create new AA Sequence terminals if the protien viewer is enabled */
659        }
660        delete string;
661    }
662    if (name_term) {
663        jump_to_species(name_term, -1, true, ED4_JUMP_KEEP_POSITION);
664        if (!loaded) {
665            aw_message(GBS_global_string("'%s' is already loaded.", species_name));
666        }
667    }
668    else {
669        aw_message(GBS_global_string("Cannot get species '%s'", species_name));
670    }
671}
672
673void ED4_get_and_jump_to_actual(AW_window *, AW_CL)
674{
675    char *name = GBT_read_string(GLOBAL_gb_main, AWAR_SPECIES_NAME);
676    if (name && name[0]) {
677        ED4_get_and_jump_to_species(name);
678        ED4_ROOT->refresh_all_windows(0);
679    }
680    else {
681        aw_message("Please select a species");
682    }
683}
684
685void ED4_get_and_jump_to_actual_from_menu(AW_window *aw, AW_CL cl, AW_CL) {
686    ED4_get_and_jump_to_actual(aw, cl);
687    ED4_ROOT->refresh_all_windows(0);
688}
689
690void ED4_get_marked_from_menu(AW_window *, AW_CL, AW_CL) {
691#define BUFFERSIZE 1000
692    GB_transaction dummy(GLOBAL_gb_main);
693    int marked = GBT_count_marked_species(GLOBAL_gb_main);
694
695    if (marked) {
696        GBDATA *gb_species = GBT_first_marked_species(GLOBAL_gb_main);
697        int count = 0;
698        char *buffer = new char[BUFFERSIZE+1];
699        char *bp = buffer;
700        //      int inbuf = 0; // # of names in buffer
701        ED4_multi_species_manager *insert_into_manager = ED4_new_species_multi_species_manager();
702        ED4_group_manager *group_man = insert_into_manager->get_parent(ED4_L_GROUP)->to_group_manager();
703        int group_depth = insert_into_manager->calc_group_depth();
704        int index = 0;
705        ED4_index y = 0;
706        ED4_index lot = 0;
707        int inserted = 0;
708        char *default_alignment = GBT_get_default_alignment(GLOBAL_gb_main);
709
710        aw_openstatus("ARB_EDIT4");
711        aw_status("Loading species...");
712
713        ED4_init_notFoundMessage();
714
715        while (gb_species) {
716            count++;
717            GB_status(double(count)/double(marked));
718
719            const char *name = GBT_read_name(gb_species);
720            ED4_species_name_terminal *name_term = ED4_find_species_name_terminal(name);
721
722            if (!name_term) { // species not found -> insert
723                {
724                    int namelen = strlen(name);
725                    int buffree = BUFFERSIZE-int(bp-buffer);
726
727                    if ((namelen+2)>buffree) {
728                        *bp++ = 0;
729                        ED4_ROOT->database->fill_species(insert_into_manager,
730                                                         ED4_ROOT->ref_terminals.get_ref_sequence_info(), ED4_ROOT->ref_terminals.get_ref_sequence(),
731                                                         buffer, &index, &y, 0, &lot, group_depth);
732                        bp = buffer;
733                        index = 0;
734                    }
735
736                    *bp++ = 1;
737                    *bp++ = 'L';
738                    memcpy(bp, name, namelen);
739                    bp += namelen;
740                }
741
742                {
743                    GBDATA *gbd = GBT_read_sequence(gb_species, default_alignment);
744
745                    if (gbd) {
746                        char *data = GB_read_string(gbd);
747                        int len = GB_read_string_count(gbd);
748                        group_man->table().add(data, len);
749                    }
750                }
751
752                inserted++;
753            }
754            gb_species = GBT_next_marked_species(gb_species);
755        }
756
757        if (bp>buffer) {
758            *bp++ = 0;
759            ED4_ROOT->database->fill_species(insert_into_manager,
760                                             ED4_ROOT->ref_terminals.get_ref_sequence_info(), ED4_ROOT->ref_terminals.get_ref_sequence(),
761                                             buffer, &index, &y, 0, &lot, group_depth);
762        }
763
764        aw_closestatus();
765        aw_message(GBS_global_string("Loaded %i of %i marked species.", inserted, marked));
766
767        ED4_finish_and_show_notFoundMessage();
768       
769        if (inserted) {
770            /* new AAseqTerminals should be created if it is in ProtView mode */
771            if (ED4_ROOT->alignment_type == GB_AT_DNA) {
772                PV_AddAAseqTerminalsToLoadedSpecies();
773            }
774
775            ED4_ROOT->main_manager->update_info.set_resize(1);
776            ED4_ROOT->main_manager->resize_requested_by_parent();
777        }
778
779        delete buffer;
780        delete default_alignment;
781    }
782    else {
783        aw_message("No species marked.");
784    }
785
786#undef BUFFERSIZE
787
788    ED4_ROOT->refresh_all_windows(0);
789}
790
791ED4_returncode ED4_cursor::HideCursor()
792{
793    if (owner_of_cursor) {
794        if (is_partly_visible()) {
795            delete_cursor(cursor_abs_x, owner_of_cursor);
796        }
797        owner_of_cursor = 0;
798    }
799
800    return ED4_R_OK;
801}
802
803void ED4_cursor::changeType(ED4_CursorType typ)
804{
805    if (owner_of_cursor) {
806        ED4_base *old_owner_of_cursor = owner_of_cursor;
807
808        HideCursor();
809        ctype = typ;
810        ED4_ROOT->aw_root->awar(ED4_AWAR_CURSOR_TYPE)->write_int(int(ctype));
811        owner_of_cursor = old_owner_of_cursor;
812        ShowCursor(0, ED4_C_NONE, 0);
813    }
814    else {
815        ctype = typ;
816    }
817}
818
819int ED4_update_global_cursor_awars_allowed = true;
820
821void ED4_cursor::updateAwars()
822{
823    AW_root     *aw_root = ED4_ROOT->aw_root;
824    ED4_window  *win = ED4_ROOT->get_ed4w();
825    int         seq_pos = get_sequence_pos();
826
827    if (ED4_update_global_cursor_awars_allowed) {
828        if (owner_of_cursor) {
829            ED4_terminal *cursor_terminal = owner_of_cursor->to_terminal();
830            char         *species_name    = cursor_terminal->get_name_of_species();
831
832            if (species_name) {
833                ED4_manager *cursor_manager = cursor_terminal->parent->parent->to_manager();
834
835                if (cursor_manager->parent->flag.is_SAI) {
836                    static char *last_set_SAI = 0;
837                    if (!last_set_SAI || strcmp(last_set_SAI, species_name) != 0) {
838                        freedup(last_set_SAI, species_name);
839
840                        ignore_selected_SAI_changes_cb = true;
841                        GBT_write_string(GLOBAL_gb_main, AWAR_SAI_NAME, species_name);
842                        ignore_selected_SAI_changes_cb = false;
843                    }
844                }
845                else {
846                    static char *last_set_species = 0;
847                    if (!last_set_species || strcmp(last_set_species, species_name) != 0) {
848                        freedup(last_set_species, species_name);
849
850                        ignore_selected_species_changes_cb = true;
851                        GBT_write_string(GLOBAL_gb_main, AWAR_SPECIES_NAME, species_name);
852                        ignore_selected_species_changes_cb = false;
853                    }
854                }
855            }
856            free(species_name);
857        }
858    }
859
860    // update awars for cursor position:
861
862    aw_root->awar(win->awar_path_for_cursor)->write_int(seq_pos+1);
863    if (ED4_update_global_cursor_awars_allowed) {
864        aw_root->awar(AWAR_CURSOR_POSITION)->write_int(seq_pos+1);      // this supports last cursor position for all applications
865    }
866
867    // look if we have a commented search result under the cursor:
868
869    if (owner_of_cursor && owner_of_cursor->is_sequence_terminal()) {
870        ED4_sequence_terminal *seq_term = owner_of_cursor->to_sequence_terminal();
871        ED4_SearchResults &results = seq_term->results();
872        ED4_SearchPosition *pos = results.get_shown_at(seq_pos);
873
874        if (pos) {
875            GB_CSTR comment = pos->get_comment();
876
877            if (comment) {
878                char *buffer = GB_give_buffer(strlen(comment)+30);
879
880                sprintf(buffer, "%s: %s", ED4_SearchPositionTypeId[pos->get_whatsFound()], comment);
881                aw_message(buffer);
882            }
883        }
884    }
885
886    // update awar for ecoli position:
887
888    BI_ecoli_ref *ecoli = ED4_ROOT->ecoli_ref;
889    if (ecoli->gotData()) {
890        long ecoli_pos = ecoli->abs_2_rel(seq_pos);
891        aw_root->awar(win->awar_path_for_Ecoli)->write_int(ecoli_pos+1);
892    }
893
894    // update awar for base position:
895
896    int base_pos = base_position.get_base_position(owner_of_cursor, seq_pos+1);
897    aw_root->awar(win->awar_path_for_basePos)->write_int(base_pos); // update awar for base position
898
899    // update awar for IUPAC:
900
901#define MAXIUPAC 6
902
903    char iupac[MAXIUPAC+1];
904    strcpy(iupac, ED4_IUPAC_EMPTY);
905
906    if (owner_of_cursor) {
907        ED4_species_manager *species_manager = owner_of_cursor->get_parent(ED4_L_SPECIES)->to_species_manager();
908        int                  len;
909        char                *seq;
910
911        if (species_manager->flag.is_consensus) {
912            ED4_group_manager *group_manager = owner_of_cursor->get_parent(ED4_L_GROUP)->to_group_manager();
913
914            seq = group_manager->table().build_consensus_string(seq_pos, seq_pos, 0);
915            len = seq_pos+1; // fake
916        }
917        else {
918            seq = owner_of_cursor->resolve_pointer_to_string_copy(&len);
919        }
920
921        e4_assert(seq);
922
923        if (seq_pos<len) {
924            char base = seq[seq_pos];
925            const char *i = ED4_decode_iupac(base, ED4_ROOT->alignment_type);
926
927            e4_assert(strlen(i)<=MAXIUPAC);
928            strcpy(iupac, i);
929        }
930
931        free(seq);
932    }
933
934#undef MAXIUPAC
935
936    aw_root->awar(win->awar_path_for_IUPAC)->write_string(iupac);
937
938    // update awar for helix#:
939    const char *helixNr = ED4_ROOT->helix->helixNr(seq_pos);
940    aw_root->awar(win->awar_path_for_helixNr)->write_string(helixNr ? helixNr : "");
941}
942
943int ED4_cursor::get_screen_relative_pos() {
944    ED4_coords *coords = &ED4_ROOT->get_ed4w()->coords;
945    return cursor_abs_x - coords->window_left_clip_point;
946}
947void ED4_cursor::set_screen_relative_pos(AW_window *aww, int scroll_to_relpos) {
948    int curr_rel_pos  = get_screen_relative_pos();
949    int scroll_amount = curr_rel_pos-scroll_to_relpos;
950
951    int length_of_char = ED4_ROOT->font_group.get_width(ED4_G_SEQUENCES);
952    scroll_amount      = (scroll_amount/length_of_char)*length_of_char; // align to char-size
953
954    if (scroll_amount != 0) {
955        aww->set_horizontal_scrollbar_position(aww->slider_pos_horizontal + scroll_amount);
956#if defined(DEBUG)
957        printf("set_screen_relative_pos(%i) auto-scrolls %i\n", scroll_to_relpos, scroll_amount);
958#endif // DEBUG
959        ED4_horizontal_change_cb(aww, 0, 0);
960    }
961}
962
963
964void ED4_cursor::jump_screen_pos(AW_window *aww, int screen_pos, ED4_CursorJumpType jump_type) {
965    if (!owner_of_cursor) {
966        aw_message("First you have to place the cursor");
967        return;
968    }
969
970    ED4_base *temp_parent = owner_of_cursor;
971    while (temp_parent->parent) {
972        temp_parent = temp_parent->parent;
973        if (temp_parent->flag.hidden) return; // don't move cursor if terminal is flag.hidden
974    }
975
976    AW_pos terminal_x, terminal_y;
977    owner_of_cursor->calc_world_coords(&terminal_x, &terminal_y);
978
979#if defined(DEBUG) && 0
980    printf("jump_screen_pos(%i)\n", screen_pos);
981#endif // DEBUG
982
983    ED4_terminal *term = owner_of_cursor->to_terminal();
984    term->scroll_into_view(aww); // correct y-position of terminal
985
986    int cursor_diff = screen_pos-screen_position;
987    if (cursor_diff == 0) { // cursor position did not change
988        if (jump_type == ED4_JUMP_KEEP_VISIBLE) return; // nothing special -> done
989    }
990
991    int terminal_pixel_length = aww->get_device(AW_MIDDLE_AREA)->get_string_size(ED4_G_SEQUENCES, 0, owner_of_cursor->to_text_terminal()->get_length());
992    int length_of_char        = ED4_ROOT->font_group.get_width(ED4_G_SEQUENCES);
993    int abs_x_new             = cursor_abs_x+cursor_diff*length_of_char; // position in terminal
994
995    if (abs_x_new > terminal_x+terminal_pixel_length+CHARACTEROFFSET || abs_x_new < terminal_x+CHARACTEROFFSET) {
996        return; // don`t move out of terminal
997    }
998
999    ED4_coords *coords = &ED4_ROOT->get_ed4w()->coords;
1000
1001    int screen_width  = coords->window_right_clip_point-coords->window_left_clip_point;
1002    int scroll_new_to = -1;     // if >0 -> scroll abs_x_new to this screen-relative position
1003
1004    if (jump_type != ED4_JUMP_KEEP_VISIBLE) {
1005        int rel_x = cursor_abs_x-coords->window_left_clip_point;
1006
1007        if (jump_type == ED4_JUMP_KEEP_POSITION) {
1008            bool was_in_screen = rel_x >= 0 && rel_x <= screen_width;
1009            if (!was_in_screen) {
1010                jump_type = ED4_JUMP_KEEP_VISIBLE; // // don't have useful relative position -> scroll
1011            }
1012        }
1013
1014        switch (jump_type) {
1015            case ED4_JUMP_CENTERED:             scroll_new_to = screen_width/2;         break;
1016            case ED4_JUMP_KEEP_POSITION:        scroll_new_to = rel_x;                  break;
1017            case ED4_JUMP_KEEP_VISIBLE:         break; // handled below
1018            default: e4_assert(0); break;
1019        }
1020    }
1021
1022    if (jump_type == ED4_JUMP_KEEP_VISIBLE) {
1023        int margin = length_of_char * ED4_ROOT->aw_root->awar(ED4_AWAR_SCROLL_MARGIN)->read_int();
1024
1025        int right_margin = coords->window_right_clip_point - margin;
1026        int left_margin  = coords->window_left_clip_point + margin;
1027
1028        if (left_margin >= right_margin)    scroll_new_to = screen_width/2; // margins too big -> center
1029        else if (abs_x_new > right_margin)  scroll_new_to = screen_width-margin;
1030        else if (abs_x_new < left_margin)   scroll_new_to = margin;
1031    }
1032
1033    delete_cursor(cursor_abs_x, owner_of_cursor);
1034
1035    int old_allowed_to_draw = allowed_to_draw;
1036    if (scroll_new_to >= 0) {   // scroll
1037        int rel_x_new     = abs_x_new-coords->window_left_clip_point;
1038        int scroll_amount = rel_x_new-scroll_new_to;
1039
1040        if      (scroll_amount>0) scroll_amount += length_of_char/2;
1041        else if (scroll_amount<0) scroll_amount -= length_of_char/2;
1042
1043        scroll_amount = (scroll_amount/length_of_char)*length_of_char; // align to char-size
1044        if (scroll_amount != 0) {
1045            aww->set_horizontal_scrollbar_position(aww->slider_pos_horizontal + scroll_amount);
1046#if defined(DEBUG) && 0
1047            printf("jump_screen_pos auto-scrolls %i\n", scroll_amount);
1048#endif // DEBUG
1049            allowed_to_draw = 0;
1050            ED4_horizontal_change_cb(aww, 0, 0);
1051        }
1052    }
1053
1054    allowed_to_draw = 1;
1055    if (cursor_diff >= 0) {
1056        ShowCursor(cursor_diff*length_of_char, ED4_C_RIGHT, ABS(cursor_diff));
1057    }
1058    else {
1059        ShowCursor(cursor_diff*length_of_char, ED4_C_LEFT, ABS(cursor_diff));
1060    }
1061    allowed_to_draw = old_allowed_to_draw;
1062}
1063
1064void ED4_cursor::jump_sequence_pos(AW_window *aww, int seq_pos, ED4_CursorJumpType jump_type) {
1065    int screen_pos = ED4_ROOT->root_group_man->remap()->sequence_to_screen_clipped(seq_pos);
1066    jump_screen_pos(aww, screen_pos, jump_type);
1067}
1068
1069void ED4_cursor::jump_base_pos(AW_window *aww, int base_pos, ED4_CursorJumpType jump_type) {
1070    int seq_pos = base2sequence_position(base_pos);
1071    jump_sequence_pos(aww, seq_pos, jump_type);
1072}
1073
1074static bool has_gap_or_base_at(ED4_base *terminal, bool test_for_base, int seq_pos) {
1075    bool test_succeeded = false;
1076
1077    if (terminal->is_sequence_terminal()) {
1078        ED4_sequence_terminal *seqTerm = terminal->to_sequence_terminal();
1079        int len;
1080        char *seq = seqTerm->resolve_pointer_to_string_copy(&len);
1081        if (seq) {
1082            test_succeeded = len>seq_pos && bool(ADPP_IS_ALIGN_CHARACTER(seq[seq_pos]))!=test_for_base;
1083        }
1084        free(seq);
1085    }
1086
1087#if defined(DEBUG) && 0
1088    printf("test_for_base=%i test_succeeded=%i\n", int(test_for_base), int(test_succeeded));
1089#endif // DEBUG
1090    return test_succeeded;
1091}
1092
1093static bool has_base_at(ED4_base *terminal, int seq_pos) { return has_gap_or_base_at(terminal, true,  seq_pos); }
1094static bool has_gap_at(ED4_base *terminal, int seq_pos) { return has_gap_or_base_at(terminal, false, seq_pos); }
1095
1096
1097ED4_returncode ED4_cursor::move_cursor(AW_event *event) {
1098    // move cursor up down
1099    ED4_cursor_move dir     = ED4_C_NONE;
1100    ED4_returncode result   = ED4_R_OK;
1101    bool            endHome = false;
1102
1103    switch (event->keycode) {
1104        case AW_KEY_UP:   dir = ED4_C_UP;   break;
1105        case AW_KEY_DOWN: dir = ED4_C_DOWN; break;
1106        case AW_KEY_HOME: dir = ED4_C_UP;   endHome = true; break;
1107        case AW_KEY_END:  dir = ED4_C_DOWN; endHome = true; break;
1108        default: e4_assert(0); break; // illegal call of move_cursor()
1109    }
1110
1111    if (dir != ED4_C_NONE) {
1112        // don't move cursor if terminal is hidden
1113        {
1114            ED4_base *temp_parent = owner_of_cursor->parent;
1115            while (temp_parent->parent && result == ED4_R_OK) {
1116                if (temp_parent->flag.hidden) { result = ED4_R_IMPOSSIBLE; }
1117                temp_parent = temp_parent->parent;
1118            }
1119        }
1120
1121        if (result == ED4_R_OK) {
1122            AW_pos     x_dummy, y_world;
1123            AW_window *aww      = ED4_ROOT->get_aww();
1124
1125            owner_of_cursor->calc_world_coords(&x_dummy, &y_world);
1126
1127            int       seq_pos         = get_sequence_pos();
1128            ED4_base *target_terminal = 0;
1129
1130            if (event->keymodifier & AW_KEYMODE_CONTROL) {
1131                bool has_base = has_base_at(owner_of_cursor, seq_pos);
1132
1133                // stay in current area
1134                ED4_manager *start_at_manager = 0;
1135                if (owner_of_cursor->has_parent(ED4_ROOT->top_area_man)) {
1136                    start_at_manager = ED4_ROOT->top_area_man;
1137                }
1138                else {
1139                    start_at_manager = ED4_ROOT->middle_area_man;
1140                }
1141
1142                if (!endHome) { // not End or Home
1143                    target_terminal = get_upper_lower_cursor_pos(start_at_manager, dir, y_world, false, has_base ? has_gap_at : has_base_at, seq_pos);
1144                    if (target_terminal && !has_base && ED4_ROOT->aw_root->awar(ED4_AWAR_FAST_CURSOR_JUMP)->read_int())  { // if jump_over group
1145                        target_terminal->calc_world_coords(&x_dummy, &y_world);
1146                        target_terminal = get_upper_lower_cursor_pos(start_at_manager, dir, y_world, false, has_gap_at, seq_pos);
1147                    }
1148                }
1149
1150                if (target_terminal == 0) {
1151                    // either already in last group (or no space behind last group) -> jump to end (or start)
1152                    target_terminal = get_upper_lower_cursor_pos(start_at_manager,
1153                                                                 dir == ED4_C_UP ? ED4_C_DOWN : ED4_C_UP, // use opposite movement direction
1154                                                                 dir == ED4_C_UP ? 0 : INT_MAX, false, // search for top-/bottom-most terminal
1155                                                                 0, seq_pos);
1156                }
1157            }
1158            else {
1159                e4_assert(!endHome); // END and HOME w/o Ctrl should not call move_cursor()
1160
1161                bool isScreen = false;
1162                if (dir == ED4_C_DOWN) {
1163                    ED4_ROOT->world_to_win_coords(aww, &x_dummy, &y_world); // special handling to move cursor from top to bottom area
1164                    isScreen = true;
1165                }
1166                target_terminal = get_upper_lower_cursor_pos(ED4_ROOT->main_manager, dir, y_world, isScreen, 0, seq_pos);
1167            }
1168
1169            if (target_terminal) {
1170                set_to_terminal(aww, target_terminal->to_terminal(), seq_pos, ED4_JUMP_KEEP_VISIBLE);
1171            }
1172        }
1173    }
1174
1175    return result;
1176}
1177
1178void ED4_cursor::set_abs_x()
1179{
1180    AW_pos x, y;
1181    owner_of_cursor->calc_world_coords( &x, &y );
1182    cursor_abs_x = int(get_sequence_pos()*ED4_ROOT->font_group.get_width(ED4_G_SEQUENCES) + CHARACTEROFFSET + x);
1183}
1184
1185
1186ED4_returncode ED4_cursor::ShowCursor(ED4_index offset_x, ED4_cursor_move move, int move_pos)
1187{
1188    AW_pos x=0, y=0, x_help = 0, y_help;
1189
1190    owner_of_cursor->calc_world_coords( &x, &y );
1191
1192    switch (move)
1193    {
1194        case ED4_C_RIGHT:
1195            screen_position += move_pos;
1196            break;
1197        case ED4_C_LEFT:
1198            screen_position -= move_pos;
1199            break;
1200        case ED4_C_NONE:
1201            break;
1202        default:
1203            e4_assert(0);
1204            break;
1205    }
1206
1207    updateAwars();
1208
1209    x_help = cursor_abs_x + offset_x;
1210    y_help = y;
1211
1212    ED4_ROOT->world_to_win_coords(ED4_ROOT->get_aww(), &x_help, &y_help);
1213
1214    if (allowed_to_draw) draw_cursor(x_help, y_help);
1215#if defined(DEBUG) && 0
1216    else printf("Skip draw_cursor (allowed_to_draw=false)\n");
1217#endif // DEBUG
1218
1219    cursor_abs_x += offset_x;
1220
1221    return ( ED4_R_OK );
1222}
1223
1224
1225bool ED4_cursor::is_partly_visible() const {
1226    e4_assert(owner_of_cursor);
1227    e4_assert(cursor_shape); // cursor is not drawn, cannot test visibility
1228
1229    AW_pos x,y;
1230    owner_of_cursor->calc_world_coords( &x, &y );
1231
1232    int x1, y1, x2, y2;
1233    cursor_shape->get_bounding_box(cursor_abs_x, int(y), x1, y1, x2, y2);
1234
1235    bool visible = false;
1236
1237    switch (owner_of_cursor->get_area_level(0)) {
1238        case ED4_A_TOP_AREA:
1239            visible =
1240                owner_of_cursor->is_visible(x1, 0, ED4_D_HORIZONTAL) ||
1241                owner_of_cursor->is_visible(x2, 0, ED4_D_HORIZONTAL);
1242            break;
1243        case ED4_A_MIDDLE_AREA:
1244            visible = owner_of_cursor->is_visible(x1, y1, x2, y2, ED4_D_ALL_DIRECTION);
1245            break;
1246        default:
1247            break;
1248    }
1249
1250    return visible;
1251}
1252
1253void ED4_terminal::scroll_into_view(AW_window *aww) { // scroll y-position only
1254    AW_pos termw_x, termw_y;
1255    calc_world_coords(&termw_x, &termw_y);
1256
1257    ED4_coords *coords  = &ED4_ROOT->get_ed4w()->coords;
1258
1259    int term_height = int(extension.size[1]);
1260    int win_ysize   = coords->window_lower_clip_point - coords->window_upper_clip_point + 1;
1261
1262    bool scroll = false;
1263    int slider_pos_y;
1264
1265    AW_pos termw_y_upper = termw_y - term_height; // upper border of terminal
1266
1267    if (termw_y_upper > coords->top_area_height) { // dont scroll if terminal is in top area (always visible)
1268        if (termw_y_upper < coords->window_upper_clip_point) {
1269#if defined(DEBUG) && 0
1270            printf("termw_y(%i)-term_height(%i) < window_upper_clip_point(%i)\n",
1271                   int(termw_y), term_height, int(coords->window_upper_clip_point));
1272#endif // DEBUG
1273            slider_pos_y = int(termw_y - coords->top_area_height - term_height);
1274            scroll       = true;
1275        }
1276        else if (termw_y > coords->window_lower_clip_point) {
1277#if defined(DEBUG) && 0
1278            printf("termw_y(%i) > window_lower_clip_point(%i)\n",
1279                   int(termw_y), int(coords->window_lower_clip_point));
1280#endif // DEBUG
1281            slider_pos_y = int(termw_y - coords->top_area_height - win_ysize);
1282            scroll       = true;
1283        }
1284    }
1285
1286#if defined(DEBUG) && 0
1287    if (!scroll) {
1288        printf("No scroll needed (termw_y=%i termw_y_upper=%i term_height=%i window_upper_clip_point=%i window_lower_clip_point=%i)\n",
1289               int(termw_y), int(termw_y_upper), term_height,
1290               int(coords->window_upper_clip_point), int(coords->window_lower_clip_point));
1291    }
1292#endif // DEBUG
1293
1294    if (scroll) {
1295        int pic_ysize         = int(aww->get_scrolled_picture_height());
1296        int slider_pos_yrange = pic_ysize - win_ysize;
1297
1298        if (slider_pos_y>slider_pos_yrange) slider_pos_y = slider_pos_yrange;
1299        if (slider_pos_y<0) slider_pos_y                 = 0;
1300
1301        aww->set_vertical_scrollbar_position(slider_pos_y);
1302        ED4_scrollbar_change_cb(aww, 0, 0);
1303    }
1304}
1305
1306void ED4_cursor::set_to_terminal(AW_window *aww, ED4_terminal *terminal, int seq_pos, ED4_CursorJumpType jump_type)
1307{
1308    if (seq_pos == -1) seq_pos = get_sequence_pos();
1309
1310    if (owner_of_cursor == terminal) {
1311        jump_sequence_pos(aww, seq_pos, jump_type);
1312    }
1313    else {
1314        if (owner_of_cursor) {
1315            if (get_sequence_pos() != seq_pos) {
1316                jump_sequence_pos(aww, seq_pos, jump_type); // position to wanted column -- scrolls horizontally
1317            }
1318        }
1319
1320        int scr_pos = ED4_ROOT->root_group_man->remap()->sequence_to_screen_clipped(seq_pos);
1321        show_cursor_at(terminal, scr_pos);
1322
1323        if (!is_partly_visible()) {
1324#if defined(DEBUG) && 0
1325            printf("Cursor not visible in set_to_terminal (was drawn outside screen)\n");
1326#endif // DEBUG
1327            jump_sequence_pos(aww, seq_pos, jump_type);
1328        }
1329    }
1330
1331    GB_transaction ta(GLOBAL_gb_main);
1332    updateAwars();
1333}
1334
1335ED4_returncode ED4_cursor::show_cursor_at(ED4_terminal *target_terminal, ED4_index scr_pos)
1336{
1337    if (owner_of_cursor) {
1338        if (is_partly_visible()) {
1339            delete_cursor(cursor_abs_x, owner_of_cursor);
1340        }
1341
1342        owner_of_cursor->set_refresh(); // we have to refresh old owner of cursor
1343        owner_of_cursor->parent->refresh_requested_by_child();
1344        owner_of_cursor = NULL;
1345        ED4_ROOT->refresh_window(0);
1346        DRAW = 1;
1347    }
1348
1349    target_terminal->scroll_into_view(ED4_ROOT->get_aww());
1350
1351    AW_pos termw_x, termw_y;
1352    target_terminal->calc_world_coords( &termw_x, &termw_y );
1353
1354    screen_position = scr_pos;
1355
1356    int length_of_char = ED4_ROOT->font_group.get_width(ED4_G_SEQUENCES);
1357
1358    AW_pos world_x = termw_x + length_of_char*screen_position + CHARACTEROFFSET;
1359    AW_pos world_y = termw_y;
1360
1361    AW_pos win_x = world_x;
1362    AW_pos win_y = world_y;
1363    ED4_ROOT->world_to_win_coords(ED4_ROOT->get_aww(), &win_x, &win_y);
1364
1365    cursor_abs_x = (long int)world_x;
1366    owner_of_cursor = target_terminal;
1367
1368    draw_cursor(win_x, win_y);
1369
1370    GB_transaction gb_dummy(GLOBAL_gb_main);
1371    updateAwars();
1372
1373    return ED4_R_OK;
1374}
1375
1376ED4_returncode ED4_cursor::show_clicked_cursor(AW_pos click_xpos, ED4_terminal *target_terminal)
1377{
1378    AW_pos termw_x, termw_y;
1379    target_terminal->calc_world_coords( &termw_x, &termw_y );
1380
1381    ED4_index scr_pos = ED4_ROOT->pixel2pos(click_xpos - termw_x);
1382    return show_cursor_at(target_terminal, scr_pos);
1383}
1384
1385ED4_terminal *ED4_cursor::get_upper_lower_cursor_pos(ED4_manager *starting_point, ED4_cursor_move cursor_move, AW_pos current_y, bool isScreen, ED4_TerminalTest terminal_is_appropriate, int seq_pos)
1386{
1387    // current_y is y-position of terminal at which search starts.
1388    // It may be in world or screen coordinates (isScreen marks which is used)
1389    // This is needed to move the cursor from top- to middle-area w/o scrolling middle-area to top-position.
1390
1391    ED4_terminal *result = 0;
1392
1393    for (int i=0; i<starting_point->children->members(); i++) {
1394        ED4_base *member = starting_point->children->member(i);
1395
1396        AW_pos x, y;
1397        member->calc_world_coords( &x, &y );
1398
1399        switch (cursor_move) {
1400            case ED4_C_UP:
1401                e4_assert(!isScreen); // use screen coordinates for ED4_C_DOWN only!
1402
1403                if (y < current_y) {
1404                    if ((member->is_manager()) && !member->flag.hidden) {
1405                        ED4_terminal *result_in_manager = get_upper_lower_cursor_pos(member->to_manager(), cursor_move, current_y, isScreen, terminal_is_appropriate, seq_pos);
1406                        if (result_in_manager) result   = result_in_manager;
1407                    }
1408
1409                    if ((member->dynamic_prop & ED4_P_CURSOR_ALLOWED)) {
1410                        if (terminal_is_appropriate==0 || terminal_is_appropriate(member, seq_pos)) {
1411                            result = member->to_terminal(); // overwrite (i.e. take last matching terminal)
1412                        }
1413                    }
1414                }
1415                break;
1416
1417            case ED4_C_DOWN:
1418                if (!result) { // don't overwrite (i.e. take first matching terminal)
1419                    if ((member->is_manager()) && !member->flag.hidden) {
1420                        result = get_upper_lower_cursor_pos(member->to_manager(), cursor_move, current_y, isScreen, terminal_is_appropriate, seq_pos);
1421                    }
1422
1423                    if (isScreen) ED4_ROOT->world_to_win_coords(ED4_ROOT->get_aww(), &x, &y); // if current_y is screen, convert x/y to screen-coordinates as well
1424
1425                    if ((member->dynamic_prop & ED4_P_CURSOR_ALLOWED) && y > current_y) {
1426                        ED4_multi_species_manager *marea_man = NULL; // probably multi_species_manager of middle_area, otherwise just a dummy
1427                        ED4_AREA_LEVEL level                 = member->get_area_level(&marea_man);
1428
1429                        if (level != ED4_A_MIDDLE_AREA) {
1430                            if (terminal_is_appropriate==0 || terminal_is_appropriate(member, seq_pos)) {
1431                                result = member->to_terminal();
1432                            }
1433                        }
1434                        else if (level == ED4_A_MIDDLE_AREA) {
1435                            AW_pos y_area = marea_man->parent->extension.position[Y_POS];
1436                            if (y > y_area) {
1437                                member = starting_point->children->member(i);
1438                                if (terminal_is_appropriate==0 || terminal_is_appropriate(member, seq_pos)) {
1439                                    result = member->to_terminal();
1440                                }
1441                            }
1442                        }
1443                    }
1444                }
1445                break;
1446
1447            default:
1448                e4_assert(0);
1449                break;
1450        }
1451    }
1452
1453    return result;
1454}
1455
1456/* --------------------------------------------------------------------------------
1457   ED4_base_position
1458   -------------------------------------------------------------------------------- */
1459
1460ED4_base_position::ED4_base_position()
1461    : calced4base(0)
1462    , seq_pos(0)
1463    , count(0)
1464{
1465}
1466
1467ED4_base_position::~ED4_base_position() {
1468    invalidate();
1469    delete [] seq_pos;
1470}
1471
1472static void ed4_bp_sequence_changed_cb(ED4_species_manager *, AW_CL cl_base_pos) {
1473    ED4_base_position *base_pos = (ED4_base_position*)cl_base_pos;
1474    base_pos->invalidate();
1475}
1476
1477void ED4_base_position::invalidate() {
1478    if (calced4base) {
1479        ED4_species_manager *species_manager = calced4base->get_parent(ED4_L_SPECIES)->to_species_manager();
1480        species_manager->remove_sequence_changed_cb(ed4_bp_sequence_changed_cb, (AW_CL)this);
1481
1482        calced4base = 0;
1483    }
1484}
1485
1486void ED4_base_position::calc4base(const ED4_base *base)
1487{
1488    e4_assert(base);
1489
1490    ED4_species_manager *species_manager = base->get_parent(ED4_L_SPECIES)->to_species_manager();
1491    int                  len;
1492    char                *seq;
1493
1494    if (calced4base) {
1495        ED4_species_manager *prev_species_manager = calced4base->get_parent(ED4_L_SPECIES)->to_species_manager();
1496        prev_species_manager->remove_sequence_changed_cb(ed4_bp_sequence_changed_cb, (AW_CL)this);
1497    }
1498
1499    species_manager->add_sequence_changed_cb(ed4_bp_sequence_changed_cb, (AW_CL)this);
1500
1501    if (species_manager->flag.is_consensus) {
1502        ED4_group_manager *group_manager = base->get_parent(ED4_L_GROUP)->to_group_manager();
1503
1504        seq = group_manager->table().build_consensus_string();
1505        len = strlen(seq);
1506    }
1507    else {
1508        seq = base->resolve_pointer_to_string_copy(&len);
1509    }
1510
1511    e4_assert(seq);
1512
1513    delete [] seq_pos;
1514    calced4base = base;
1515
1516    {
1517        int *pos = new int[len];
1518        int p;
1519
1520        count = 0;
1521        for (p=0; p<len; p++) {
1522            if (!ADPP_IS_ALIGN_CHARACTER(seq[p])) {
1523                pos[count++] = p;
1524            }
1525        }
1526
1527        if (count) {
1528            seq_pos = new int[count];
1529            for (p=0; p<count; p++) {
1530                seq_pos[p] = pos[p];
1531            }
1532        }
1533        else {
1534            seq_pos = 0;
1535        }
1536
1537        delete[] pos;
1538    }
1539
1540    free(seq);
1541}
1542int ED4_base_position::get_base_position(const ED4_base *base, int sequence_position)
1543{
1544    if (!base) return 0;
1545    if (base!=calced4base) calc4base(base);
1546
1547    if (count==0) return 0;
1548    if (sequence_position>seq_pos[count-1]) return count;
1549
1550    int h = count-1,
1551        l = 0;
1552
1553    while (1)
1554    {
1555        int m = (l+h)/2;
1556
1557        if (seq_pos[m]==sequence_position) {
1558            return m;
1559        }
1560        else {
1561            if (l==h) break;
1562
1563            if (sequence_position<seq_pos[m]) h = m;
1564            else                              l = m+1;
1565        }
1566    }
1567
1568    return l;
1569}
1570int ED4_base_position::get_sequence_position(const ED4_base *base, int base_pos)
1571{
1572    if (!base) return 0;
1573    if (base!=calced4base) calc4base(base);
1574    return base_pos<count ? seq_pos[base_pos] : seq_pos[count-1]+1;
1575}
1576
1577int ED4_get_base_position(const ED4_sequence_terminal *seq_term, int seq_position) {
1578    static ED4_base_position *base_pos = 0;
1579
1580    if (!base_pos) base_pos = new ED4_base_position;
1581    return base_pos->get_base_position(seq_term, seq_position);
1582}
1583
1584
1585/* --------------------------------------------------------------------------------
1586   Store/Restore Cursorpositions
1587   -------------------------------------------------------------------------------- */
1588
1589class CursorPos
1590{
1591    ED4_terminal *terminal;
1592    int seq_pos;
1593
1594    CursorPos *next;
1595
1596    static CursorPos *head;
1597
1598public:
1599
1600    static void clear()
1601    {
1602        while (head) {
1603            CursorPos *p = head->next;
1604
1605            delete head;
1606            head = p;
1607        }
1608    }
1609    static CursorPos *get_head() { return head; }
1610
1611    CursorPos(ED4_terminal *t, int p)
1612    {
1613        terminal = t;
1614        seq_pos = p;
1615        next = head;
1616        head = this;
1617    }
1618    ~CursorPos() {}
1619
1620    ED4_terminal *get_terminal() const { return terminal; }
1621    int get_seq_pos() const { return seq_pos; }
1622
1623    void moveToEnd()
1624    {
1625        e4_assert(this==head);
1626
1627        if (next) {
1628            CursorPos *p = head = next;
1629
1630            while (p->next) {
1631                p = p->next;
1632            }
1633
1634            p->next = this;
1635            this->next = 0;
1636        }
1637    }
1638};
1639
1640CursorPos *CursorPos::head = 0;
1641
1642void ED4_store_curpos(AW_window *aww, AW_CL /*cd1*/, AW_CL /*cd2*/)
1643{
1644    GB_transaction dummy(GLOBAL_gb_main);
1645    ED4_ROOT->use_window(aww);
1646    ED4_cursor *cursor = &ED4_ROOT->get_ed4w()->cursor;
1647    if (!cursor->owner_of_cursor) {
1648        aw_message("First you have to place the cursor.");
1649        return;
1650    }
1651
1652    new CursorPos(cursor->owner_of_cursor->to_terminal(), cursor->get_sequence_pos());
1653}
1654
1655void ED4_restore_curpos(AW_window *aww, AW_CL /*cd1*/, AW_CL /*cd2*/)
1656{
1657    GB_transaction dummy(GLOBAL_gb_main);
1658    ED4_ROOT->use_window(aww);
1659    ED4_cursor *cursor = &ED4_ROOT->get_ed4w()->cursor;
1660
1661    CursorPos *pos = CursorPos::get_head();
1662    if (!pos) {
1663        aw_message("No cursor position stored.");
1664        return;
1665    }
1666
1667    pos->get_terminal()->setCursorTo(cursor, pos->get_seq_pos(), true, ED4_JUMP_KEEP_VISIBLE);
1668    pos->moveToEnd();
1669}
1670
1671void ED4_clear_stored_curpos(AW_window */*aww*/, AW_CL /*cd1*/, AW_CL /*cd2*/)
1672{
1673    CursorPos::clear();
1674}
1675
1676/* --------------------------------------------------------------------------------
1677   Other stuff
1678   -------------------------------------------------------------------------------- */
1679
1680void ED4_helix_jump_opposite(AW_window *aww, AW_CL /*cd1*/, AW_CL /*cd2*/)
1681{
1682    GB_transaction  dummy(GLOBAL_gb_main);
1683    ED4_ROOT->use_window(aww);
1684    ED4_cursor     *cursor = &ED4_ROOT->get_ed4w()->cursor;
1685
1686    if (!cursor->owner_of_cursor) {
1687        aw_message("First you have to place the cursor.");
1688        return;
1689    }
1690
1691    int           seq_pos  = cursor->get_sequence_pos();
1692    AW_helix     *helix    = ED4_ROOT->helix;
1693    BI_PAIR_TYPE  pairType = helix->pairtype(seq_pos);
1694
1695    if (pairType != HELIX_NONE) {
1696        int pairing_pos = helix->opposite_position(seq_pos);
1697        cursor->jump_sequence_pos(aww, pairing_pos, ED4_JUMP_KEEP_POSITION);
1698    }
1699    else {
1700        aw_message("Not at helix position");
1701    }
1702}
1703
1704void ED4_change_cursor(AW_window */*aww*/, AW_CL /*cd1*/, AW_CL /*cd2*/) {
1705    ED4_cursor *cursor = &ED4_ROOT->get_ed4w()->cursor;
1706    ED4_CursorType typ = cursor->getType();
1707
1708    cursor->changeType((ED4_CursorType)((typ+1)%ED4_CURSOR_TYPES));
1709}
Note: See TracBrowser for help on using the repository browser.