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

Last change on this file was 6109, checked in by westram, 15 years ago
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 55.1 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_get_and_jump_to_species(GB_CSTR species_name)
595{
596    e4_assert(species_name && species_name[0]);
597
598    GB_transaction dummy(GLOBAL_gb_main);
599    ED4_species_name_terminal *name_term = ED4_find_species_name_terminal(species_name);
600    int loaded = 0;
601
602    if (!name_term) { // insert new species
603        ED4_multi_species_manager *insert_into_manager = ED4_new_species_multi_species_manager();
604        ED4_group_manager         *group_man           = insert_into_manager->get_parent(ED4_L_GROUP)->to_group_manager();
605        char                      *string              = (char*)GB_calloc(strlen(species_name)+3, sizeof(*string));
606        int                        index               = 0;
607        ED4_index                  y                   = 0;
608        ED4_index                  lot                 = 0;
609
610        all_found         = 0;
611        not_found_message = GBS_stropen(1000);
612        GBS_strcat(not_found_message,"Species not found: ");
613
614        sprintf(string, "-L%s", species_name);
615        ED4_ROOT->database->fill_species(insert_into_manager,
616                                         ED4_ROOT->ref_terminals.get_ref_sequence_info(), ED4_ROOT->ref_terminals.get_ref_sequence(),
617                                         string, &index, &y, 0, &lot, insert_into_manager->calc_group_depth());
618        loaded = 1;
619
620        {
621            char *out_message = GBS_strclose(not_found_message);
622            not_found_message = 0;
623            if (all_found != 0) aw_message(out_message);
624            free(out_message);
625        }
626
627        {
628            GBDATA *gb_species = GBT_find_species(GLOBAL_gb_main, species_name);
629            GBDATA *gbd = GBT_read_sequence(gb_species, ED4_ROOT->alignment_name);
630
631            if (gbd) {
632                char *data = GB_read_string(gbd);
633                int len = GB_read_string_count(gbd);
634                group_man->table().add(data, len);
635            }
636        }
637
638        name_term = ED4_find_species_name_terminal(species_name);
639        if (name_term) {
640            /* new AAseqTerminals should be created if it is in ProtView mode */
641            if(ED4_ROOT->alignment_type == GB_AT_DNA) {
642                PV_AddCorrespondingAAseqTerminals(name_term);
643            }
644            ED4_ROOT->main_manager->update_info.set_resize(1);
645            ED4_ROOT->main_manager->resize_requested_by_parent();
646            /* it should create new AA Sequence terminals if the protien viewer is enabled */
647        }
648        delete string;
649    }
650    if (name_term) {
651        jump_to_species(name_term, -1, true, ED4_JUMP_KEEP_POSITION);
652        if (!loaded) {
653            aw_message(GBS_global_string("'%s' is already loaded.", species_name));
654        }
655    }
656    else {
657        aw_message(GBS_global_string("Cannot get species '%s'", species_name));
658    }
659}
660
661void ED4_get_and_jump_to_actual(AW_window *, AW_CL)
662{
663    char *name = GBT_read_string(GLOBAL_gb_main, AWAR_SPECIES_NAME);
664    if (name && name[0]) {
665        ED4_get_and_jump_to_species(name);
666        ED4_ROOT->refresh_all_windows(0);
667    }
668    else {
669        aw_message("Please select a species");
670    }
671}
672
673void ED4_get_and_jump_to_actual_from_menu(AW_window *aw, AW_CL cl, AW_CL) {
674    ED4_get_and_jump_to_actual(aw, cl);
675    ED4_ROOT->refresh_all_windows(0);
676}
677
678void ED4_get_marked_from_menu(AW_window *, AW_CL, AW_CL) {
679#define BUFFERSIZE 1000
680    GB_transaction dummy(GLOBAL_gb_main);
681    int marked = GBT_count_marked_species(GLOBAL_gb_main);
682
683    if (marked) {
684        GBDATA *gb_species = GBT_first_marked_species(GLOBAL_gb_main);
685        int count = 0;
686        char *buffer = new char[BUFFERSIZE+1];
687        char *bp = buffer;
688        //      int inbuf = 0; // # of names in buffer
689        ED4_multi_species_manager *insert_into_manager = ED4_new_species_multi_species_manager();
690        ED4_group_manager *group_man = insert_into_manager->get_parent(ED4_L_GROUP)->to_group_manager();
691        int group_depth = insert_into_manager->calc_group_depth();
692        int index = 0;
693        ED4_index y = 0;
694        ED4_index lot = 0;
695        int inserted = 0;
696        char *default_alignment = GBT_get_default_alignment(GLOBAL_gb_main);
697
698        aw_openstatus("ARB_EDIT4");
699        aw_status("Loading species...");
700
701        all_found         = 0;
702        not_found_message = GBS_stropen(1000);
703        GBS_strcat(not_found_message,"Species not found: ");
704
705        while (gb_species) {
706            count++;
707            GB_status(double(count)/double(marked));
708
709            const char *name = GBT_read_name(gb_species);
710            ED4_species_name_terminal *name_term = ED4_find_species_name_terminal(name);
711
712            if (!name_term) { // species not found -> insert
713                {
714                    int namelen = strlen(name);
715                    int buffree = BUFFERSIZE-int(bp-buffer);
716
717                    if ((namelen+2)>buffree) {
718                        *bp++ = 0;
719                        ED4_ROOT->database->fill_species(insert_into_manager,
720                                                         ED4_ROOT->ref_terminals.get_ref_sequence_info(), ED4_ROOT->ref_terminals.get_ref_sequence(),
721                                                         buffer, &index, &y, 0, &lot, group_depth);
722                        bp = buffer;
723                        index = 0;
724                    }
725
726                    *bp++ = 1;
727                    *bp++ = 'L';
728                    memcpy(bp, name, namelen);
729                    bp += namelen;
730                }
731
732                {
733                    GBDATA *gbd = GBT_read_sequence(gb_species, default_alignment);
734
735                    if (gbd) {
736                        char *data = GB_read_string(gbd);
737                        int len = GB_read_string_count(gbd);
738                        group_man->table().add(data, len);
739                    }
740                }
741
742                inserted++;
743            }
744            gb_species = GBT_next_marked_species(gb_species);
745        }
746
747        if (bp>buffer) {
748            *bp++ = 0;
749            ED4_ROOT->database->fill_species(insert_into_manager,
750                                             ED4_ROOT->ref_terminals.get_ref_sequence_info(), ED4_ROOT->ref_terminals.get_ref_sequence(),
751                                             buffer, &index, &y, 0, &lot, group_depth);
752        }
753
754        aw_closestatus();
755        aw_message(GBS_global_string("Loaded %i of %i marked species.", inserted, marked));
756
757        {
758            char *out_message = GBS_strclose(not_found_message);
759            not_found_message = 0;
760            if (all_found != 0) aw_message(out_message);
761            free(out_message);
762        }
763
764        if (inserted) {
765            /* new AAseqTerminals should be created if it is in ProtView mode */
766            if (ED4_ROOT->alignment_type == GB_AT_DNA) {
767                PV_AddAAseqTerminalsToLoadedSpecies();
768            }
769
770            ED4_ROOT->main_manager->update_info.set_resize(1);
771            ED4_ROOT->main_manager->resize_requested_by_parent();
772        }
773
774        delete buffer;
775        delete default_alignment;
776    }
777    else {
778        aw_message("No species marked.");
779    }
780
781#undef BUFFERSIZE
782
783    ED4_ROOT->refresh_all_windows(0);
784}
785
786ED4_returncode ED4_cursor::HideCursor()
787{
788    if (owner_of_cursor) {
789        if (is_partly_visible()) {
790            delete_cursor(cursor_abs_x, owner_of_cursor);
791        }
792        owner_of_cursor = 0;
793    }
794
795    return ED4_R_OK;
796}
797
798void ED4_cursor::changeType(ED4_CursorType typ)
799{
800    if (owner_of_cursor) {
801        ED4_base *old_owner_of_cursor = owner_of_cursor;
802
803        HideCursor();
804        ctype = typ;
805        ED4_ROOT->aw_root->awar(ED4_AWAR_CURSOR_TYPE)->write_int(int(ctype));
806        owner_of_cursor = old_owner_of_cursor;
807        ShowCursor(0, ED4_C_NONE, 0);
808    }
809    else {
810        ctype = typ;
811    }
812}
813
814int ED4_update_global_cursor_awars_allowed = true;
815
816void ED4_cursor::updateAwars()
817{
818    AW_root     *aw_root = ED4_ROOT->aw_root;
819    ED4_window  *win = ED4_ROOT->get_ed4w();
820    int         seq_pos = get_sequence_pos();
821
822    if (ED4_update_global_cursor_awars_allowed) {
823        if (owner_of_cursor) {
824            ED4_terminal *cursor_terminal = owner_of_cursor->to_terminal();
825            char         *species_name    = cursor_terminal->get_name_of_species();
826
827            if (species_name) {
828                ED4_manager *cursor_manager = cursor_terminal->parent->parent->to_manager();
829
830                if (cursor_manager->parent->flag.is_SAI) {
831                    static char *last_set_SAI = 0;
832                    if (!last_set_SAI || strcmp(last_set_SAI, species_name) != 0) {
833                        freedup(last_set_SAI, species_name);
834
835                        ignore_selected_SAI_changes_cb = true;
836                        GBT_write_string(GLOBAL_gb_main, AWAR_SAI_NAME, species_name);
837                        ignore_selected_SAI_changes_cb = false;
838                    }
839                }
840                else {
841                    static char *last_set_species = 0;
842                    if (!last_set_species || strcmp(last_set_species, species_name) != 0) {
843                        freedup(last_set_species, species_name);
844
845                        ignore_selected_species_changes_cb = true;
846                        GBT_write_string(GLOBAL_gb_main, AWAR_SPECIES_NAME, species_name);
847                        ignore_selected_species_changes_cb = false;
848                    }
849                }
850            }
851            free(species_name);
852        }
853    }
854
855    // update awars for cursor position:
856
857    aw_root->awar(win->awar_path_for_cursor)->write_int(seq_pos+1);
858    if (ED4_update_global_cursor_awars_allowed) {
859        aw_root->awar(AWAR_CURSOR_POSITION)->write_int(seq_pos+1);      // this supports last cursor position for all applications
860    }
861
862    // look if we have a commented search result under the cursor:
863
864    if (owner_of_cursor && owner_of_cursor->is_sequence_terminal()) {
865        ED4_sequence_terminal *seq_term = owner_of_cursor->to_sequence_terminal();
866        ED4_SearchResults &results = seq_term->results();
867        ED4_SearchPosition *pos = results.get_shown_at(seq_pos);
868
869        if (pos) {
870            GB_CSTR comment = pos->get_comment();
871
872            if (comment) {
873                char *buffer = GB_give_buffer(strlen(comment)+30);
874
875                sprintf(buffer, "%s: %s", ED4_SearchPositionTypeId[pos->get_whatsFound()], comment);
876                aw_message(buffer);
877            }
878        }
879    }
880
881    // update awar for ecoli position:
882
883    BI_ecoli_ref *ecoli = ED4_ROOT->ecoli_ref;
884    if (ecoli->gotData()) {
885        long ecoli_pos = ecoli->abs_2_rel(seq_pos);
886        aw_root->awar(win->awar_path_for_Ecoli)->write_int(ecoli_pos+1);
887    }
888
889    // update awar for base position:
890
891    int base_pos = base_position.get_base_position(owner_of_cursor, seq_pos+1);
892    aw_root->awar(win->awar_path_for_basePos)->write_int(base_pos); // update awar for base position
893
894    // update awar for IUPAC:
895
896#define MAXIUPAC 6
897
898    char iupac[MAXIUPAC+1];
899    strcpy(iupac, ED4_IUPAC_EMPTY);
900
901    if (owner_of_cursor) {
902        ED4_species_manager *species_manager = owner_of_cursor->get_parent(ED4_L_SPECIES)->to_species_manager();
903        int                  len;
904        char                *seq;
905
906        if (species_manager->flag.is_consensus) {
907            ED4_group_manager *group_manager = owner_of_cursor->get_parent(ED4_L_GROUP)->to_group_manager();
908
909            seq = group_manager->table().build_consensus_string(seq_pos, seq_pos, 0);
910            len = seq_pos+1; // fake
911        }
912        else {
913            seq = owner_of_cursor->resolve_pointer_to_string_copy(&len);
914        }
915
916        e4_assert(seq);
917
918        if (seq_pos<len) {
919            char base = seq[seq_pos];
920            const char *i = ED4_decode_iupac(base, ED4_ROOT->alignment_type);
921
922            e4_assert(strlen(i)<=MAXIUPAC);
923            strcpy(iupac, i);
924        }
925
926        free(seq);
927    }
928
929#undef MAXIUPAC
930
931    aw_root->awar(win->awar_path_for_IUPAC)->write_string(iupac);
932
933    // update awar for helix#:
934    const char *helixNr = ED4_ROOT->helix->helixNr(seq_pos);
935    aw_root->awar(win->awar_path_for_helixNr)->write_string(helixNr ? helixNr : "");
936}
937
938int ED4_cursor::get_screen_relative_pos() {
939    ED4_coords *coords = &ED4_ROOT->get_ed4w()->coords;
940    return cursor_abs_x - coords->window_left_clip_point;
941}
942void ED4_cursor::set_screen_relative_pos(AW_window *aww, int scroll_to_relpos) {
943    int curr_rel_pos  = get_screen_relative_pos();
944    int scroll_amount = curr_rel_pos-scroll_to_relpos;
945
946    int length_of_char = ED4_ROOT->font_group.get_width(ED4_G_SEQUENCES);
947    scroll_amount      = (scroll_amount/length_of_char)*length_of_char; // align to char-size
948
949    if (scroll_amount != 0) {
950        aww->set_horizontal_scrollbar_position(aww->slider_pos_horizontal + scroll_amount);
951#if defined(DEBUG)
952        printf("set_screen_relative_pos(%i) auto-scrolls %i\n", scroll_to_relpos, scroll_amount);
953#endif // DEBUG
954        ED4_horizontal_change_cb(aww, 0, 0);
955    }
956}
957
958
959void ED4_cursor::jump_screen_pos(AW_window *aww, int screen_pos, ED4_CursorJumpType jump_type) {
960    if (!owner_of_cursor) {
961        aw_message("First you have to place the cursor");
962        return;
963    }
964
965    ED4_base *temp_parent = owner_of_cursor;
966    while (temp_parent->parent) {
967        temp_parent = temp_parent->parent;
968        if (temp_parent->flag.hidden) return; // don't move cursor if terminal is flag.hidden
969    }
970
971    AW_pos terminal_x, terminal_y;
972    owner_of_cursor->calc_world_coords(&terminal_x, &terminal_y);
973
974#if defined(DEBUG) && 0
975    printf("jump_screen_pos(%i)\n", screen_pos);
976#endif // DEBUG
977
978    ED4_terminal *term = owner_of_cursor->to_terminal();
979    term->scroll_into_view(aww); // correct y-position of terminal
980
981    int cursor_diff = screen_pos-screen_position;
982    if (cursor_diff == 0) { // cursor position did not change
983        if (jump_type == ED4_JUMP_KEEP_VISIBLE) return; // nothing special -> done
984    }
985
986    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());
987    int length_of_char        = ED4_ROOT->font_group.get_width(ED4_G_SEQUENCES);
988    int abs_x_new             = cursor_abs_x+cursor_diff*length_of_char; // position in terminal
989
990    if (abs_x_new > terminal_x+terminal_pixel_length+CHARACTEROFFSET || abs_x_new < terminal_x+CHARACTEROFFSET) {
991        return; // don`t move out of terminal
992    }
993
994    ED4_coords *coords = &ED4_ROOT->get_ed4w()->coords;
995
996    int screen_width  = coords->window_right_clip_point-coords->window_left_clip_point;
997    int scroll_new_to = -1;     // if >0 -> scroll abs_x_new to this screen-relative position
998
999    if (jump_type != ED4_JUMP_KEEP_VISIBLE) {
1000        int rel_x = cursor_abs_x-coords->window_left_clip_point;
1001
1002        if (jump_type == ED4_JUMP_KEEP_POSITION) {
1003            bool was_in_screen = rel_x >= 0 && rel_x <= screen_width;
1004            if (!was_in_screen) {
1005                jump_type = ED4_JUMP_KEEP_VISIBLE; // // don't have useful relative position -> scroll
1006            }
1007        }
1008
1009        switch (jump_type) {
1010            case ED4_JUMP_CENTERED:             scroll_new_to = screen_width/2;         break;
1011            case ED4_JUMP_KEEP_POSITION:        scroll_new_to = rel_x;                  break;
1012            case ED4_JUMP_KEEP_VISIBLE:         break; // handled below
1013            default: e4_assert(0); break;
1014        }
1015    }
1016
1017    if (jump_type == ED4_JUMP_KEEP_VISIBLE) {
1018        int margin = length_of_char * ED4_ROOT->aw_root->awar(ED4_AWAR_SCROLL_MARGIN)->read_int();
1019
1020        int right_margin = coords->window_right_clip_point - margin;
1021        int left_margin  = coords->window_left_clip_point + margin;
1022
1023        if (left_margin >= right_margin)    scroll_new_to = screen_width/2; // margins too big -> center
1024        else if (abs_x_new > right_margin)  scroll_new_to = screen_width-margin;
1025        else if (abs_x_new < left_margin)   scroll_new_to = margin;
1026    }
1027
1028    delete_cursor(cursor_abs_x, owner_of_cursor);
1029
1030    int old_allowed_to_draw = allowed_to_draw;
1031    if (scroll_new_to >= 0) {   // scroll
1032        int rel_x_new     = abs_x_new-coords->window_left_clip_point;
1033        int scroll_amount = rel_x_new-scroll_new_to;
1034
1035        if      (scroll_amount>0) scroll_amount += length_of_char/2;
1036        else if (scroll_amount<0) scroll_amount -= length_of_char/2;
1037
1038        scroll_amount = (scroll_amount/length_of_char)*length_of_char; // align to char-size
1039        if (scroll_amount != 0) {
1040            aww->set_horizontal_scrollbar_position(aww->slider_pos_horizontal + scroll_amount);
1041#if defined(DEBUG) && 0
1042            printf("jump_screen_pos auto-scrolls %i\n", scroll_amount);
1043#endif // DEBUG
1044            allowed_to_draw = 0;
1045            ED4_horizontal_change_cb(aww, 0, 0);
1046        }
1047    }
1048
1049    allowed_to_draw = 1;
1050    if (cursor_diff >= 0) {
1051        ShowCursor(cursor_diff*length_of_char, ED4_C_RIGHT, ABS(cursor_diff));
1052    }
1053    else {
1054        ShowCursor(cursor_diff*length_of_char, ED4_C_LEFT, ABS(cursor_diff));
1055    }
1056    allowed_to_draw = old_allowed_to_draw;
1057}
1058
1059void ED4_cursor::jump_sequence_pos(AW_window *aww, int seq_pos, ED4_CursorJumpType jump_type) {
1060    int screen_pos = ED4_ROOT->root_group_man->remap()->sequence_to_screen_clipped(seq_pos);
1061    jump_screen_pos(aww, screen_pos, jump_type);
1062}
1063
1064void ED4_cursor::jump_base_pos(AW_window *aww, int base_pos, ED4_CursorJumpType jump_type) {
1065    int seq_pos = base2sequence_position(base_pos);
1066    jump_sequence_pos(aww, seq_pos, jump_type);
1067}
1068
1069static bool has_gap_or_base_at(ED4_base *terminal, bool test_for_base, int seq_pos) {
1070    bool test_succeeded = false;
1071
1072    if (terminal->is_sequence_terminal()) {
1073        ED4_sequence_terminal *seqTerm = terminal->to_sequence_terminal();
1074        int len;
1075        char *seq = seqTerm->resolve_pointer_to_string_copy(&len);
1076        if (seq) {
1077            test_succeeded = len>seq_pos && bool(ADPP_IS_ALIGN_CHARACTER(seq[seq_pos]))!=test_for_base;
1078        }
1079        free(seq);
1080    }
1081
1082#if defined(DEBUG) && 0
1083    printf("test_for_base=%i test_succeeded=%i\n", int(test_for_base), int(test_succeeded));
1084#endif // DEBUG
1085    return test_succeeded;
1086}
1087
1088static bool has_base_at(ED4_base *terminal, int seq_pos) { return has_gap_or_base_at(terminal, true,  seq_pos); }
1089static bool has_gap_at(ED4_base *terminal, int seq_pos) { return has_gap_or_base_at(terminal, false, seq_pos); }
1090
1091
1092ED4_returncode ED4_cursor::move_cursor(AW_event *event) {
1093    // move cursor up down
1094    ED4_cursor_move dir     = ED4_C_NONE;
1095    ED4_returncode result   = ED4_R_OK;
1096    bool            endHome = false;
1097
1098    switch (event->keycode) {
1099        case AW_KEY_UP:   dir = ED4_C_UP;   break;
1100        case AW_KEY_DOWN: dir = ED4_C_DOWN; break;
1101        case AW_KEY_HOME: dir = ED4_C_UP;   endHome = true; break;
1102        case AW_KEY_END:  dir = ED4_C_DOWN; endHome = true; break;
1103        default: e4_assert(0); break; // illegal call of move_cursor()
1104    }
1105
1106    if (dir != ED4_C_NONE) {
1107        // don't move cursor if terminal is hidden
1108        {
1109            ED4_base *temp_parent = owner_of_cursor->parent;
1110            while (temp_parent->parent && result == ED4_R_OK) {
1111                if (temp_parent->flag.hidden) { result = ED4_R_IMPOSSIBLE; }
1112                temp_parent = temp_parent->parent;
1113            }
1114        }
1115
1116        if (result == ED4_R_OK) {
1117            AW_pos     x_dummy, y_world;
1118            AW_window *aww      = ED4_ROOT->get_aww();
1119
1120            owner_of_cursor->calc_world_coords(&x_dummy, &y_world);
1121
1122            int       seq_pos         = get_sequence_pos();
1123            ED4_base *target_terminal = 0;
1124
1125            if (event->keymodifier & AW_KEYMODE_CONTROL) {
1126                bool has_base = has_base_at(owner_of_cursor, seq_pos);
1127
1128                // stay in current area
1129                ED4_manager *start_at_manager = 0;
1130                if (owner_of_cursor->has_parent(ED4_ROOT->top_area_man)) {
1131                    start_at_manager = ED4_ROOT->top_area_man;
1132                }
1133                else {
1134                    start_at_manager = ED4_ROOT->middle_area_man;
1135                }
1136
1137                if (!endHome) { // not End or Home
1138                    target_terminal = get_upper_lower_cursor_pos(start_at_manager, dir, y_world, false, has_base ? has_gap_at : has_base_at, seq_pos);
1139                    if (target_terminal && !has_base && ED4_ROOT->aw_root->awar(ED4_AWAR_FAST_CURSOR_JUMP)->read_int())  { // if jump_over group
1140                        target_terminal->calc_world_coords(&x_dummy, &y_world);
1141                        target_terminal = get_upper_lower_cursor_pos(start_at_manager, dir, y_world, false, has_gap_at, seq_pos);
1142                    }
1143                }
1144
1145                if (target_terminal == 0) {
1146                    // either already in last group (or no space behind last group) -> jump to end (or start)
1147                    target_terminal = get_upper_lower_cursor_pos(start_at_manager,
1148                                                                 dir == ED4_C_UP ? ED4_C_DOWN : ED4_C_UP, // use opposite movement direction
1149                                                                 dir == ED4_C_UP ? 0 : INT_MAX, false, // search for top-/bottom-most terminal
1150                                                                 0, seq_pos);
1151                }
1152            }
1153            else {
1154                e4_assert(!endHome); // END and HOME w/o Ctrl should not call move_cursor()
1155
1156                bool isScreen = false;
1157                if (dir == ED4_C_DOWN) {
1158                    ED4_ROOT->world_to_win_coords(aww, &x_dummy, &y_world); // special handling to move cursor from top to bottom area
1159                    isScreen = true;
1160                }
1161                target_terminal = get_upper_lower_cursor_pos(ED4_ROOT->main_manager, dir, y_world, isScreen, 0, seq_pos);
1162            }
1163
1164            if (target_terminal) {
1165                set_to_terminal(aww, target_terminal->to_terminal(), seq_pos, ED4_JUMP_KEEP_VISIBLE);
1166            }
1167        }
1168    }
1169
1170    return result;
1171}
1172
1173void ED4_cursor::set_abs_x()
1174{
1175    AW_pos x, y;
1176    owner_of_cursor->calc_world_coords( &x, &y );
1177    cursor_abs_x = int(get_sequence_pos()*ED4_ROOT->font_group.get_width(ED4_G_SEQUENCES) + CHARACTEROFFSET + x);
1178}
1179
1180
1181ED4_returncode ED4_cursor::ShowCursor(ED4_index offset_x, ED4_cursor_move move, int move_pos)
1182{
1183    AW_pos x=0, y=0, x_help = 0, y_help;
1184
1185    owner_of_cursor->calc_world_coords( &x, &y );
1186
1187    switch (move)
1188    {
1189        case ED4_C_RIGHT:
1190            screen_position += move_pos;
1191            break;
1192        case ED4_C_LEFT:
1193            screen_position -= move_pos;
1194            break;
1195        case ED4_C_NONE:
1196            break;
1197        default:
1198            e4_assert(0);
1199            break;
1200    }
1201
1202    updateAwars();
1203
1204    x_help = cursor_abs_x + offset_x;
1205    y_help = y;
1206
1207    ED4_ROOT->world_to_win_coords(ED4_ROOT->get_aww(), &x_help, &y_help);
1208
1209    if (allowed_to_draw) draw_cursor(x_help, y_help);
1210#if defined(DEBUG) && 0
1211    else printf("Skip draw_cursor (allowed_to_draw=false)\n");
1212#endif // DEBUG
1213
1214    cursor_abs_x += offset_x;
1215
1216    return ( ED4_R_OK );
1217}
1218
1219
1220bool ED4_cursor::is_partly_visible() const {
1221    e4_assert(owner_of_cursor);
1222    e4_assert(cursor_shape); // cursor is not drawn, cannot test visibility
1223
1224    AW_pos x,y;
1225    owner_of_cursor->calc_world_coords( &x, &y );
1226
1227    int x1, y1, x2, y2;
1228    cursor_shape->get_bounding_box(cursor_abs_x, int(y), x1, y1, x2, y2);
1229
1230    bool visible = false;
1231
1232    switch (owner_of_cursor->get_area_level(0)) {
1233        case ED4_A_TOP_AREA:
1234            visible =
1235                owner_of_cursor->is_visible(x1, 0, ED4_D_HORIZONTAL) ||
1236                owner_of_cursor->is_visible(x2, 0, ED4_D_HORIZONTAL);
1237            break;
1238        case ED4_A_MIDDLE_AREA:
1239            visible = owner_of_cursor->is_visible(x1, y1, x2, y2, ED4_D_ALL_DIRECTION);
1240            break;
1241        default:
1242            break;
1243    }
1244
1245    return visible;
1246}
1247
1248void ED4_terminal::scroll_into_view(AW_window *aww) { // scroll y-position only
1249    AW_pos termw_x, termw_y;
1250    calc_world_coords(&termw_x, &termw_y);
1251
1252    ED4_coords *coords  = &ED4_ROOT->get_ed4w()->coords;
1253
1254    int term_height = int(extension.size[1]);
1255    int win_ysize   = coords->window_lower_clip_point - coords->window_upper_clip_point + 1;
1256
1257    bool scroll = false;
1258    int slider_pos_y;
1259
1260    AW_pos termw_y_upper = termw_y - term_height; // upper border of terminal
1261
1262    if (termw_y_upper > coords->top_area_height) { // dont scroll if terminal is in top area (always visible)
1263        if (termw_y_upper < coords->window_upper_clip_point) {
1264#if defined(DEBUG) && 0
1265            printf("termw_y(%i)-term_height(%i) < window_upper_clip_point(%i)\n",
1266                   int(termw_y), term_height, int(coords->window_upper_clip_point));
1267#endif // DEBUG
1268            slider_pos_y = int(termw_y - coords->top_area_height - term_height);
1269            scroll       = true;
1270        }
1271        else if (termw_y > coords->window_lower_clip_point) {
1272#if defined(DEBUG) && 0
1273            printf("termw_y(%i) > window_lower_clip_point(%i)\n",
1274                   int(termw_y), int(coords->window_lower_clip_point));
1275#endif // DEBUG
1276            slider_pos_y = int(termw_y - coords->top_area_height - win_ysize);
1277            scroll       = true;
1278        }
1279    }
1280
1281#if defined(DEBUG) && 0
1282    if (!scroll) {
1283        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",
1284               int(termw_y), int(termw_y_upper), term_height,
1285               int(coords->window_upper_clip_point), int(coords->window_lower_clip_point));
1286    }
1287#endif // DEBUG
1288
1289    if (scroll) {
1290        int pic_ysize         = int(aww->get_scrolled_picture_height());
1291        int slider_pos_yrange = pic_ysize - win_ysize;
1292
1293        if (slider_pos_y>slider_pos_yrange) slider_pos_y = slider_pos_yrange;
1294        if (slider_pos_y<0) slider_pos_y                 = 0;
1295
1296        aww->set_vertical_scrollbar_position(slider_pos_y);
1297        ED4_scrollbar_change_cb(aww, 0, 0);
1298    }
1299}
1300
1301void ED4_cursor::set_to_terminal(AW_window *aww, ED4_terminal *terminal, int seq_pos, ED4_CursorJumpType jump_type)
1302{
1303    if (seq_pos == -1) seq_pos = get_sequence_pos();
1304
1305    if (owner_of_cursor == terminal) {
1306        jump_sequence_pos(aww, seq_pos, jump_type);
1307    }
1308    else {
1309        if (owner_of_cursor) {
1310            if (get_sequence_pos() != seq_pos) {
1311                jump_sequence_pos(aww, seq_pos, jump_type); // position to wanted column -- scrolls horizontally
1312            }
1313        }
1314
1315        int scr_pos = ED4_ROOT->root_group_man->remap()->sequence_to_screen_clipped(seq_pos);
1316        show_cursor_at(terminal, scr_pos);
1317
1318        if (!is_partly_visible()) {
1319#if defined(DEBUG) && 0
1320            printf("Cursor not visible in set_to_terminal (was drawn outside screen)\n");
1321#endif // DEBUG
1322            jump_sequence_pos(aww, seq_pos, jump_type);
1323        }
1324    }
1325
1326    GB_transaction ta(GLOBAL_gb_main);
1327    updateAwars();
1328}
1329
1330ED4_returncode ED4_cursor::show_cursor_at(ED4_terminal *target_terminal, ED4_index scr_pos)
1331{
1332    if (owner_of_cursor) {
1333        if (is_partly_visible()) {
1334            delete_cursor(cursor_abs_x, owner_of_cursor);
1335        }
1336
1337        owner_of_cursor->set_refresh(); // we have to refresh old owner of cursor
1338        owner_of_cursor->parent->refresh_requested_by_child();
1339        owner_of_cursor = NULL;
1340        ED4_ROOT->refresh_window(0);
1341        DRAW = 1;
1342    }
1343
1344    target_terminal->scroll_into_view(ED4_ROOT->get_aww());
1345
1346    AW_pos termw_x, termw_y;
1347    target_terminal->calc_world_coords( &termw_x, &termw_y );
1348
1349    screen_position = scr_pos;
1350
1351    int length_of_char = ED4_ROOT->font_group.get_width(ED4_G_SEQUENCES);
1352
1353    AW_pos world_x = termw_x + length_of_char*screen_position + CHARACTEROFFSET;
1354    AW_pos world_y = termw_y;
1355
1356    AW_pos win_x = world_x;
1357    AW_pos win_y = world_y;
1358    ED4_ROOT->world_to_win_coords(ED4_ROOT->get_aww(), &win_x, &win_y);
1359
1360    cursor_abs_x = (long int)world_x;
1361    owner_of_cursor = target_terminal;
1362
1363    draw_cursor(win_x, win_y);
1364
1365    GB_transaction gb_dummy(GLOBAL_gb_main);
1366    updateAwars();
1367
1368    return ED4_R_OK;
1369}
1370
1371ED4_returncode ED4_cursor::show_clicked_cursor(AW_pos click_xpos, ED4_terminal *target_terminal)
1372{
1373    AW_pos termw_x, termw_y;
1374    target_terminal->calc_world_coords( &termw_x, &termw_y );
1375
1376    ED4_index scr_pos = ED4_ROOT->pixel2pos(click_xpos - termw_x);
1377    return show_cursor_at(target_terminal, scr_pos);
1378}
1379
1380ED4_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)
1381{
1382    // current_y is y-position of terminal at which search starts.
1383    // It may be in world or screen coordinates (isScreen marks which is used)
1384    // This is needed to move the cursor from top- to middle-area w/o scrolling middle-area to top-position.
1385
1386    ED4_terminal *result = 0;
1387
1388    for (int i=0; i<starting_point->children->members(); i++) {
1389        ED4_base *member = starting_point->children->member(i);
1390
1391        AW_pos x, y;
1392        member->calc_world_coords( &x, &y );
1393
1394        switch (cursor_move) {
1395            case ED4_C_UP:
1396                e4_assert(!isScreen); // use screen coordinates for ED4_C_DOWN only!
1397
1398                if (y < current_y) {
1399                    if ((member->is_manager()) && !member->flag.hidden) {
1400                        ED4_terminal *result_in_manager = get_upper_lower_cursor_pos(member->to_manager(), cursor_move, current_y, isScreen, terminal_is_appropriate, seq_pos);
1401                        if (result_in_manager) result   = result_in_manager;
1402                    }
1403
1404                    if ((member->dynamic_prop & ED4_P_CURSOR_ALLOWED)) {
1405                        if (terminal_is_appropriate==0 || terminal_is_appropriate(member, seq_pos)) {
1406                            result = member->to_terminal(); // overwrite (i.e. take last matching terminal)
1407                        }
1408                    }
1409                }
1410                break;
1411
1412            case ED4_C_DOWN:
1413                if (!result) { // don't overwrite (i.e. take first matching terminal)
1414                    if ((member->is_manager()) && !member->flag.hidden) {
1415                        result = get_upper_lower_cursor_pos(member->to_manager(), cursor_move, current_y, isScreen, terminal_is_appropriate, seq_pos);
1416                    }
1417
1418                    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
1419
1420                    if ((member->dynamic_prop & ED4_P_CURSOR_ALLOWED) && y > current_y) {
1421                        ED4_multi_species_manager *marea_man = NULL; // probably multi_species_manager of middle_area, otherwise just a dummy
1422                        ED4_AREA_LEVEL level                 = member->get_area_level(&marea_man);
1423
1424                        if (level != ED4_A_MIDDLE_AREA) {
1425                            if (terminal_is_appropriate==0 || terminal_is_appropriate(member, seq_pos)) {
1426                                result = member->to_terminal();
1427                            }
1428                        }
1429                        else if (level == ED4_A_MIDDLE_AREA) {
1430                            AW_pos y_area = marea_man->parent->extension.position[Y_POS];
1431                            if (y > y_area) {
1432                                member = starting_point->children->member(i);
1433                                if (terminal_is_appropriate==0 || terminal_is_appropriate(member, seq_pos)) {
1434                                    result = member->to_terminal();
1435                                }
1436                            }
1437                        }
1438                    }
1439                }
1440                break;
1441
1442            default:
1443                e4_assert(0);
1444                break;
1445        }
1446    }
1447
1448    return result;
1449}
1450
1451/* --------------------------------------------------------------------------------
1452   ED4_base_position
1453   -------------------------------------------------------------------------------- */
1454
1455ED4_base_position::ED4_base_position()
1456    : calced4base(0)
1457    , seq_pos(0)
1458    , count(0)
1459{
1460}
1461
1462ED4_base_position::~ED4_base_position() {
1463    invalidate();
1464    delete [] seq_pos;
1465}
1466
1467static void ed4_bp_sequence_changed_cb(ED4_species_manager *, AW_CL cl_base_pos) {
1468    ED4_base_position *base_pos = (ED4_base_position*)cl_base_pos;
1469    base_pos->invalidate();
1470}
1471
1472void ED4_base_position::invalidate() {
1473    if (calced4base) {
1474        ED4_species_manager *species_manager = calced4base->get_parent(ED4_L_SPECIES)->to_species_manager();
1475        species_manager->remove_sequence_changed_cb(ed4_bp_sequence_changed_cb, (AW_CL)this);
1476
1477        calced4base = 0;
1478    }
1479}
1480
1481void ED4_base_position::calc4base(const ED4_base *base)
1482{
1483    e4_assert(base);
1484
1485    ED4_species_manager *species_manager = base->get_parent(ED4_L_SPECIES)->to_species_manager();
1486    int                  len;
1487    char                *seq;
1488
1489    if (calced4base) {
1490        ED4_species_manager *prev_species_manager = calced4base->get_parent(ED4_L_SPECIES)->to_species_manager();
1491        prev_species_manager->remove_sequence_changed_cb(ed4_bp_sequence_changed_cb, (AW_CL)this);
1492    }
1493
1494    species_manager->add_sequence_changed_cb(ed4_bp_sequence_changed_cb, (AW_CL)this);
1495
1496    if (species_manager->flag.is_consensus) {
1497        ED4_group_manager *group_manager = base->get_parent(ED4_L_GROUP)->to_group_manager();
1498
1499        seq = group_manager->table().build_consensus_string();
1500        len = strlen(seq);
1501    }
1502    else {
1503        seq = base->resolve_pointer_to_string_copy(&len);
1504    }
1505
1506    e4_assert(seq);
1507
1508    delete [] seq_pos;
1509    calced4base = base;
1510
1511    {
1512        int *pos = new int[len];
1513        int p;
1514
1515        count = 0;
1516        for (p=0; p<len; p++) {
1517            if (!ADPP_IS_ALIGN_CHARACTER(seq[p])) {
1518                pos[count++] = p;
1519            }
1520        }
1521
1522        if (count) {
1523            seq_pos = new int[count];
1524            for (p=0; p<count; p++) {
1525                seq_pos[p] = pos[p];
1526            }
1527        }
1528        else {
1529            seq_pos = 0;
1530        }
1531
1532        delete[] pos;
1533    }
1534
1535    free(seq);
1536}
1537int ED4_base_position::get_base_position(const ED4_base *base, int sequence_position)
1538{
1539    if (!base) return 0;
1540    if (base!=calced4base) calc4base(base);
1541
1542    if (count==0) return 0;
1543    if (sequence_position>seq_pos[count-1]) return count;
1544
1545    int h = count-1,
1546        l = 0;
1547
1548    while (1)
1549    {
1550        int m = (l+h)/2;
1551
1552        if (seq_pos[m]==sequence_position) {
1553            return m;
1554        }
1555        else {
1556            if (l==h) break;
1557
1558            if (sequence_position<seq_pos[m]) h = m;
1559            else                              l = m+1;
1560        }
1561    }
1562
1563    return l;
1564}
1565int ED4_base_position::get_sequence_position(const ED4_base *base, int base_pos)
1566{
1567    if (!base) return 0;
1568    if (base!=calced4base) calc4base(base);
1569    return base_pos<count ? seq_pos[base_pos] : seq_pos[count-1]+1;
1570}
1571
1572int ED4_get_base_position(const ED4_sequence_terminal *seq_term, int seq_position) {
1573    static ED4_base_position *base_pos = 0;
1574
1575    if (!base_pos) base_pos = new ED4_base_position;
1576    return base_pos->get_base_position(seq_term, seq_position);
1577}
1578
1579
1580/* --------------------------------------------------------------------------------
1581   Store/Restore Cursorpositions
1582   -------------------------------------------------------------------------------- */
1583
1584class CursorPos
1585{
1586    ED4_terminal *terminal;
1587    int seq_pos;
1588
1589    CursorPos *next;
1590
1591    static CursorPos *head;
1592
1593public:
1594
1595    static void clear()
1596    {
1597        while (head) {
1598            CursorPos *p = head->next;
1599
1600            delete head;
1601            head = p;
1602        }
1603    }
1604    static CursorPos *get_head() { return head; }
1605
1606    CursorPos(ED4_terminal *t, int p)
1607    {
1608        terminal = t;
1609        seq_pos = p;
1610        next = head;
1611        head = this;
1612    }
1613    ~CursorPos() {}
1614
1615    ED4_terminal *get_terminal() const { return terminal; }
1616    int get_seq_pos() const { return seq_pos; }
1617
1618    void moveToEnd()
1619    {
1620        e4_assert(this==head);
1621
1622        if (next) {
1623            CursorPos *p = head = next;
1624
1625            while (p->next) {
1626                p = p->next;
1627            }
1628
1629            p->next = this;
1630            this->next = 0;
1631        }
1632    }
1633};
1634
1635CursorPos *CursorPos::head = 0;
1636
1637void ED4_store_curpos(AW_window *aww, AW_CL /*cd1*/, AW_CL /*cd2*/)
1638{
1639    GB_transaction dummy(GLOBAL_gb_main);
1640    ED4_ROOT->use_window(aww);
1641    ED4_cursor *cursor = &ED4_ROOT->get_ed4w()->cursor;
1642    if (!cursor->owner_of_cursor) {
1643        aw_message("First you have to place the cursor.");
1644        return;
1645    }
1646
1647    new CursorPos(cursor->owner_of_cursor->to_terminal(), cursor->get_sequence_pos());
1648}
1649
1650void ED4_restore_curpos(AW_window *aww, AW_CL /*cd1*/, AW_CL /*cd2*/)
1651{
1652    GB_transaction dummy(GLOBAL_gb_main);
1653    ED4_ROOT->use_window(aww);
1654    ED4_cursor *cursor = &ED4_ROOT->get_ed4w()->cursor;
1655
1656    CursorPos *pos = CursorPos::get_head();
1657    if (!pos) {
1658        aw_message("No cursor position stored.");
1659        return;
1660    }
1661
1662    pos->get_terminal()->setCursorTo(cursor, pos->get_seq_pos(), true, ED4_JUMP_KEEP_VISIBLE);
1663    pos->moveToEnd();
1664}
1665
1666void ED4_clear_stored_curpos(AW_window */*aww*/, AW_CL /*cd1*/, AW_CL /*cd2*/)
1667{
1668    CursorPos::clear();
1669}
1670
1671/* --------------------------------------------------------------------------------
1672   Other stuff
1673   -------------------------------------------------------------------------------- */
1674
1675void ED4_helix_jump_opposite(AW_window *aww, AW_CL /*cd1*/, AW_CL /*cd2*/)
1676{
1677    GB_transaction  dummy(GLOBAL_gb_main);
1678    ED4_ROOT->use_window(aww);
1679    ED4_cursor     *cursor = &ED4_ROOT->get_ed4w()->cursor;
1680
1681    if (!cursor->owner_of_cursor) {
1682        aw_message("First you have to place the cursor.");
1683        return;
1684    }
1685
1686    int           seq_pos  = cursor->get_sequence_pos();
1687    AW_helix     *helix    = ED4_ROOT->helix;
1688    BI_PAIR_TYPE  pairType = helix->pairtype(seq_pos);
1689
1690    if (pairType != HELIX_NONE) {
1691        int pairing_pos = helix->opposite_position(seq_pos);
1692        cursor->jump_sequence_pos(aww, pairing_pos, ED4_JUMP_KEEP_POSITION);
1693    }
1694    else {
1695        aw_message("Not at helix position");
1696    }
1697}
1698
1699void ED4_change_cursor(AW_window */*aww*/, AW_CL /*cd1*/, AW_CL /*cd2*/) {
1700    ED4_cursor *cursor = &ED4_ROOT->get_ed4w()->cursor;
1701    ED4_CursorType typ = cursor->getType();
1702
1703    cursor->changeType((ED4_CursorType)((typ+1)%ED4_CURSOR_TYPES));
1704}
Note: See TracBrowser for help on using the repository browser.