/* $Id: seqpanel.c,v 6.230 2011/07/19 18:40:47 bollin Exp $ * =========================================================================== * * PUBLIC DOMAIN NOTICE * National Center for Biotechnology Information (NCBI) * * This software/database is a "United States Government Work" under the * terms of the United States Copyright Act. It was written as part of * the author's official duties as a United States Government employee and * thus cannot be copyrighted. This software/database is freely available * to the public for use. The National Library of Medicine and the U.S. * Government do not place any restriction on its use or reproduction. * We would, however, appreciate having the NCBI and the author cited in * any work or product based on this material * * Although all reasonable efforts have been taken to ensure the accuracy * and reliability of the software and data, the NLM and the U.S. * Government do not and cannot warrant the performance or results that * may be obtained by using this software or data. The NLM and the U.S. * Government disclaim all warranties, express or implied, including * warranties of performance, merchantability or fitness for any particular * purpose. * * =========================================================================== * * Author: Vlad Lebedev * * Comment: A single implementation for sequence and alignment viewers based * on feature indexing and Alignment Manager. * ========================================================================== */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include enum ESeqNum { eNumNone=1, eNumSide=2, eNumTop=3 }; enum EDrawGrid { eDrawGridOn=1, eDrawGridOff=2 }; enum EShowFeatures { eShowFeaturesOn=1, eShowFeaturesOff=2, eShowFeaturesAll=3 }; enum ELineType { eTypeTopSeqNumbers, eTypeTopScaleMarks, eTypeSequence, eTypeAlignSequence, eTypeFeature, eTypeAlignDivider, eTypeFrame1, eTypeFrame2, eTypeFrame3, eTypeFrame4, eTypeFrame5, eTypeFrame6, eTypeSequenceComplement }; #define GRID_LINE_SPACE 6 #define NO_GRID_LINE_SPACE 2 #define SEQ_GROUP_SIZE 10 /* Sequence group size */ #define SEQ_X_OFFSET 4 #define SEQ_Y_OFFSET 4 #define ROW_UNDEFINED -1 #define PROT_PRODUCT_TYPE 255 #define PROT_ON_THE_FLY 254 #define GAP_CHAR '.' static Uint1 FillRectangleSym [] = { 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0x00 }; static Uint1 FillLeftArrowSym [] = { 0x06, 0x1E, 0x7E, 0xFE, 0x7E, 0x1E, 0x06, 0x00 }; static Uint1 FillRightArrowSym[] = { 0xC0, 0xF0, 0xFC, 0xFE, 0xFC, 0xF0, 0xC0, 0x00 }; typedef struct seqParag { ValNodePtr PNTR pFeatList; /* pointer to an array of lists of feature indexes */ } SeqParaG, PNTR SeqParaGPtr; /* struct that holds data for SeqEditor window */ typedef struct seqedformdata { FORM_MESSAGE_BLOCK BioseqViewFormPtr bfp; GrouP upper_button_group; ButtoN goto_btn; TexT goto_txt; ButtoN lookat_btn; TexT lookat_txt; PrompT position_label; GrouP lower_button_group; ButtoN accept; ButtoN cancel; IteM frames[10]; IteM undo_menu; IteM redo_menu; Boolean spliteditmode; /* This flag indicates whether new nucleotides * entered into the sequence will become part of * a feature or will introduce an exon into the * location of the features containing this span. */ Int4 edit_pos_start; Int4 edit_pos_end; Int4 edit_pos_orig; Uint2 moltype; SeqEdJournalPtr undo_list; /* This is a list of journal entries used for * undo and redo. */ SeqEdJournalPtr last_journal_entry; /* This entry points to the last action taken - * undo should unplay starting with this entry, * redo should start playing beginning with * last_journal_entry->next. * This should never, ever be NULL, as undo_list * contains start and end journal entries. */ BioseqPtr orig_bsp; CharPtr current_pattern; /* This holds the most recently selected pattern * from the Find dialog. */ Boolean current_pattern_revcomp;/* This indicates whether the most recent search * in the Find dialog was a reverse-complement * search. */ Boolean current_pattern_translate; /*This indicates whether the most recent search * in the Find dialog was a translation search. */ Int4 current_pattern_translate_frame_choice; /* This indicates the frame * for the translated search for the most recent * search in the Find dialog. */ Boolean current_pattern_exact_match; /* This indicates whether the most recent search * in the Find dialog was an exact match or an * ambiguous match. */ ValNodePtr match_list; /* This holds a list of SeqLocs that contain * current_pattern. */ SeqFeatPtr feature_to_drag; /* This points to the last feature to receive a * single click, in preparation for dragging the * end. */ SeqLocPtr feature_orig_loc; /* This indicates the original position of the * feature whose end is being dragged. */ EMoveType feature_drag_type; /* This indicates whether we are dragging the * left end, dragging the right end, or sliding * the entire interval. */ Int4 feature_drag_origin; Int4 feature_drag_interval; /* integer offset of interval to edit */ Int4 last_drag_change; /* amount of change for last drag command - * we only want to resize the window if * we have pulled a feature interval onto or off * of a new line. */ ValNodePtr gapvnp; /* used for indexing gap features */ WindoW find_window; /* This is the window used for finding text * in the sequence. It must be removed if the * SequenceEditor window is closed. */ MenU aln_target_menu; /* This is used by the alignment editor to * change the target. */ SeqAnnotPtr annot; /* This is the annotation that should point * to our alignment. If it does not, the * alignment has been replaced. */ ValNodePtr locked_aln_bioseqs; /* This is the list of far Bioseqs that are * locked when the alignment panel is created * using LockFarAlignmentBioseqs and unlocked * when the alignment panel is removed using * UnlockFarComponents. */ Nlm_ChangeNotifyProc on_close_func; /* This is called when the window is being closed. */ Pointer on_close_data; /* Argument for on_close_func */ } SeqEdFormData, PNTR SeqEdFormPtr; typedef struct seqpanpara { Int4 sequenceLineOffset; /* This indicates the position of the line of * sequence data described by the paragraph. */ Boolean indexed; /* This flag indicates whether the paragraph has * been indexed or not. */ SeqPanLinePtr PNTR lines; /* If the paragraph has been indexed, lines will * point to an array of pointers to SeqPanLinePtr * with the lines for this paragraph. Otherwise * lines should be NULL. */ Int4 num_lines; /* If the paragraph has been indexed, num_lines * will indicate the size of the array in lines. * Otherwise num_lines should be zero. */ } SeqPanParaData, PNTR SeqPanParaPtr; /* This is the number of paragraphs to be allocated per chapter. */ #define SEQ_PAN_CHAPTER_SIZE 50 static Boolean PlayJournal (SeqEdJournalPtr list, SeqEdJournalPtr PNTR last, Int4 num_steps, BoolPtr pfeats_deleted, SeqEdFormPtr sefp); static Boolean UnplayJournal (SeqEdJournalPtr PNTR last, Int4 num_steps, SeqEdFormPtr sefp); static BioseqViewPtr GetBioseqViewPtr(PaneL p) { return &((BioseqViewFormPtr) GetObjectExtra (p))->bvd; } static void FreeSeqPanelLines(SeqPanLinePtr PNTR splp, BioseqViewPtr bvp) { Int4 i; for (i = 0; i < bvp->TotalLines; i++) MemFree(splp[i]); MemFree (splp); } static SeqPanLinePtr MakeSeqPanLine(Int2 type, Int4 line) { SeqPanLinePtr plp = (SeqPanLinePtr)MemNew(sizeof(SeqPanLine)); plp->lineType = type; plp->bioSeqLine = line; plp->on_the_fly = FALSE; return plp; } static void ShowSeqView (BioseqViewPtr bvp, Boolean show) { Int2 val = GetValue(bvp->newFeatControl); show ? SafeShow (bvp->seqView ) : SafeHide (bvp->seqView ); show ? SafeShow (bvp->seqViewParentGrp) : SafeHide (bvp->seqViewParentGrp); show ? SafeShow (bvp->clickMe ) : SafeHide (bvp->clickMe ); SafeHide (bvp->styleControlGrp); SafeHide (bvp->scaleControlGrp); SafeHide (bvp->findGeneGrp ); SafeHide (bvp->newFeatControl); Reset(bvp->newFeatControl); if (bvp->seqAlignMode) { PopupItem (bvp->newFeatControl, "Target"); PopupItem (bvp->newFeatControl, "Off"); PopupItem (bvp->newFeatControl, "Aligned"); } else { PopupItem (bvp->newFeatControl, "Target"); PopupItem (bvp->newFeatControl, "Off"); if (val == eShowFeaturesAll) val = eShowFeaturesOn; } SetValue (bvp->newFeatControl, val); SafeShow (bvp->newFeatControl); } static Boolean isSelected(Uint2 entityID, Uint4 itemID, Int2 itemtype, BioseqViewPtr bvp) { SelStructPtr sel; if (bvp->salp == NULL) { if (bvp->bsp != NULL) { for (sel = bvp->sel_list; sel != NULL; sel = sel->next) { if (sel->itemID == itemID && sel->itemtype == itemtype && sel->entityID == entityID) { return TRUE; } } } } else { sel = ObjMgrGetSelected (); while (sel != NULL) { if (sel->entityID == entityID && sel->itemtype == itemtype && sel->itemID == itemID) { return TRUE; } sel = sel->next; } if (entityID == 0) { for (sel = bvp->sel_list; sel != NULL; sel = sel->next) { if (sel->itemID == itemID && sel->itemtype == itemtype && sel->entityID == entityID) { return TRUE; } } } } return FALSE; } static SelStructPtr SelStructListFree (SelStructPtr sel) { if (sel == NULL) { return NULL; } sel->next = SelStructListFree (sel->next); sel = MemFree (sel); return sel; } static void SeqEdSelectFeature (BioseqViewPtr bvp, Int4 idx) { if (bvp == NULL) return; if (bvp->bsp == NULL && bvp->salp == NULL) return; if (bvp->salp != NULL) { ObjMgrDeSelectAll (); ObjMgrSelect (bvp->salp->idx.entityID, idx, OBJ_SEQFEAT, 0, NULL); } else if (bvp->bsp != NULL) { bvp->sel_list = SelStructListFree (bvp->sel_list); bvp->sel_list = SelStructNew (bvp->bsp->idx.entityID, idx, OBJ_SEQFEAT, 0, 0, NULL, 0, FALSE); } } static void SelectSeqView (BioseqViewPtr bvp, Uint2 selentityID, Uint4 selitemID, Uint2 selitemtype, SeqLocPtr region, Boolean select, Boolean scrollto) { RecT r_redraw; if (selitemtype != OBJ_SEQFEAT) return; SeqEdSelectFeature (bvp, selitemID); UseWindow (ParentWindow(bvp->seqView)); ObjectRect (bvp->seqView, &r_redraw); InvalRect (&r_redraw); } static Int4 x_Coord(BioseqViewPtr bvp, Int4 pos, Int4 row) { if (bvp->seqAlignMode) { Int4 tmp = AlnMgr2MapBioseqToSeqAlign(bvp->salp, pos, row); return tmp; } else return pos; } static Int4 GetAlnRowForBsp (BioseqPtr bsp, SeqAlignPtr salp) { Int4 aln_row; SeqIdPtr sip; if (bsp == NULL || salp == NULL) { return 0; } for (aln_row = 1; aln_row <= salp->dim; aln_row++) { sip = AlnMgr2GetNthSeqIdPtr(salp, aln_row); if (SeqIdIn (sip, bsp->id)) { return aln_row; } } return 0; } static Int4 x_FeatLeft(BioseqViewPtr bvp, Int4 fpos, Int4 row) /* trim feature to fit alignment */ { Int4 start = 0, stop; if (bvp->seqAlignMode) { if (row > 0) { AlnMgr2GetNthSeqRangeInSA(bvp->salp, row, &start, &stop); } return MAX(start, fpos); } else return fpos; } static Int4 x_FeatRight(BioseqViewPtr bvp, Int4 fpos, Int4 row) /* trim feature to fit alignment */ { Int4 start, stop = 0; if (bvp->seqAlignMode) { AlnMgr2GetNthSeqRangeInSA(bvp->salp, row, &start, &stop); return MIN(stop, fpos); } else return fpos; } static void FillFeatureInfo(BioseqViewPtr bvp, BioseqPtr bsp, Int2 lineLength, Int4 pCount, Int4 row, Int4 idx, SeqParaGPtr PNTR ref) { Int4 j, start, stop; SeqMgrFeatContext fcontext; SeqFeatPtr sfp = SeqMgrGetNextFeature (bsp, NULL, 0, 0, &fcontext); Int4 aln_row = -1; Uint2 aln_strand = Seq_strand_plus; Int4 paraFrom; /* feature starting paragraph */ Int4 paraTo; /* feature ending paragraph */ if (bvp == NULL || bsp == NULL) { return; } if (bvp->seqAlignMode) { aln_row = GetAlnRowForBsp (bsp, bvp->salp); aln_strand = AlnMgr2GetNthStrand (bvp->salp, aln_row); } while (sfp != NULL) { if (fcontext.seqfeattype != SEQFEAT_PUB && fcontext.seqfeattype != SEQFEAT_BIOSRC && (fcontext.left != fcontext.right)) { Boolean coding = fcontext.seqfeattype == SEQFEAT_CDREGION; Int4 fLeft = x_FeatLeft (bvp, fcontext.left, aln_row); Int4 fRight = x_FeatRight(bvp, fcontext.right, aln_row); if (fLeft < 0) fLeft = 0; if (aln_strand == Seq_strand_minus) { /* if the alignment strand is reversed, the left and right endpoints will be * reversed during mapping */ paraFrom = floor(x_Coord(bvp, fRight, row) / lineLength); paraTo = ceil (x_Coord(bvp, fLeft, row) / lineLength) + 1; } else { paraFrom = floor(x_Coord(bvp, fLeft, row) / lineLength); paraTo = ceil (x_Coord(bvp, fRight, row) / lineLength) + 1; } /*BioseqPtr bsp_prot = BioseqFind (SeqLocId(sfp->product));*/ start = SeqLocStart (sfp->location); stop = SeqLocStop (sfp->location); for (j = paraFrom; j != paraTo && j < pCount; j++) { ValNodeAddInt(&ref[j]->pFeatList[idx], fcontext.seqfeattype, fcontext.itemID); if (coding) ValNodeAddInt(&ref[j]->pFeatList[idx], PROT_PRODUCT_TYPE, fcontext.itemID); /* add space for prot product */ } } sfp = SeqMgrGetNextFeature (bsp, sfp, 0, 0, &fcontext); } /* while */ } static void MakeFeatureLine(Int4Ptr lCount, Int4 para, Int4 row, Int4 idx, SeqParaGPtr PNTR ref, SeqPanLinePtr PNTR splp) { ValNodePtr vnp; for (vnp = ref[para]->pFeatList[idx]; vnp != NULL; vnp = vnp->next) { SeqPanLinePtr plp = MakeSeqPanLine(eTypeFeature, para); plp->idx = vnp->data.intvalue; plp->protProduct = vnp->choice==PROT_PRODUCT_TYPE ? TRUE : FALSE; plp->row = row; splp[*lCount] = plp; (*lCount)++; } } static BioseqPtr LockNthBioseqInAlignment(SeqAlignPtr salp, Int4 seq_num) { SeqIdPtr tmp_sip; SeqEntryPtr oldscope, aln_scope; BioseqPtr bsp; if (salp == NULL || seq_num < 1) return NULL; tmp_sip = AlnMgr2GetNthSeqIdPtr(salp, seq_num); aln_scope = GetTopSeqEntryForEntityID (salp->idx.entityID); oldscope = SeqEntrySetScope (aln_scope); bsp = BioseqLockById (tmp_sip); if (bsp == NULL) { SeqEntrySetScope (NULL); bsp = BioseqLockById (tmp_sip); } SeqEntrySetScope (oldscope); tmp_sip = SeqIdFree (tmp_sip); return bsp; } static BioseqPtr PNTR PNTR GetAlignmentBioseqLists (SeqAlignPtr salp) { Int4 num_alignments = 0, aln_num, alnRows, seq_num; BioseqPtr PNTR PNTR bioseqs_for_each_aln = NULL; BioseqPtr PNTR bioseqs_for_aln; SeqAlignPtr tmp_salp; if (salp == NULL) { return NULL; } num_alignments = 0; for (tmp_salp = salp; tmp_salp != NULL; tmp_salp = tmp_salp->next) { num_alignments ++; } bioseqs_for_each_aln = (BioseqPtr PNTR PNTR) MemNew (sizeof (BioseqPtr PNTR) * num_alignments); if (bioseqs_for_each_aln != NULL) { for (aln_num = 0, tmp_salp = salp; aln_num < num_alignments && tmp_salp != NULL; aln_num++, tmp_salp = tmp_salp->next) { alnRows = AlnMgr2GetNumRows(tmp_salp); /* size of the alignment */ bioseqs_for_aln = (BioseqPtr PNTR) MemNew (sizeof (BioseqPtr) * alnRows); bioseqs_for_each_aln [aln_num] = bioseqs_for_aln; if (bioseqs_for_aln != NULL) { for (seq_num = 1; seq_num < alnRows + 1; seq_num++) { bioseqs_for_aln[seq_num - 1] = LockNthBioseqInAlignment(tmp_salp, seq_num); } } } } return bioseqs_for_each_aln; } static BioseqPtr PNTR PNTR FreeAlignmentBioseqLists (BioseqPtr PNTR PNTR bioseqs_for_each_aln, SeqAlignPtr salp) { Int4 aln_num = 0, alnRows, seq_num; BioseqPtr PNTR bioseqs_for_aln; if (bioseqs_for_each_aln != NULL) { while (salp != NULL) { alnRows = AlnMgr2GetNumRows (salp); /* size of the alignment */ bioseqs_for_aln = (BioseqPtr PNTR) bioseqs_for_each_aln [aln_num]; if (bioseqs_for_aln != NULL) { for (seq_num = 0; seq_num < alnRows; seq_num++) { BioseqUnlock(bioseqs_for_aln[seq_num]); bioseqs_for_aln [seq_num] = NULL; } bioseqs_for_each_aln [aln_num] = MemFree (bioseqs_for_each_aln [aln_num]); } salp = salp->next; aln_num++; } bioseqs_for_each_aln = MemFree (bioseqs_for_each_aln); } return bioseqs_for_each_aln; } static SeqPanLinePtr PNTR CreateSeqPanelLines(Int2 lineLength, BioseqViewPtr bvp) { BioseqPtr bsp = bvp->bsp; SeqParaGPtr PNTR ref; SeqPanLinePtr PNTR splp; Int2 fLines; Int4 lCount = 0, i, j; Int4 pCount; /* Total number of paragraphs */ Int4 alnRows = -1; Int4Ptr alnValidRows = NULL; Int4 featRows = 1; SeqAlignPtr tmp_salp; Int4Ptr lines_per_alignment = NULL; Int4 num_alignments; Int4 aln_idx; SeqParaGPtr PNTR ref_offset; BioseqPtr PNTR bioseqs_for_aln; /* store array of bioseqs for alignment * here while generating features, * so that we don't have to fetch * far pointers over and over again */ BioseqPtr PNTR PNTR bioseqs_for_each_aln = NULL; Int4 para_num; if (bvp->seqAlignMode) { /* if this is in alignment mode, get the list of sequences for each * alignment so that we don't have to refetch the farpointer sequences */ bioseqs_for_each_aln = GetAlignmentBioseqLists (bvp->salp); alnRows = AlnMgr2GetNumRows(bvp->salp); /* size of the alignment */ fLines = GetValue(bvp->newNumControl) == eNumTop ? 2 : 0; pCount = 0; num_alignments = 0; for (tmp_salp = bvp->salp; tmp_salp != NULL; tmp_salp = tmp_salp->next) { num_alignments ++; } lines_per_alignment = (Int4Ptr) MemNew (sizeof (Int4) * num_alignments); if (lines_per_alignment == NULL) return NULL; alnValidRows = (Int4Ptr) MemNew (sizeof (Int4) * num_alignments); if (alnValidRows == NULL) { MemFree (lines_per_alignment); return NULL; } for (i=0; i < num_alignments; i++) { lines_per_alignment [i] = 0; alnValidRows [i] = 0; } for (tmp_salp = bvp->salp, aln_idx = 0; tmp_salp != NULL; tmp_salp = tmp_salp->next, aln_idx++) { lines_per_alignment [aln_idx] = floor((AlnMgr2GetAlnLength(tmp_salp, FALSE)-1) / lineLength) + 1; /* alignment length */ pCount += lines_per_alignment [aln_idx]; if (bvp->viewWholeEntity || GetValue(bvp->newFeatControl) == eShowFeaturesAll) { if (featRows == 1) featRows = alnRows; else featRows += alnRows; } /* show features for all rows */ bioseqs_for_aln = bioseqs_for_each_aln [aln_idx]; if (bioseqs_for_aln != NULL) { for (j = 0; j < alnRows; j++) { if (bioseqs_for_aln [j] != NULL) { alnValidRows [aln_idx]++; } } } } } else { fLines = GetValue(bvp->newNumControl) == eNumTop ? 3 : 1; pCount = floor(bsp->length / lineLength) + 1; /* sequence length */ } ref = (SeqParaGPtr*) MemNew( (size_t)(sizeof(SeqParaGPtr)*pCount) ); for (i = 0; i < pCount; i++) { ref[i] = (SeqParaGPtr) MemNew(sizeof(SeqParaG)); ref[i]->pFeatList = (ValNodePtr*) MemNew( (size_t)(sizeof(ValNodePtr)*featRows) ); } ref_offset = ref; if (GetValue(bvp->newFeatControl) != eShowFeaturesOff) { if (bvp->seqAlignMode) { /* in alignment mode */ for (tmp_salp = bvp->salp, aln_idx = 0; tmp_salp != NULL; tmp_salp = tmp_salp->next, aln_idx ++) { bioseqs_for_aln = bioseqs_for_each_aln [aln_idx]; if (bioseqs_for_aln != NULL) { for (i = 1; i != alnRows + 1; i++) { BioseqPtr bsp_tmp = bioseqs_for_aln [i - 1]; if (bsp_tmp != NULL) { /* TODO: Need to calculate better values for passing to FillFeatureInfo */ if (bvp->viewWholeEntity || GetValue(bvp->newFeatControl) == eShowFeaturesAll) { FillFeatureInfo(bvp, bsp_tmp, lineLength, lines_per_alignment [aln_idx], i, i - 1, ref_offset); /* show features for each seq in alignment */ } else if (i == bvp->TargetRow) { FillFeatureInfo(bvp, bsp_tmp, lineLength, lines_per_alignment [aln_idx], i, 0, ref_offset); /* show features for target seq in alignment */ } } /* bsp_tmp != NULL */ } } /* for */ ref_offset += lines_per_alignment [aln_idx]; } } else { FillFeatureInfo(bvp, bsp, lineLength, pCount, 0, 0, ref); } } /* done with features */ bvp->TotalLines = 0; /* go through all pararaphs and count total */ if (bvp->seqAlignMode) { para_num = 0; for (tmp_salp = bvp->salp, aln_idx = 0; tmp_salp != NULL; tmp_salp = tmp_salp->next, aln_idx ++) { /* add lines for features */ for (i = 0; i < lines_per_alignment [aln_idx]; i++) { Int4 sub_total = 0; for (j = 0; j < featRows; j++) { sub_total += ValNodeLen(ref[i + para_num]->pFeatList[j]); } bvp->TotalLines += fLines + sub_total + (alnRows == -1 ? 0 : alnValidRows[aln_idx]); /* reserve space for alignment */ } /* add one more for divider */ if (tmp_salp->next != NULL) bvp->TotalLines ++; para_num += lines_per_alignment [aln_idx]; } } else { /* add lines for features */ for (i = 0; i < pCount; i++) { Int4 sub_total = 0; for (j = 0; j < featRows; j++) sub_total += ValNodeLen(ref[i]->pFeatList[j]); bvp->TotalLines += fLines + sub_total; } /* add lines for frames */ for (i = 0; i < 6; i++) { if (bvp->frames[i]) { bvp->TotalLines += pCount; } } /* add lines for complements */ if (bvp->ShowComplement) { bvp->TotalLines += pCount; } } splp = (SeqPanLinePtr*) MemNew( (size_t)(sizeof(SeqPanLinePtr)*bvp->TotalLines) ); if (bvp->seqAlignMode) { ref_offset = ref; for (tmp_salp = bvp->salp, aln_idx = 0; tmp_salp != NULL; tmp_salp = tmp_salp->next, aln_idx ++) { bioseqs_for_aln = bioseqs_for_each_aln [aln_idx]; if (bioseqs_for_aln != NULL) { for (i = 0; i < lines_per_alignment [aln_idx]; i++) { if (fLines > 1) { /* Numbers on top */ splp[lCount++] = MakeSeqPanLine(eTypeTopSeqNumbers, i); splp[lCount++] = MakeSeqPanLine(eTypeTopScaleMarks, i); } for (j = 1; j != alnRows + 1; j++) { /* AlnMgr counts from 1, not 0 */ BioseqPtr tmp_bsp = bioseqs_for_aln [j - 1]; if (tmp_bsp != NULL) { SeqPanLinePtr plp = MakeSeqPanLine(eTypeAlignSequence, i); /* Add align sequence line*/ plp->row = j; /* Index position in the alignment (row) */ splp[lCount++] = plp; if (bvp->viewWholeEntity || GetValue(bvp->newFeatControl) == eShowFeaturesAll) { MakeFeatureLine(&lCount, i, j, j - 1, ref_offset, splp); /* Add feature line */ } else if (j == bvp->TargetRow) { MakeFeatureLine(&lCount, i, j, 0, ref_offset, splp); } } } } /* add divider line between alignments */ if (tmp_salp->next != NULL) { splp[lCount++] = MakeSeqPanLine (eTypeAlignDivider, i); } ref_offset += lines_per_alignment [aln_idx]; } } } else { for (i = 0; i < pCount; i++) { if (fLines > 1) { /* Numbers on top */ splp[lCount++] = MakeSeqPanLine(eTypeTopSeqNumbers, i); splp[lCount++] = MakeSeqPanLine(eTypeTopScaleMarks, i); } splp[lCount++] = MakeSeqPanLine(eTypeSequence, i); /* Add sequence line */ if (bvp->ShowComplement) { splp[lCount++] = MakeSeqPanLine (eTypeSequenceComplement, i); } MakeFeatureLine(&lCount, i, 0, 0, ref, splp); /* Add feature line */ if (bvp->frames [0]) splp[lCount++] = MakeSeqPanLine (eTypeFrame1, i); if (bvp->frames [1]) splp[lCount++] = MakeSeqPanLine (eTypeFrame2, i); if (bvp->frames [2]) splp[lCount++] = MakeSeqPanLine (eTypeFrame3, i); if (bvp->frames [3]) splp[lCount++] = MakeSeqPanLine (eTypeFrame4, i); if (bvp->frames [4]) splp[lCount++] = MakeSeqPanLine (eTypeFrame5, i); if (bvp->frames [5]) splp[lCount++] = MakeSeqPanLine (eTypeFrame6, i); } }/* bvp->seqAlignMode */ for (i = 0; i < pCount; i++) { for (j = 0; j < featRows; j++) ValNodeFree (ref[i]->pFeatList[j]); MemFree (ref[i]->pFeatList); MemFree (ref[i]); } MemFree (ref); MemFree (lines_per_alignment); MemFree (alnValidRows); bioseqs_for_each_aln = FreeAlignmentBioseqLists (bioseqs_for_each_aln, bvp->salp); return splp; } static void onSeqViewClick (PaneL p, PoinT pt) { BioseqViewPtr bvp; bvp = GetBioseqViewPtr (p); bvp->wasDoubleClick = dblClick; bvp->wasShiftKey = shftKey; bvp->old_rect_shown = FALSE; bvp->pnt_start = pt; bvp->pnt_stop = pt; } static void onSeqViewRelease (PaneL p, PoinT pt) { RecT r; BaR sb; BioseqPtr bsp; BioseqViewPtr bvp; SeqPanLinePtr splp; Int4 line; Uint2 entityID = 0; Uint4 itemID = 0; Uint2 itemtype = 0; SeqEntryPtr sep; bvp = GetBioseqViewPtr (p); bsp = bvp->bsp; sb = GetSlateVScrollBar ((SlatE)bvp->seqView); ObjectRect (bvp->seqView, &r); InsetRect (&r, 4, 4); line = (pt.y-r.top-SEQ_Y_OFFSET) / bvp->LineHeight + GetBarValue(sb); if(line >= bvp->TotalLines) return; splp = bvp->SeqPanLines[line]; switch (splp->lineType) { case eTypeSequence: /* printf("Sequence from %d to %d\n", splp->bioSeqLine*bvp->CharsAtLine+1, splp->bioSeqLine*bvp->CharsAtLine+bvp->CharsAtLine); */ break; case eTypeFeature: /* if (splp->protProduct) printf("Prot. product: %d\n", splp->idx); else printf("Feature. Index: %d\n", splp->idx); */ if (splp->protProduct) { /* just get CDS feature from protein product */ entityID = ObjMgrGetEntityIDForPointer (bsp); itemID = splp->idx; itemtype = OBJ_SEQFEAT; } else { entityID = ObjMgrGetEntityIDForPointer (bsp); itemID = splp->idx; itemtype = OBJ_SEQFEAT; } break; } if (itemID < 1) { if (! bvp->wasShiftKey) { ObjMgrDeSelect (0, 0, 0, 0, NULL); } return; } if (bvp->wasDoubleClick) { if (bvp->sendSelectMessages) { if (bvp->wasShiftKey) { ObjMgrAlsoSelect (entityID, itemID, itemtype, 0, NULL); } else { ObjMgrSelect (entityID, itemID, itemtype, 0, NULL); } } sep = GetTopSeqEntryForEntityID (entityID); if (bvp->launchSubviewers) { WatchCursor (); Update (); LaunchNewBioseqViewer (bvp->bsp, entityID, itemID, itemtype); ArrowCursor (); Update (); return; } else if (LaunchViewerNotEditor (bvp, sep, entityID, itemID, itemtype)) { WatchCursor (); Update (); LaunchNewBioseqViewer (bvp->bsp, entityID, itemID, itemtype); ArrowCursor (); Update (); return; } else if (bvp->launchEditors) { WatchCursor (); Update (); GatherProcLaunch (OMPROC_EDIT, FALSE, entityID, itemID, itemtype, 0, 0, itemtype, 0); ArrowCursor (); Update (); return; } else { return; } } else if (bvp->sendSelectMessages) { if (bvp->wasShiftKey) { ObjMgrAlsoSelect (entityID, itemID, itemtype, 0, NULL); } else { ObjMgrSelect (entityID, itemID, itemtype, 0, NULL); } } } static void ResizeSeqView (BioseqViewPtr bvp) { RecT r; Int4 height, width; BaR sb = GetSlateVScrollBar ((SlatE)bvp->seqView); Int4 bar_max; ObjectRect (bvp->seqView, &r); InsetRect (&r, 4, 4); width = r.right - r.left; height = r.bottom - r.top - 3 * SEQ_Y_OFFSET; bvp->BlocksAtLine = (width - SEQ_X_OFFSET - bvp->SeqStartPosX) / ((SEQ_GROUP_SIZE + 1) * bvp->CharWidth); if (bvp->BlocksAtLine == 0) bvp->BlocksAtLine = 1; /* Always at least 1 block */ bvp->CharsAtLine = SEQ_GROUP_SIZE * bvp->BlocksAtLine; if (bvp->SeqPanLines) { FreeSeqPanelLines (bvp->SeqPanLines, bvp); bvp->SeqPanLines = NULL; } bvp->SeqPanLines = CreateSeqPanelLines (bvp->CharsAtLine, bvp); bar_max = bvp->TotalLines - height / bvp->LineHeight; /* If height is evenly divisible by bvp->LineHeight, bar_max is too small */ if (height % bvp->LineHeight == 0) { bar_max ++; } SetBarMax (sb, bar_max); CorrectBarPage(sb, (height / bvp->LineHeight) - 1, (height / bvp->LineHeight) - 1); SetPanelClick(bvp->seqView, onSeqViewClick, NULL, NULL, onSeqViewRelease); } static void PopulateSeqAlnView (BioseqViewPtr bvp) { RecT r; SelectFont ((FonT)(bvp->displayFont)); bvp->DrawGrid = GetValue (bvp->newGridControl) == eDrawGridOn; bvp->LineSpace = bvp->DrawGrid ? GRID_LINE_SPACE-1 : NO_GRID_LINE_SPACE; bvp->CharHeight = FontHeight (); bvp->CharWidth = CharWidth ('A'); bvp->LineHeight = bvp->CharHeight + bvp->LineSpace; CorrectBarValue (GetSlateVScrollBar ((SlatE)bvp->seqView), 0); ResizeSeqView (bvp); Select (bvp->seqView); ObjectRect (bvp->seqView, &r); InsetRect (&r, 2, 2); InvalRect (&r); SetPanelClick(bvp->seqView, onSeqViewClick, NULL, NULL, onSeqViewRelease); } static void PopulateSeqView (BioseqViewPtr bvp) { bvp->seqAlignMode = FALSE; bvp->SeqStartPosX = 100; PopulateSeqAlnView(bvp); } static void PopulateAlnView (BioseqViewPtr bvp) { SeqIdPtr sip = bvp->bsp->id; SeqIdPtr tmpsip; SeqLocPtr slp; bvp->seqAlignMode = TRUE; bvp->SeqStartPosX = 150; /* if we're switching between segments we might need to load a * different alignment */ if (bvp->salp != NULL) { if ((bvp->bsp->repr != Seq_repr_seg && bvp->salp->next != NULL) || (bvp->TargetRow = AlnMgr2GetFirstNForSip (bvp->salp, sip)) == -1) { bvp->salp = SeqAlignFree (bvp->salp); } else { PopulateSeqAlnView(bvp); return; } } if (bvp->salp == NULL && bvp->seqAlignMode) { /* Try to find an alignment */ bvp->salp = FindAlignmentsForBioseq (bvp->bsp); if (bvp->salp == NULL) { /* No alignment found or bug in AlignMgr (which is more likely). Switch to sequence mode */ PopulateSeqView(bvp); return; } } bvp->TargetRow = ROW_UNDEFINED; if (bvp->bsp->repr == Seq_repr_seg) { slp = (SeqLocPtr) bvp->bsp->seq_ext; while (slp != NULL && bvp->TargetRow == ROW_UNDEFINED) { tmpsip = SeqLocId (slp); while (tmpsip && bvp->TargetRow == ROW_UNDEFINED) { bvp->TargetRow = AlnMgr2GetFirstNForSip(bvp->salp, tmpsip); tmpsip = tmpsip->next; } slp = slp->next; } } else { while (sip && bvp->TargetRow == ROW_UNDEFINED) { bvp->TargetRow = AlnMgr2GetFirstNForSip(bvp->salp, sip); sip = sip->next; } } PopulateSeqAlnView(bvp); } static void onCloseSeqPanel (PaneL p) { BioseqViewPtr bvp; bvp = GetBioseqViewPtr (p); if (bvp->SeqPanLines) FreeSeqPanelLines (bvp->SeqPanLines, bvp); bvp->SeqPanLines = NULL; bvp->sel_list = SelStructListFree (bvp->sel_list); } static void DrawTopScaleMarks(Int2 x, Int2 y, Int4 line, BioseqViewPtr bvp) { Int2 block, ctr=0; Magenta (); for (block = 0; block != bvp->BlocksAtLine && ctr >= 0; block++) { MoveTo(x+SEQ_X_OFFSET+bvp->SeqStartPosX+(block+1)*SEQ_GROUP_SIZE*bvp->CharWidth+block*bvp->CharWidth - bvp->CharWidth/2 - 1, y - 1); LineTo(x+SEQ_X_OFFSET+bvp->SeqStartPosX+(block+1)*SEQ_GROUP_SIZE*bvp->CharWidth+block*bvp->CharWidth - bvp->CharWidth/2 - 1, y-bvp->CharHeight); MoveTo(x+SEQ_X_OFFSET+bvp->SeqStartPosX+(block+1)*SEQ_GROUP_SIZE*bvp->CharWidth+block*bvp->CharWidth - SEQ_GROUP_SIZE*bvp->CharWidth/2 - bvp->CharWidth/2 - 1, y - 1); LineTo(x+SEQ_X_OFFSET+bvp->SeqStartPosX+(block+1)*SEQ_GROUP_SIZE*bvp->CharWidth+block*bvp->CharWidth - SEQ_GROUP_SIZE*bvp->CharWidth/2 - bvp->CharWidth/2 - 1, y-bvp->CharHeight/2); } } static void DrawTopSeqNums(Int2 x, Int2 y, Int4 line, BioseqViewPtr bvp) { Int2 block, ctr=0; char buf[20]; Magenta (); for (block = 0; block != bvp->BlocksAtLine && ctr >= 0; block++) { sprintf(buf, "%d", line * bvp->CharsAtLine + (block+1)*SEQ_GROUP_SIZE); PaintStringEx (buf, x+SEQ_X_OFFSET+bvp->SeqStartPosX+(block+1)*SEQ_GROUP_SIZE*bvp->CharWidth+block*bvp->CharWidth - bvp->CharWidth*StrLen(buf), y); } } static void DrawAlignmentDivider (Int2 x, Int2 y, BioseqViewPtr bvp) { Int2 block, ctr=0; char buf[20]; Magenta (); for (block = 0; block != bvp->BlocksAtLine && ctr >= 0; block++) { sprintf(buf, "~~~~~~~~~~"); PaintStringEx (buf, x+SEQ_X_OFFSET+bvp->SeqStartPosX+(block+1)*SEQ_GROUP_SIZE*bvp->CharWidth+block*bvp->CharWidth - bvp->CharWidth*StrLen(buf), y); } } static void DrawSeqSideLineNumbers(Int2 x, Int2 y, Int4 line, BioseqViewPtr bvp) { char buf[20]; sprintf(buf, "%d", line * bvp->CharsAtLine + 1); /* In sequence coordinates */ Magenta (); PaintStringEx (buf, x+ SEQ_X_OFFSET + (bvp->SeqStartPosX-30-bvp->CharWidth*StrLen(buf)), y); } static void DrawAlignSideLineNumbers (Int2 x, Int2 y, Int4 line, Int4 row, BioseqViewPtr bvp, Int4 aln_idx) { char buf[20]; Int4 aln_pos = line * bvp->CharsAtLine + 1; Int4 seq_pos; Int4 i; SeqAlignPtr tmp_salp; for (i=0, tmp_salp = bvp->salp; i < aln_idx && tmp_salp != NULL; i++, tmp_salp = tmp_salp->next) { } if (tmp_salp == NULL) return; seq_pos = AlnMgr2MapSeqAlignToBioseq(tmp_salp, aln_pos, row); while (seq_pos == ALNMGR_GAP && aln_pos > 1) { /* count back if we in the gap */ aln_pos--; seq_pos = AlnMgr2MapSeqAlignToBioseq(bvp->salp, aln_pos, row); } if (seq_pos == ALNMGR_GAP) seq_pos = 1; /* Gap at the begining of the alignment */ sprintf(buf, "%d", seq_pos); /* In alignment coordinates */ Magenta (); SelectFont ((FonT)(bvp->displayFont)); PaintStringEx (buf, x+ SEQ_X_OFFSET + (bvp->SeqStartPosX-30-bvp->CharWidth*StrLen(buf)), y); } static double *GetAlignmentColumnPercentIDsForAlignmentSection (BioseqViewPtr bvp, Int4 line, Int4 aln_idx) { Int4 i, start, stop; SeqAlignPtr tmp_salp; double * pct_ids; Int4 aln_len; if (bvp == NULL) return NULL; for (i=0, tmp_salp = bvp->salp; i < aln_idx && tmp_salp != NULL; i++, tmp_salp = tmp_salp->next) { } if (tmp_salp == NULL) return NULL; start = line * bvp->CharsAtLine; stop = start + bvp->BlocksAtLine * SEQ_GROUP_SIZE; aln_len = AlnMgr2GetAlnLength(tmp_salp, FALSE); pct_ids = GetAlignmentColumnPercentIdentities (tmp_salp, start, stop, FALSE, TRUE); for (i = aln_len; i <= stop; i++) { pct_ids[i - start] = 1.0; } return pct_ids; } static void DrawPercentIDColors (double * pct_ids, Int2 x, Int2 y, Int4 line, BioseqViewPtr bvp, double threshhold) { RecT rct; Int4 i; Int4 start = line * bvp->CharsAtLine; Int4 stop = start + bvp->BlocksAtLine * SEQ_GROUP_SIZE; Int4 x_pos; if (pct_ids == NULL) return; for (i = start; i < stop; i++) { if (pct_ids[i - start] < threshhold) { Gray (); InvertColors (); Black (); x_pos = x + SEQ_X_OFFSET + bvp->SeqStartPosX + (i - start) * bvp->CharWidth + ((i - start) / SEQ_GROUP_SIZE) * bvp->CharWidth; LoadRect (&rct, x_pos, y + Descent (), x_pos + bvp->CharWidth, y - bvp->LineHeight + Descent ()); EraseRect (&rct); InvertColors(); } } } static void DrawAlignment (Int2 x, Int2 y, Int4 line, Int4 row, Uint1Ptr buf, Uint1Ptr seqbuf, Uint1Ptr alnbuf, BioseqViewPtr bvp, Int4 aln_idx, double *pct_ids) { Int2 block; CharPtr alnlabel; Int4 alnlabel_len; BioseqPtr bsp; Int4 start = line * bvp->CharsAtLine; Int4 stop = start + bvp->BlocksAtLine * SEQ_GROUP_SIZE; Int4 alnbuf_len; SeqIdPtr best_id; SeqAlignPtr tmp_salp; Int4 i; RecT rct; Boolean invert = FALSE; for (i=0, tmp_salp = bvp->salp; i < aln_idx && tmp_salp != NULL; i++, tmp_salp = tmp_salp->next) { } if (tmp_salp == NULL) return; bsp = LockNthBioseqInAlignment(tmp_salp, row); if (bsp == NULL) return; AlignmentIntervalToString (tmp_salp, row, start, stop, bvp->TargetRow, bvp->viewWholeEntity, seqbuf, alnbuf, &alnbuf_len, bvp->showAlnSubstitutions); /* finally draw everything */ best_id = SeqIdFindBestAccession (bsp->id); alnlabel_len = (bvp->SeqStartPosX / bvp->CharWidth) - 10; if (alnlabel_len < 10) alnlabel_len = 10; alnlabel = (CharPtr) MemNew (sizeof (Char) * (alnlabel_len + 1)); SeqIdWrite (best_id, alnlabel, PRINTID_TEXTID_ACCESSION, alnlabel_len); /* Get label */ if (row == bvp->TargetRow && !bvp->viewWholeEntity) Red(); /* Highlight current */ else Black(); /* We need to select the font here because BioseqLockById will update * the Desktop if it is open, which will change the font setting. */ SelectFont ((FonT)(bvp->displayFont)); PaintStringEx (alnlabel, x+10, y); /* Draw sequence label */ alnlabel = MemFree (alnlabel); if (isSelected (bsp->idx.entityID, bsp->idx.itemID, OBJ_BIOSEQ, bvp)) { Gray (); InvertColors (); Black (); LoadRect (&rct, x + SEQ_X_OFFSET + bvp->SeqStartPosX, y + Descent (), x + SEQ_X_OFFSET + bvp->SeqStartPosX + bvp->BlocksAtLine * SEQ_GROUP_SIZE * bvp->CharWidth + (bvp->BlocksAtLine - 1) * bvp->CharWidth, y - bvp->LineHeight + Descent ()); EraseRect (&rct); invert = TRUE; } else { DrawPercentIDColors (pct_ids, x, y, line, bvp, (double) 0.5); Black (); } block = 0; for (block = 0; block != bvp->BlocksAtLine; block++) { Int4 len = SEQ_GROUP_SIZE; Int4 from = block * SEQ_GROUP_SIZE; if (from >= alnbuf_len) break; if (from + SEQ_GROUP_SIZE > alnbuf_len) len = alnbuf_len - from; MemCpy(buf, alnbuf + from, len); MemSet(buf+len, '\0', 1); PaintStringEx ( (CharPtr)buf, x+SEQ_X_OFFSET+bvp->SeqStartPosX+block*SEQ_GROUP_SIZE*bvp->CharWidth+block*bvp->CharWidth, y); } BioseqUnlock (bsp); if (invert) { InvertColors (); } } /* DrawAlignment*/ static Int2 SeqPos2XCoord(Int2 x, Int4 seqXPos, BioseqViewPtr bvp); static void DrawSequenceCaret (Int2 x, Int2 y, Int4 line, BioseqViewPtr bvp) { PoinT pt1, pt2; Int4 lenv = 3; Int4 lenh = 2; Int4 colstart, colstop, row; WindoW w; SeqEdFormPtr sefp; if (bvp == NULL) return; w = ParentWindow (bvp->seqView); if (w == NULL) return; sefp = (SeqEdFormPtr) GetObjectExtra (w); if (sefp == NULL) return; if (line < sefp->edit_pos_start / bvp->CharsAtLine || line > sefp->edit_pos_end / bvp->CharsAtLine) { return; } Red (); WidePen (2); row = y + 1; if (sefp->edit_pos_start / bvp->CharsAtLine == line) { /* draw start of caret */ colstart = SeqPos2XCoord(x, sefp->edit_pos_start - line * bvp->CharsAtLine, bvp); pt1.x = colstart; pt1.y = row - lenv; pt2.x = colstart; pt2.y = row; DrawLine (pt1, pt2); } else { colstart = SeqPos2XCoord(x, 0, bvp); } if (sefp->edit_pos_end == sefp->edit_pos_start) { colstop = colstart; } else if (sefp->edit_pos_end / bvp->CharsAtLine == line) { colstop = SeqPos2XCoord(x, sefp->edit_pos_end - line * bvp->CharsAtLine - 1, bvp) + bvp->CharWidth; pt1.x = colstop; pt1.y = row - lenv; pt2.x = colstop; pt2.y = row; DrawLine (pt1, pt2); } else { colstop = SeqPos2XCoord (x, bvp->CharsAtLine, bvp); } if (sefp->edit_pos_start == sefp->edit_pos_end) { colstart -= lenh; colstop += lenh; } pt1.x = colstart; pt1.y = row; pt2.x = colstop; pt2.y = row; DrawLine (pt1, pt2); WidePen (1); Black (); } static void DrawSequenceCodonBoundaries (Int2 x, Int2 y, Int4 frame, Int4 line, BioseqViewPtr bvp) { Int4 offset; PoinT pt1, pt2; Int2 block; Int4 low, high; if (frame == 0) return; Gray (); if (frame < 4) { offset = 3 - ((line * bvp->CharsAtLine) % 3) + frame - 1; if (offset > 2) offset -= 3; } else { offset = 7 - frame + ((bvp->bsp->length - (line * bvp->CharsAtLine)) % 3); if (offset > 2) offset -= 3; } low = y + 2; high = y - bvp->CharHeight; for (block = 0; block != bvp->BlocksAtLine; block++) { if (offset > 0) { pt1.x = x+SEQ_X_OFFSET+bvp->SeqStartPosX+block*SEQ_GROUP_SIZE*bvp->CharWidth+block*bvp->CharWidth; pt2.x = pt1.x + offset * bvp->CharWidth; pt1.y = low; pt2.y = low; DrawLine (pt1, pt2); } while (offset + 2 < SEQ_GROUP_SIZE) { pt1.x = x + SEQ_X_OFFSET + bvp->SeqStartPosX + block * SEQ_GROUP_SIZE * bvp->CharWidth + block * bvp->CharWidth + offset * bvp->CharWidth; pt2.x = pt1.x; pt1.y = low; pt2.y = high; DrawLine (pt1, pt2); pt2.x = pt1.x + 3 * bvp->CharWidth; pt2.y = low; DrawLine (pt1, pt2); offset += 3; } pt1.x = x + SEQ_X_OFFSET + bvp->SeqStartPosX + block * SEQ_GROUP_SIZE * bvp->CharWidth + block * bvp->CharWidth + offset * bvp->CharWidth; pt2.x = pt1.x; pt1.y = low; pt2.y = high; DrawLine (pt1, pt2); if (offset < SEQ_GROUP_SIZE) { pt1.x = x + SEQ_X_OFFSET + bvp->SeqStartPosX + block * SEQ_GROUP_SIZE * bvp->CharWidth + block * bvp->CharWidth + offset * bvp->CharWidth; pt2.x = pt1.x + (SEQ_GROUP_SIZE - offset) * bvp->CharWidth; pt1.y = low; pt2.y = low; DrawLine (pt1, pt2); } offset -= SEQ_GROUP_SIZE; if (offset < 0) { offset += 3; } } Black (); } static void DrawSequence(Int2 x, Int2 y, Int4 line, SeqPortPtr spp, Uint1Ptr buf, BioseqViewPtr bvp) { Int2 block, ctr = 0, i; y -= Descent(); Black (); for (block = 0; block != bvp->BlocksAtLine && ctr >= 0; block++) { SeqPortSeek (spp, line*bvp->CharsAtLine+block*SEQ_GROUP_SIZE, SEEK_SET); ctr = SeqPortRead (spp, buf, SEQ_GROUP_SIZE); if (ctr > 0) { if (ctr < SEQ_GROUP_SIZE) MemSet(buf+ctr, '\0', 1); for (i = 0; i < ctr; i++) buf[i] = TO_LOWER (buf[i]); /* convert to lowercase */ PaintStringEx ( (CharPtr)buf, x+SEQ_X_OFFSET+bvp->SeqStartPosX+block*SEQ_GROUP_SIZE*bvp->CharWidth+block*bvp->CharWidth, y); } } DrawSequenceCaret (x, y, line, bvp); } static void DrawSequenceComplement(Int2 x, Int2 y, Int4 line, SeqPortPtr spp, Uint1Ptr buf, BioseqViewPtr bvp) { Int2 block, ctr = 0, i; y -= Descent(); Black (); PaintStringEx ("complement", x+10, y); for (block = 0; block != bvp->BlocksAtLine && ctr >= 0; block++) { SeqPortSeek (spp, line*bvp->CharsAtLine+block*SEQ_GROUP_SIZE, SEEK_SET); ctr = SeqPortRead (spp, buf, SEQ_GROUP_SIZE); if (ctr > 0) { if (ctr < SEQ_GROUP_SIZE) MemSet(buf+ctr, '\0', 1); for (i = 0; i < ctr; i++) buf[i] = TO_LOWER (buf[i]); /* convert to lowercase */ complement_string ((CharPtr)buf); PaintStringEx ( (CharPtr)buf, x+SEQ_X_OFFSET+bvp->SeqStartPosX+block*SEQ_GROUP_SIZE*bvp->CharWidth+block*bvp->CharWidth, y); } } } static void DrawLineEx(Int2 x1, Int2 y1, Int2 x2, Int2 y2, Int2 width) { WidePen (width); MoveTo (x1, y1); LineTo (x2, y2); WidePen (1); } static void DrawLtGrid(Int2 x1, Int2 y1, Int2 x2, Int2 y2) { LtGray(); MoveTo (x1, y1); LineTo (x2, y2); } static void DrawDkGrid(Int2 x1, Int2 y1, Int2 x2, Int2 y2) { DkGray(); MoveTo (x1, y1); LineTo (x2, y2); } static Int2 SeqPos2XCoord(Int2 x, Int4 seqXPos, BioseqViewPtr bvp) { Int4 blocks = seqXPos / SEQ_GROUP_SIZE; Int2 xPos = x + SEQ_X_OFFSET + bvp->SeqStartPosX + seqXPos * bvp->CharWidth + blocks*bvp->CharWidth; Int2 rPos = x + SEQ_X_OFFSET + bvp->SeqStartPosX + bvp->CharsAtLine * bvp->CharWidth + (blocks-1) * bvp->CharWidth; return xPos > rPos ? rPos : xPos; } static Int4 GetFeatureX(Int4 feat_pos, Int4 bsStart, Int4 bsFinish, Boolean is_start) { Int4 lineFeatPos = is_start ? (bsStart < feat_pos ? feat_pos : bsStart ): (bsFinish < feat_pos ? bsFinish : feat_pos); return lineFeatPos; } static Boolean IsInRange(Int4 pos, Int4 min_pos, Int4 max_pos) { return min_pos <= pos && pos <= max_pos; } static void DrawMismatchBox (Int4 x, Int4 y, Int4 lineheight, Int4 charwidth) { PoinT pt1, pt2; Red (); pt1.x = x; pt1.y = y; pt2.x = x; pt2.y = y - lineheight; DrawLine (pt1, pt2); pt1.y = pt2.y; pt1.x = x + charwidth; DrawLine (pt1, pt2); pt2.x = pt1.x; pt2.y = y; DrawLine (pt1, pt2); pt1.x = x; pt1.y = y; DrawLine (pt1, pt2); Blue (); } static Int4 CalculatePreviousProductLength (SeqMgrFeatContext fcontext, Int4 interval_offset, Int4 display_start, Int4 display_end, Int4 aln_pos_left, Int4 aln_pos_right, Uint2 aln_strand, Int4 aln_row, BioseqViewPtr bvp) { Int4 product_start = 0, k, seq_offset; Int4 interval_high, interval_low; if (bvp == NULL || interval_offset < 0) { return 0; } for (k = 0; k < interval_offset; k++) { product_start += ABS (fcontext.ivals [2 * k + 1] - fcontext.ivals [2 * k]) + 1; } interval_high = MAX (fcontext.ivals [2 * interval_offset], fcontext.ivals [2 * interval_offset + 1]); interval_low = MIN (fcontext.ivals [2 * interval_offset], fcontext.ivals [2 * interval_offset + 1]); if (aln_strand == Seq_strand_plus) { if ((fcontext.strand == Seq_strand_minus && aln_pos_right <= display_end) || (fcontext.strand != Seq_strand_minus && aln_pos_left > display_start)) { return product_start; } } else { if ((fcontext.strand == Seq_strand_minus && aln_pos_left > display_start) || (fcontext.strand != Seq_strand_minus && aln_pos_right < display_end)) { return product_start; } } if (bvp->seqAlignMode) { if (fcontext.strand == Seq_strand_minus) { if (aln_strand == Seq_strand_plus) { for (seq_offset = interval_high; seq_offset >= interval_low; seq_offset--) { if (x_Coord (bvp, seq_offset, aln_row) <= display_end) { break; } } product_start += interval_high - seq_offset + 1; } else { for (seq_offset = interval_high; seq_offset >= interval_low; seq_offset --) { if (x_Coord (bvp, seq_offset, aln_row) >= display_start) { break; } } product_start += interval_high - seq_offset + 1; } } else { if (aln_strand == Seq_strand_plus) { /* need to find out how much of the product appears in lines before this one. * Can't simply subtract the distance, because we can't count the gap characters * as part of the product. */ for (seq_offset = interval_low; seq_offset <= interval_high; seq_offset++) { if (x_Coord (bvp, seq_offset, aln_row) >= display_start) { break; } } product_start += seq_offset - interval_low; } else { for (seq_offset = interval_low; seq_offset <= interval_high; seq_offset ++) { if (x_Coord (bvp, seq_offset, aln_row) <= display_end) { break; } } product_start += seq_offset - interval_low; } } } else { if (fcontext.strand == Seq_strand_minus) { /* how much of the product appears in lines after this one? */ product_start += interval_high - display_end + 1; } else { /* how much of the product appears in lines before this one? */ product_start += display_start - interval_low; } } return product_start; } /* This function puts the letters for a minus strand product in the correct positions * in the feature line. */ static void PaintMinusProtein (Int4 x, Int4 y, Int4 row, SeqMgrFeatContext fcontext, Int4 interval_offset, Int4 bsStart, Int4 bsFinish, Int4 frame, CharPtr str_prot, CharPtr str_trans, BioseqViewPtr bvp, Uint2 aln_strand) { Int4 product_start, k; Int4 prot_pos, x_pos; Char tmp[2]; Int4 prot_len, trans_len; Int4 aln_pos_right, aln_pos_left; Int4 product_pos; tmp [1] = 0; if (str_prot == NULL || interval_offset >= fcontext.numivals) return; prot_len = StringLen (str_prot); /* calculate the length of the translation string - it may be longer or shorter * than our protein, or it might not have been provided. */ if (str_trans == NULL) { trans_len = 0; } else { trans_len = StringLen (str_trans); } /* in the alignment coordinate system, find the mapping for the right end of the * interval. */ aln_pos_right = x_Coord(bvp, fcontext.ivals [2 * interval_offset], row); aln_pos_left = x_Coord(bvp, fcontext.ivals [2 * interval_offset + 1], row); product_start = CalculatePreviousProductLength (fcontext, interval_offset, bsStart, bsFinish, aln_pos_left, aln_pos_right, aln_strand, row, bvp); product_pos = product_start; product_pos -= frame - 1; if (aln_pos_right > bsFinish - 1) { aln_pos_right = bsFinish - 1; } if (aln_pos_left < bsStart) { aln_pos_left = bsStart; } /* we need to step through the alignment coordinates */ for (k = aln_pos_right; k >= aln_pos_left; k--) { /* Check for gaps in this feature if in alignment mode */ if (bvp->seqAlignMode && AlnMgr2MapSeqAlignToBioseq(bvp->salp, k, row) < 0) { x_pos = SeqPos2XCoord (x, k - bsStart, bvp); PaintStringEx("-", x_pos, y); continue; } else { prot_pos = product_pos / 3; if (prot_pos >= prot_len) { continue; } if (product_pos % 3 == 1) { x_pos = SeqPos2XCoord (x, k - bsStart, bvp); tmp[0] = str_prot [prot_pos]; if (prot_pos < trans_len && str_trans[prot_pos] != str_prot[prot_pos]) { DrawMismatchBox (x_pos, y, bvp->LineHeight, bvp->CharWidth); } if (str_prot [prot_pos] == '*') { Red(); } PaintStringEx(tmp, x_pos, y); if (prot_pos < trans_len && str_trans[prot_pos] != str_prot[prot_pos]) { Blue(); } } product_pos ++; } } } static void PaintPlusProtein (Int4 x, Int4 y, Int4 row, SeqMgrFeatContext fcontext, Int4 interval_offset, Int4 bsStart, Int4 bsFinish, Int4 frame, CharPtr str_prot, CharPtr str_trans, BioseqViewPtr bvp, Uint2 aln_strand) { Int4 product_start, k; Int4 prot_pos, x_pos; Char tmp[2]; Int4 prot_len, trans_len; Int4 aln_pos_right, aln_pos_left; Int4 product_pos; tmp [1] = 0; if (str_prot == NULL || interval_offset >= fcontext.numivals) return; prot_len = StringLen (str_prot); /* calculate the length of the translation string - it may be longer or shorter * than our protein, or it might not have been provided. */ if (str_trans == NULL) { trans_len = 0; } else { trans_len = StringLen (str_trans); } /* in the alignment coordinate system, find the mapping for the right end of the * interval. */ aln_pos_right = x_Coord(bvp, fcontext.ivals [2 * interval_offset + 1], row); aln_pos_left = x_Coord (bvp, fcontext.ivals [2 * interval_offset], row); product_start = CalculatePreviousProductLength (fcontext, interval_offset, bsStart, bsFinish, aln_pos_left, aln_pos_right, aln_strand, row, bvp); product_pos = product_start; product_pos -= frame - 1; if (product_start == 0 && product_pos > 2) { product_pos -= 3; } if (aln_pos_right > bsFinish - 1) { aln_pos_right = bsFinish - 1; } if (aln_pos_left < bsStart) { aln_pos_left = bsStart; } /* we need to step through the alignment coordinates */ for (k = aln_pos_left; k <= aln_pos_right; k++) { /* Check for gaps in this feature if in alignment mode */ if (bvp->seqAlignMode && AlnMgr2MapSeqAlignToBioseq(bvp->salp, k, row) < 0) { x_pos = SeqPos2XCoord (x, k - bsStart, bvp); PaintStringEx("-", x_pos, y); continue; } else { prot_pos = product_pos / 3; if (prot_pos >= prot_len) { continue; } x_pos = SeqPos2XCoord (x, k - bsStart, bvp); if (product_pos % 3 == 1) { if (prot_pos < trans_len && str_trans[prot_pos] != str_prot[prot_pos]) { DrawMismatchBox (x_pos, y, bvp->LineHeight, bvp->CharWidth); } if (str_prot [prot_pos] == '*') { Red(); } tmp[0] = str_prot [prot_pos]; PaintStringEx(tmp, x_pos, y); if (str_prot [prot_pos] == '*') { Blue(); } } product_pos ++; } } } static void DrawFeatureCodonLines (Int2 x, Int2 y, Int4 line, Int4 row, Int2 seqY, Uint4 itemID, Boolean protProduct, BioseqPtr bsp, BioseqViewPtr bvp) { Int4 codon_pos; Int4 k; Int4 x_pos; Char tmp[2]; Int4 aln_pos_right, aln_pos_left; Int4 product_pos; Int4 int_num; PoinT pt1, pt2, pt3, pt4; Int4 bsStart, bsFinish; SeqFeatPtr sfp; SeqMgrFeatContext fcontext; CdRegionPtr crp; Int2 frame = 1; if (!isSelected(bsp->idx.entityID, itemID, OBJ_SEQFEAT, bvp) || ! protProduct) { return; } /* need to find feature */ if (bvp->seqAlignMode) { BioseqPtr bsp_tmp = LockNthBioseqInAlignment(bvp->salp, row); sfp = SeqMgrGetDesiredFeature (ObjMgrGetEntityIDForPointer(bsp_tmp), bsp_tmp, itemID, 0, NULL, &fcontext); BioseqUnlock (bsp_tmp); } else { sfp = SeqMgrGetDesiredFeature (0, bsp, itemID, 0, NULL, &fcontext); } if (sfp == NULL || sfp->data.choice != SEQFEAT_CDREGION) return; crp = sfp->data.value.ptrvalue; if (crp == NULL ) return; if (crp->frame == 2) frame--; if (crp->frame == 3) frame-=2; bsStart = line * bvp->CharsAtLine; bsFinish = bsStart + bvp->CharsAtLine; /* then cycle through intervals, using only the ones applicable to line */ product_pos = frame - 1; tmp [1] = 0; for (int_num = 0; int_num < fcontext.numivals; int_num++) { if (fcontext.strand == Seq_strand_minus) { aln_pos_left = x_Coord(bvp, fcontext.ivals [ 2 * int_num + 1], row); aln_pos_right = x_Coord(bvp, fcontext.ivals [ 2 * int_num], row); } else { aln_pos_left = x_Coord(bvp, fcontext.ivals [ 2 * int_num], row); aln_pos_right = x_Coord(bvp, fcontext.ivals [ 2 * int_num + 1], row); } if (aln_pos_right < bsStart || aln_pos_left > bsFinish) { product_pos += aln_pos_right - aln_pos_left + 1; } else if (fcontext.strand == Seq_strand_minus && aln_pos_right > bsFinish) { /* find the portion of this interval that extends into the next line */ if (bvp->seqAlignMode) { /* need to find out how much of the product appears in lines after this one. * Can't simply subtract the distance, because we can't count the gap characters * as part of the product. */ for (k = aln_pos_right; k >= aln_pos_left; k--) { if (x_Coord (bvp, k, row) <= bsFinish) { break; } } product_pos += aln_pos_right - k + 1; } else { /* how much of the product appears in lines before this one? */ product_pos += aln_pos_right - bsFinish + 1; } } else if (fcontext.strand != Seq_strand_minus && aln_pos_left < bsStart) { /* find the portion of this interval that extends into the previous line */ if (bvp->seqAlignMode) { /* need to find out how much of the product appears in lines before this one. * Can't simply subtract the distance, because we can't count the gap characters * as part of the product. */ for (k = aln_pos_left; k <= aln_pos_right; k++) { if (x_Coord (bvp, k, row) >= bsStart) { break; } } product_pos += k - aln_pos_left; } else { /* how much of the product appears in lines before this one? */ product_pos += bsStart - aln_pos_left; } } /* we will only look at alignment coordinates inside our line */ if (fcontext.strand == Seq_strand_minus) { if (aln_pos_right > bsFinish - 1) { aln_pos_right = bsFinish - 1; } if (aln_pos_left < bsStart) { aln_pos_left = bsStart; } } else { if (aln_pos_right > bsFinish) { aln_pos_right = bsFinish; } if (aln_pos_left < bsStart) { aln_pos_left = bsStart; } } if (fcontext.strand == Seq_strand_minus) { /* minus strand - step through in minus direction */ for (k = aln_pos_right; k >= aln_pos_left; k--) { /* Check for gaps in this feature if in alignment mode */ if (bvp->seqAlignMode && AlnMgr2MapSeqAlignToBioseq(bvp->salp, k, row) < 0) { continue; /* we don't draw codon lines or increase the product position in a gap */ } else { x_pos = SeqPos2XCoord (x, k - bsStart, bvp); codon_pos = product_pos % 3; if (codon_pos != 1) { pt1.y = y - 1; pt2.y = y - bvp->LineHeight; pt3.y = seqY; pt4.y = seqY + 4; if (codon_pos == 0) { pt1.x = x_pos + bvp->CharWidth; } else if (codon_pos == 2) { pt1.x = x_pos; } pt2.x = pt1.x; pt3.x = pt1.x; pt4.x = pt1.x; Gray (); DrawLine (pt1, pt2); DrawLine (pt3, pt4); Blue (); } product_pos ++; } } } else { /* plus strand - step through in plus direction */ for (k = aln_pos_left; k <= aln_pos_right; k++) { /* Check for gaps in this feature if in alignment mode */ if (bvp->seqAlignMode && AlnMgr2MapSeqAlignToBioseq(bvp->salp, k, row) < 0) { continue; /* we don't draw codon lines or increase the product position in a gap */ } else { x_pos = SeqPos2XCoord (x, k - bsStart, bvp); codon_pos = product_pos % 3; if (codon_pos != 1) { pt1.y = y; pt2.y = y - bvp->LineHeight; pt3.y = seqY; pt4.y = seqY + 4; if (codon_pos == 0) { pt1.x = x_pos; } else if (codon_pos == 2) { pt1.x = x_pos + bvp->CharWidth; } pt2.x = pt1.x; pt3.x = pt1.x; pt4.x = pt1.x; Gray (); DrawLine (pt1, pt2); DrawLine (pt3, pt4); Blue (); } product_pos ++; } } } } } static void DrawFeature(Int2 x, Int2 y, Int4 line, Int4 row, Uint4 itemID, Boolean protProduct, Boolean on_the_fly, BioseqPtr bsp, BioseqViewPtr bvp) { SeqMgrFeatContext fcontext; SeqFeatPtr sfp; BioseqPtr bsp_prot; CharPtr str_prot = NULL; Int4 bsStart, bsFinish, ffStart, ffFinish, i; Int2 x1, x2; Char featLabel[13]; Int4 fLeft, fRight; Int4 prot_len; ByteStorePtr bs; CharPtr str_trans = NULL; Int4 aln_row = -1; Uint2 aln_strand = Seq_strand_plus; y -= Descent(); if (bvp->seqAlignMode) { BioseqPtr bsp_tmp = LockNthBioseqInAlignment(bvp->salp, row); sfp = SeqMgrGetDesiredFeature (ObjMgrGetEntityIDForPointer(bsp_tmp), bsp_tmp, itemID, 0, NULL, &fcontext); BioseqUnlock (bsp_tmp); aln_row = row; aln_strand = AlnMgr2GetNthStrand (bvp->salp, row); } else { sfp = SeqMgrGetDesiredFeature (0, bsp, itemID, 0, NULL, &fcontext); } if (sfp == NULL) return; bsStart = line * bvp->CharsAtLine; bsFinish = bsStart + bvp->CharsAtLine; fLeft = x_FeatLeft (bvp, fcontext.left, aln_row); fRight = x_FeatRight(bvp, fcontext.right, aln_row); if (aln_strand == Seq_strand_minus) { ffStart = GetFeatureX(x_Coord(bvp, fRight, row), bsStart, bsFinish, TRUE ) - bsStart; ffFinish = GetFeatureX(x_Coord(bvp, fLeft, row), bsStart, bsFinish, FALSE) - bsStart; } else { ffStart = GetFeatureX(x_Coord(bvp, fLeft, row), bsStart, bsFinish, TRUE ) - bsStart; ffFinish = GetFeatureX(x_Coord(bvp, fRight, row), bsStart, bsFinish, FALSE) - bsStart; } x1 = SeqPos2XCoord(x, ffStart, bvp); x2 = SeqPos2XCoord(x, ffFinish, bvp); fcontext.seqfeattype == SEQFEAT_CDREGION ? Blue() : Black(); if (on_the_fly) { StringCpy (featLabel, "on-the-fly"); PaintStringEx (featLabel, x+10, y); } else if (fcontext.label != NULL) { StrNCpy( featLabel, fcontext.label, 12); featLabel[12]='\0'; PaintStringEx (featLabel, x+10, y); } if (bvp->show_translation_errors) { bs = ProteinFromCdRegionEx (sfp, TRUE, FALSE); if (bs != NULL) { str_trans = BSMerge (bs, NULL); bs = BSFree (bs); } } else { str_trans = NULL; } if (protProduct) { bsp_prot = BioseqFind (SeqLocId(sfp->product)); if (on_the_fly && fcontext.seqfeattype == SEQFEAT_CDREGION && sfp->data.value.ptrvalue != NULL) { if (str_trans == NULL) { bs = ProteinFromCdRegionEx (sfp, TRUE, FALSE); if (bs != NULL) { str_prot = BSMerge (bs, NULL); bs = BSFree (bs); } } else { str_prot = str_trans; } } else { str_prot = GetSequenceByBsp (bsp_prot); } if (str_prot == NULL) { PaintStringEx ("Protein sequence is not available", SeqPos2XCoord(x, 0, bvp), y); return; } prot_len = StringLen (str_prot) - 1; } else DrawLineEx(x1, y-bvp->LineHeight/2+2, x2, y-bvp->LineHeight/2+2, 1); for (i = 0; i != fcontext.numivals; i++) { Int4 regStart, regFinish; Int4 fStart, fFinish; RecT rect; Int4 ifLeft = x_FeatLeft (bvp, fcontext.strand==Seq_strand_minus ? fcontext.ivals[i*2+1] : fcontext.ivals[i*2], aln_row); Int4 ifRight = x_FeatRight (bvp, fcontext.strand==Seq_strand_minus ? fcontext.ivals[i*2] : fcontext.ivals[i*2+1], aln_row); if (aln_strand == Seq_strand_minus) { regStart = x_Coord(bvp, ifRight, row); regFinish = x_Coord(bvp, ifLeft, row); } else { regStart = x_Coord(bvp, ifLeft, row); regFinish = x_Coord(bvp, ifRight, row); } fStart = GetFeatureX(regStart, bsStart, bsFinish, TRUE ); fFinish = GetFeatureX(regFinish, bsStart, bsFinish, FALSE); if( !IsInRange(regStart, bsStart, bsFinish ) && !IsInRange(regFinish, bsStart, bsFinish) && !IsInRange(bsStart, regStart, regFinish) && !IsInRange(bsFinish, regStart, regFinish) ) continue; x1 = SeqPos2XCoord(x, fStart - bsStart, bvp); x2 = SeqPos2XCoord(x, fFinish - bsStart, bvp); if (protProduct) { /* draw protein product */ Int4 frame = 1; /* center in group of 3 */ if (sfp->data.choice == SEQFEAT_CDREGION) { CdRegionPtr crp = sfp->data.value.ptrvalue; if (crp != NULL ) { if (crp->frame == 2) frame++; if (crp->frame == 3) frame+=2; } } #if defined(WIN_MOTIF) White(); DrawLineEx(x1, y-1, x2, y-1, bvp->CharHeight); #elif defined(WIN_MSWIN) White(); DrawLineEx(x1, y+2, x2, y+2, bvp->CharHeight); #else White(); DrawLineEx(x1, y-bvp->CharHeight, x2, y-bvp->CharHeight, bvp->CharHeight); #endif Blue(); if ((fcontext.strand == Seq_strand_minus && aln_strand != Seq_strand_minus) || (fcontext.strand != Seq_strand_minus && aln_strand == Seq_strand_minus)) { PaintMinusProtein (x, y, row, fcontext, i, bsStart, bsFinish, frame, str_prot, str_trans, bvp, aln_strand); } else { PaintPlusProtein (x, y, row, fcontext, i, bsStart, bsFinish, frame, str_prot, str_trans, bvp, aln_strand); } } /* protein product */ else { /* draw feature line */ Int4 i; fcontext.seqfeattype == SEQFEAT_CDREGION ? Blue() : Black(); #if defined(WIN_MOTIF) DrawLineEx(x1+1, y-bvp->LineHeight/2+2, x2, y-bvp->LineHeight/2+2, 3); if (isSelected(bsp->idx.entityID, itemID, OBJ_SEQFEAT, bvp)) { Black(); DrawLineEx(x1+1, y-bvp->LineHeight/2-1, x2, y-bvp->LineHeight/2-1, 1); DrawLineEx(x1+1, y-bvp->LineHeight/2+7, x2, y-bvp->LineHeight/2+7, 1); } #elif defined(WIN_MSWIN) /* should be verified */ DrawLineEx(x1+1, y-bvp->LineHeight/2+2, x2, y-bvp->LineHeight/2+2, 3); if (isSelected(bsp->idx.entityID, itemID, OBJ_SEQFEAT, bvp)) { Black(); DrawLineEx(x1+1, y-bvp->LineHeight/2-1, x2, y-bvp->LineHeight/2-1, 1); DrawLineEx(x1+1, y-bvp->LineHeight/2+7, x2, y-bvp->LineHeight/2+7, 1); } #else DrawLineEx(x1, y-bvp->LineHeight/2+1, x2, y-bvp->LineHeight/2+1, 3); if (isSelected(bsp->idx.entityID, itemID, OBJ_SEQFEAT, bvp)) { Black(); DrawLineEx(x1, y-bvp->LineHeight/2-2, x2, y-bvp->LineHeight/2-2, 1); DrawLineEx(x1, y-bvp->LineHeight/2+6, x2, y-bvp->LineHeight/2+6, 1); } #endif /* draw arrow or endpoint for left side */ if (IsInRange(regStart, bsStart, bsFinish)) { LoadRect (&rect, x1, y-bvp->LineHeight/2-1, x1+7, y-bvp->LineHeight/2+6); if ((fcontext.strand == Seq_strand_minus && aln_strand != Seq_strand_minus) || (fcontext.strand != Seq_strand_minus && aln_strand == Seq_strand_minus)) { CopyBits (&rect, FillLeftArrowSym); } else { CopyBits (&rect, FillRectangleSym ); } } if (IsInRange(regFinish, bsStart, bsFinish)) { LoadRect (&rect, x2, y-bvp->LineHeight/2-1, x2+7, y-bvp->LineHeight/2+6); if ((fcontext.strand == Seq_strand_minus && aln_strand != Seq_strand_minus) || (fcontext.strand != Seq_strand_minus && aln_strand == Seq_strand_minus)) { CopyBits (&rect, FillRectangleSym); } else { CopyBits (&rect, FillRightArrowSym); } } if (bvp->seqAlignMode) { /* Check for gaps in this feature if in alignment mode */ #ifdef WIN_MOTIF Gray(); #else White(); #endif for (i = fStart; i < fFinish; i++) { if (AlnMgr2MapSeqAlignToBioseq(bvp->salp, i, row) < 0) { /* Gap? */ Int4 xPos = SeqPos2XCoord(x, i - bsStart, bvp); PaintStringEx ( "-", xPos, bvp->DrawGrid ? y - 2 : y); /* Highlight gaps in features */ } } /* for */ } } /* feature or product */ } /* for */ } static void DrawFrame(Int2 x, Int2 y, Int4 line, Int4 frame, BioseqViewPtr bvp) { SeqFeatPtr fake_cds; ByteStorePtr bs; CharPtr frame_str; Uint1 strand; Int4 seqStart; Int4 bsStart, bsFinish, j; Int4 xPos, pPos, frame_len; Char tmp[2]; Char label[50]; Int4 offset; y -= Descent(); seqStart = line * bvp->CharsAtLine; /* determine start of line */ if (frame < 4) { offset = 3 - ((line * bvp->CharsAtLine) % 3) + frame - 1; strand = Seq_strand_plus; } else { offset = 7 - frame + ((bvp->bsp->length - (line * bvp->CharsAtLine)) % 3); strand = Seq_strand_minus; } if (offset > 2) { offset = offset % 3; } if (offset == 2 && line > 0) { offset -= 3; } bsStart = seqStart + offset; bsFinish = (line + 1) * bvp->CharsAtLine + offset; frame_len = bsFinish - bsStart + 1; bsFinish -= frame_len % 3; if (frame_len % 3 == 2 && bsFinish + 3 < bvp->bsp->length) { bsFinish += 3; } /* must not extend past end of sequence */ while (bsFinish > bvp->bsp->length - 1) { bsFinish -= 3; } /* should not extend past end of line */ while (bsFinish > seqStart + bvp->CharsAtLine) { bsFinish -= 3; } frame_len = bsFinish - bsStart + 1; fake_cds = make_fake_cds(bvp->bsp, bsStart, bsFinish, strand); bs = ProteinFromCdRegionEx(fake_cds, TRUE, FALSE); SeqFeatFree(fake_cds); if(bs == NULL) return; frame_str = BSMerge (bs, NULL); bs = BSFree (bs); if (frame_str == NULL) return; frame_len = StringLen (frame_str); Black (); if (frame < 4) { sprintf(label, "frame +%d", frame); } else { sprintf (label, "frame %d", 3 - frame); } PaintStringEx (label, x+10, y); tmp[1] = '\0'; if (frame < 4) { for (j = offset + 1, pPos = 0; j < bsFinish && pPos < frame_len; j+=3, pPos ++) { xPos = SeqPos2XCoord(x, j, bvp); tmp[0] = frame_str[pPos]; PaintStringEx(tmp, xPos, y); } } else { for (j = offset + 1, pPos = frame_len - 1; j < bsFinish && pPos > -1; j+=3, pPos --) { xPos = SeqPos2XCoord(x, j, bvp); tmp[0] = frame_str[pPos]; PaintStringEx(tmp, xPos, y); } } MemFree (frame_str); } static void DrawSeqPanel (BioseqViewPtr bvp) { BioseqPtr bsp; SeqPortPtr spp; SeqPanLinePtr splp; Uint1Ptr buf, seqbuf, alnbuf; BaR sb; RecT r; Int4 line, last_row = -1; double * pct_ids = NULL; Int2 x, y; Int4 aln_idx; Int4 start; PaneL p; Int4 vis_seq_start_line, vis_seq_start, vis_seq_stop; if (bvp == NULL || bvp->bsp == NULL || bvp->SeqPanLines == NULL) return; bsp = bvp->bsp; p = bvp->seqView; buf = MemNew (SEQ_GROUP_SIZE+1); if (bvp->seqAlignMode) { /* allocate it here, to speed up drawing of alignments */ seqbuf = MemNew (bvp->BlocksAtLine * SEQ_GROUP_SIZE + 3); alnbuf = MemNew (bvp->BlocksAtLine * SEQ_GROUP_SIZE + 3); } sb = GetSlateVScrollBar ((SlatE)bvp->seqView); ObjectRect (p, &r); InsetRect (&r, 4, 4); x = r.left + 1; y = r.top + bvp->CharHeight + SEQ_Y_OFFSET; SelectFont ((FonT)(bvp->displayFont)); aln_idx = 0; start = GetBarValue (sb); for (line = 0; line < start && line < bvp->TotalLines; line++) { splp = bvp->SeqPanLines[line]; if (splp->lineType == eTypeAlignDivider) { aln_idx++; } } splp = bvp->SeqPanLines[line]; vis_seq_start_line = splp->bioSeqLine; vis_seq_start = vis_seq_start_line * bvp->CharsAtLine; if (vis_seq_start > bsp->length - 1) { spp = NULL; } else { vis_seq_stop = vis_seq_start + ((r.bottom - 3 * SEQ_Y_OFFSET - r.top) / (bvp->LineHeight == 0 ? 1 : bvp->LineHeight)) * bvp->CharsAtLine; vis_seq_stop = MIN (vis_seq_stop, bsp->length - 1); spp = SeqPortNew (bsp, vis_seq_start, vis_seq_stop, Seq_strand_plus, Seq_code_iupacna); } for (line = start; line < bvp->TotalLines && y <= r.bottom-2*SEQ_Y_OFFSET; line++) { if (IsInRange(y, updateRect.top,updateRect.bottom) || IsInRange(y+bvp->LineHeight,updateRect.top,updateRect.bottom)) { /* draw begin */ splp = bvp->SeqPanLines[line]; switch ( splp->lineType ) { case eTypeTopSeqNumbers: if (bvp->DrawGrid) DrawLtGrid(bvp->SeqStartPosX+1, y+bvp->LineSpace/2, r.right, y+bvp->LineSpace/2); DrawTopSeqNums(x, y, splp->bioSeqLine, bvp); /* Draw top numbering */ break; case eTypeTopScaleMarks: if (bvp->DrawGrid) DrawLtGrid(bvp->SeqStartPosX+1, y+bvp->LineSpace/2, r.right, y+bvp->LineSpace/2); DrawTopScaleMarks(x, y, splp->bioSeqLine, bvp); /* Draw top scale marks */ break; case eTypeSequence: if (GetValue(bvp->newNumControl) != eNumNone) DrawSeqSideLineNumbers(x, y, splp->bioSeqLine, bvp); /* Draw line numbers */ DrawSequence(x, y, splp->bioSeqLine - vis_seq_start_line, spp, buf, bvp); /* Draw the sequence */ if (bvp->DrawGrid) DrawLtGrid(x, y+bvp->LineSpace/2, r.right, y+bvp->LineSpace/2); break; case eTypeSequenceComplement: DrawSequenceComplement(x, y, splp->bioSeqLine - vis_seq_start_line, spp, buf, bvp); /* Draw the sequence */ if (bvp->DrawGrid) DrawLtGrid(x, y+bvp->LineSpace/2, r.right, y+bvp->LineSpace/2); break; case eTypeAlignSequence: DrawAlignSideLineNumbers(x, y, splp->bioSeqLine, splp->row, bvp, aln_idx); if (last_row == -1 || splp->row < last_row) { /* commented out per indexer request */ /* pct_ids = MemFree (pct_ids); pct_ids = GetAlignmentColumnPercentIDsForAlignmentSection (bvp, splp->bioSeqLine, aln_idx); */ } DrawAlignment(x, y, splp->bioSeqLine, splp->row, buf, seqbuf, alnbuf, bvp, aln_idx, pct_ids); /* Draw the alignment */ if (bvp->DrawGrid) DrawLtGrid(x, y+bvp->LineSpace/2, r.right, y+bvp->LineSpace/2); if (bvp->last_aln_row_clicked == splp->row) { DrawSequenceCaret (x, y, splp->bioSeqLine, bvp); } last_row = splp->row; break; case eTypeAlignDivider: DrawAlignmentDivider (x, y, bvp); aln_idx++; break; case eTypeFeature: if (bvp->DrawGrid) DrawLtGrid(x, y+bvp->LineSpace/2, r.right, y+bvp->LineSpace/2); DrawFeature(x, y, splp->bioSeqLine, splp->row, splp->idx, splp->protProduct, FALSE, bsp, bvp); /* Draw Features */ break; case eTypeFrame1: DrawFrame(x, y, splp->bioSeqLine, 1, bvp); if (bvp->DrawGrid) DrawLtGrid(x, y+bvp->LineSpace/2, r.right, y+bvp->LineSpace/2); break; case eTypeFrame2: DrawFrame(x, y, splp->bioSeqLine, 2, bvp); if (bvp->DrawGrid) DrawLtGrid(x, y+bvp->LineSpace/2, r.right, y+bvp->LineSpace/2); break; case eTypeFrame3: DrawFrame(x, y, splp->bioSeqLine, 3, bvp); if (bvp->DrawGrid) DrawLtGrid(x, y+bvp->LineSpace/2, r.right, y+bvp->LineSpace/2); break; case eTypeFrame4: DrawFrame(x, y, splp->bioSeqLine, 4, bvp); if (bvp->DrawGrid) DrawLtGrid(x, y+bvp->LineSpace/2, r.right, y+bvp->LineSpace/2); break; case eTypeFrame5: DrawFrame(x, y, splp->bioSeqLine, 5, bvp); if (bvp->DrawGrid) DrawLtGrid(x, y+bvp->LineSpace/2, r.right, y+bvp->LineSpace/2); break; case eTypeFrame6: DrawFrame(x, y, splp->bioSeqLine, 6, bvp); if (bvp->DrawGrid) DrawLtGrid(x, y+bvp->LineSpace/2, r.right, y+bvp->LineSpace/2); break; } if(bvp->DrawGrid && lineTotalLines-1 && splp->bioSeqLine!=bvp->SeqPanLines[line+1]->bioSeqLine) DrawDkGrid(x, y+bvp->LineSpace/2, r.right, y+bvp->LineSpace/2); /* Draw Horizontal Grid */ /* draw end */ } else if (bvp->SeqPanLines[line]->lineType == eTypeAlignDivider) { aln_idx++; } y += bvp->LineHeight; } if (bvp->DrawGrid) { DrawDkGrid(bvp->SeqStartPosX, r.top, bvp->SeqStartPosX, r.bottom); /* Draw Vertical Grid */ if (bvp->seqAlignMode) DrawDkGrid(bvp->SeqStartPosX-50, r.top, bvp->SeqStartPosX-50, r.bottom); /* Draw Second Grid */ } if (bvp->seqAlignMode) { MemFree (seqbuf); MemFree (alnbuf); } MemFree (buf); SeqPortFree (spp); pct_ids = MemFree (pct_ids); } static void onDrawSeqPanel (PaneL p) { BioseqViewPtr bvp; bvp = GetBioseqViewPtr (p); if (bvp == NULL) return; DrawSeqPanel (bvp); } static void onVScrollBarSeqPanel (BaR sb, SlatE s, Int4 newval, Int4 oldval) { BioseqViewPtr bvp; RecT r_scroll, r_redraw; Int2 pixels; Int2 lines; Select (s); bvp = GetBioseqViewPtr((PaneL)s); ObjectRect (bvp->seqView, &r_scroll); ObjectRect (bvp->seqView, &r_redraw); InsetRect (&r_scroll, 2, 2); InsetRect (&r_redraw, 2, 2); lines = (r_scroll.bottom - r_scroll.top - 2*SEQ_Y_OFFSET-3) / bvp->LineHeight; if (abs(oldval-newval) > lines) InvalRect(&r_redraw); else { pixels = (oldval - newval) * bvp->LineHeight; if (pixels < 0) { r_scroll.top += SEQ_Y_OFFSET + 2; r_redraw.bottom = r_scroll.bottom = r_scroll.top + lines * bvp->LineHeight + 4; r_redraw.top = r_scroll.bottom-abs(pixels)-bvp->LineHeight; } else { r_redraw.bottom = r_redraw.top + pixels + 2*SEQ_Y_OFFSET; r_scroll.bottom = r_scroll.top + lines * bvp->LineHeight + 6; } ScrollRect (&r_scroll, 0, pixels); InvalRect (&r_redraw); } Update (); } /* extern functions */ PaneL CreateSeqViewPanel (GrouP g, Int2 w, Int2 h) { PaneL pnl = AutonomousPanel4 (g, w, h, onDrawSeqPanel, onVScrollBarSeqPanel, NULL, sizeof (BioseqViewPtr), onCloseSeqPanel, NULL); SetPanelClick(pnl, onSeqViewClick, NULL, NULL, onSeqViewRelease); return pnl; } extern void UpdateSeqViewPanel (PaneL pnl) { BioseqViewPtr bvp; WindoW currentport, temport; bvp = GetBioseqViewPtr(pnl); if (bvp == NULL) return; bvp->salp = SeqAlignFree (bvp->salp); if (Visible (bvp->seqView)) { PopulateAlnView (bvp); currentport = ParentWindow (bvp->seqView); temport = SavePort (currentport); Select (bvp->seqView); inval_panel (bvp->seqView, -1, -1); RestorePort (temport); } } /* New Sequence Editor Functions */ /* This section of the code is for the new sequence editor. * New data types for the new sequence editor include: * * SeqPanPara: a structure to hold information about a "paragraph" of data * for display/editing. Each paragraph represents one line of sequence * data, where the length of the line is determined by the width of the * display window. Depending on the options chosen by the user, a paragraph * could include lines for numbering, lines for features, lines for frames, * and/or a line for the complement, in addition to the main line which * displays the sequence data. * * chapters: a "chapter" is an array of SEQ_PAN_CHAPTER_SIZE SeqPanPara * structures. When the Sequence Editor is first opened, a ValNode list * of enough chapters to hold the entire sequence is created but left * unindexed (i.e., information about features is not collected). If * during the course of editing the sequence more chapters are needed, * these will be appended to the end of the chapter list. Leftover * SeqPanPara entries will have the sequenceLineOffset member set to -1. * A chapter will only be indexed if it is about to be viewed, but it * will retain its information until the editor window is resized. * The scroll position is based on the estimated number of lines for * unindexed paragraphs plus the actual number of lines for indexed * paragraphs. As previously unindexed paragraphs are indexed, the * maximum scroll position is adjusted. * * SeqEdForm: a structure to hold information about the sequence editor * form, including a BioseqView structure (used by functions shared * by the sequence and alignment view panels and the new sequence editor). * * SeqEdJournal: a structure that holds information about changes the user has made * in the past so that these actions may be undone or redone. * */ /* This section of code manages the journal entries used for undo, redo, and cancel. */ /* The SeqEdFormPtr contains two SeqEdJournalPtr members - undo_list and last_journal_entry. * undo_list starts with an eSeqEdJournalStart journal entry and ends with an eSeqEdJournalEnd * journal entry. These entries should not be removed until the SeqEdFormPtr is to be freed. * They are used to indicate that the undo/redo state is at either end. * The last_journal_entry points to the first action to be undone if cancelling or undoing. * If last_journal_entry points to an eSeqEdJournalEnd entry, the previous item is the first action * to be undone. * To redo, start playing entries after the last_journal_entry. */ static void SetUndoRedoStatus (SeqEdFormPtr sefp); /* This function initializes the SeqEdJournalPtr members for SeqEdFormPtr. An initial journal * entry list with a start and end is created, and last_journal_entry points to the end. */ static void InitJournal (SeqEdFormPtr sefp) { sefp->undo_list = (SeqEdJournalPtr) MemNew (sizeof (SeqEdJournalData)); sefp->undo_list->action = eSeqEdJournalStart; sefp->last_journal_entry = (SeqEdJournalPtr) MemNew (sizeof (SeqEdJournalData)); sefp->last_journal_entry->action = eSeqEdJournalEnd; sefp->undo_list->next = sefp->last_journal_entry; sefp->undo_list->prev = NULL; sefp->last_journal_entry->next = NULL; sefp->last_journal_entry->prev = sefp->undo_list; } static Boolean AddJournalEntryEx (ESeqEdJournalAction action, Int4 offset, Int4 num_chars, CharPtr char_data, SeqEdFormPtr sefp, Boolean is_unknown_gap) { SeqEdJournalPtr sejp, prev, end, next; Boolean rval = FALSE; Boolean feats_deleted = FALSE; MsgAnswer ans = ANS_YES; if (sefp == NULL || sefp->last_journal_entry == NULL) return rval; for (end = sefp->last_journal_entry; end != NULL && end->action != eSeqEdJournalEnd; end = end->next) { } if (sefp->last_journal_entry != end) { next = (SeqEdJournalPtr) sefp->last_journal_entry->next; if (next != end) { /* set prev for next in list to NULL */ next->prev = NULL; /* set next for next to last in list to NULL */ ((SeqEdJournalPtr)(end->prev))->next = NULL; /* free middle of list */ SeqEdJournalFree (next); /* reattach end */ sefp->last_journal_entry->next = end; end->prev = sefp->last_journal_entry; } sefp->last_journal_entry = end; } sejp = SeqEdJournalNewSeqEdit (action, offset, num_chars, char_data, sefp->spliteditmode, sefp->bfp->bvd.bsp, sefp->bfp->bvd.bsp->mol, sefp->input_entityID); sejp->unknown_gap = is_unknown_gap; prev = end->prev; prev->next = sejp; sejp->prev = prev; sejp->next = end; end->prev = sejp; rval = PlayJournal (sejp, &sefp->last_journal_entry, 1, &feats_deleted, sefp); if (feats_deleted) { ans = Message (MSG_YN, "You are about to delete one or more features - do you want to continue?"); if (ans == ANS_NO) { rval = UnplayJournal (&sefp->last_journal_entry, 1, sefp); } } SetUndoRedoStatus (sefp); return rval; } static Boolean AddJournalEntry (ESeqEdJournalAction action, Int4 offset, Int4 num_chars, CharPtr char_data, SeqEdFormPtr sefp) { return AddJournalEntryEx (action, offset, num_chars, char_data, sefp, FALSE); } /* This function initializes a previously allocated chapter. The sequenceLineOffset * position values are set with new values, and the paragraphs are set to an * unindexed state. */ static void InitSeqPanChapter (SeqPanParaPtr sppp, Int4 sequenceLineOffset, Int4 total_paragraphs) { Int4 i, j; if (sppp == NULL) return; for (i = 0; i < SEQ_PAN_CHAPTER_SIZE; i++) { if (i + sequenceLineOffset < total_paragraphs) { sppp[i].sequenceLineOffset = i + sequenceLineOffset; } else { sppp[i].sequenceLineOffset = -1; } sppp[i].indexed = FALSE; if (sppp[i].lines != NULL) { for (j = 0; j < sppp[i].num_lines; j++) { MemFree(sppp[i].lines[j]); } sppp[i].lines = MemFree (sppp[i].lines); } sppp[i].num_lines = 0; } } /* This function frees a list of chapters. This should only be done when the * sequence editor window is closed, as freeing the chapter list and generating * a new chapter list is expensive. */ static ValNodePtr FreeChapterList (ValNodePtr chapter_list) { SeqPanParaPtr sppp; if (chapter_list == NULL) return NULL; FreeChapterList (chapter_list->next); chapter_list->next = NULL; sppp = chapter_list->data.ptrvalue; /* InitSeqPanChapter frees the SeqPanelLines in the chapter */ InitSeqPanChapter (sppp, 0, 0); MemFree (sppp); chapter_list->data.ptrvalue = NULL; ValNodeFree (chapter_list); return NULL; } /* This function frees the ValNode lists in the array of ValNode lists * used for calculating the features for each chapter. * This data should only be freed when the sequence editor window is * closed, as the code assumes that this memory has been allocated * and is available for use. */ static ValNodePtr PNTR FreeFeatureLists (ValNodePtr PNTR feature_lists) { Int4 j; if (feature_lists == NULL) { return NULL; } for (j = 0; j < SEQ_PAN_CHAPTER_SIZE; j++) { feature_lists [j] = ValNodeFree (feature_lists [j]); } MemFree (feature_lists); return NULL; } /* This function creates a new chapter (an array of SEQ_PAN_CHAPTER_SIZE SeqPanPara * structures) and initializes them. */ static SeqPanParaPtr CreateNewSeqPanChapter (Int4 sequenceLineOffset, Int4 total_paragraphs) { SeqPanParaPtr sppp; sppp = (SeqPanParaPtr) MemNew (SEQ_PAN_CHAPTER_SIZE * sizeof (SeqPanParaData)); if (sppp != NULL) { InitSeqPanChapter (sppp, sequenceLineOffset, total_paragraphs); } return sppp; } /* This function examines the options from the GUI to determine the number of lines that * will appear in each paragraph other than the feature lines. * This function is used to estimate the size of unindexed paragraphs. */ static Int4 CountCommonLines (BioseqViewPtr bvp) { Int4 num_lines = 1; /* start with one, for sequence */ Int4 i; if (GetValue (bvp->newNumControl) == eNumTop) { num_lines += 2; } /* add lines for frames */ for (i = 0; i < 6; i++) { if (bvp->frames[i]) { num_lines ++; } } /* add lines for complements */ if (bvp->ShowComplement) { num_lines ++; } return num_lines; } /* This function will add chapters to the existing chapter list to accommodate the * number of required chapters. It does not remove unneeded chapters. */ static void CreateSeqPanChapterList (Int2 lineLength, BioseqViewPtr bvp) { ValNodePtr chapter_vnp; Int4 num_paragraphs; Int4 paragraph_count = 0; SeqPanParaPtr chapter; if (bvp == NULL || lineLength == 0) return; num_paragraphs = floor(bvp->bsp->length / lineLength) + 1; /* sequence length */ chapter_vnp = bvp->chapter_list; while (paragraph_count < num_paragraphs) { if (chapter_vnp == NULL) { chapter_vnp = ValNodeNew (bvp->chapter_list); if (bvp->chapter_list == NULL) bvp->chapter_list = chapter_vnp; chapter = CreateNewSeqPanChapter (paragraph_count, num_paragraphs); chapter_vnp->data.ptrvalue = chapter; } else { chapter = chapter_vnp->data.ptrvalue; InitSeqPanChapter (chapter, paragraph_count, num_paragraphs); } if (chapter == NULL || chapter_vnp == NULL) { bvp->chapter_list = FreeChapterList (bvp->chapter_list); return; } paragraph_count += SEQ_PAN_CHAPTER_SIZE; chapter_vnp = chapter_vnp->next; } /* we reuse an array of SEQ_PAN_CHAPTER_SIZE ValNodePtr to calculate the features for * each chapter. This is allocated once and reused until the chapter list is freed. */ if (bvp->feature_lists == NULL) { bvp->feature_lists = (ValNodePtr PNTR) MemNew (SEQ_PAN_CHAPTER_SIZE * sizeof (ValNodePtr)); } bvp->TotalLines = num_paragraphs * CountCommonLines (bvp); } static void AdjustSeqEdScrollBar (BioseqViewPtr bvp) { BaR sb; Int4 curr_pos, max_pos; RecT r; Int4 height, num_visible_lines; if (bvp == NULL) return; sb = GetSlateVScrollBar ((SlatE)bvp->seqView); curr_pos = GetBarValue (sb); ObjectRect (bvp->seqView, &r); InsetRect (&r, SEQ_Y_OFFSET, SEQ_Y_OFFSET); height = r.bottom - r.top; num_visible_lines = height / bvp->LineHeight; max_pos = bvp->TotalLines - num_visible_lines; CorrectBarMax (sb, max_pos); if (curr_pos > max_pos) { SetBarValue (sb, max_pos); } else { SetBarValue (sb, curr_pos); } CorrectBarPage(sb, (height / bvp->LineHeight) - 1, (height / bvp->LineHeight) - 1); } /* This function indexes a paragraph. This function should only be called by IndexSeqPanChapter, * as the sequence editor code frequently makes the assumption that if the first paragraph in a * chapter is indexed, all of the paragraphs in the chapter are indexed. Also, it is more * efficient to calculate the feature_lists for an entire chapter, rather than for individual * paragraphs. */ static void IndexSeqPanPara (BioseqViewPtr bvp, SeqPanParaPtr sppp, ValNodePtr feature_list) { Int4 num_lines, prev_lines; Int4 i; Boolean show_top_scale = FALSE; Boolean show_features = FALSE; ValNodePtr vnp; if (bvp == NULL || sppp == NULL) return; prev_lines = CountCommonLines (bvp); num_lines = prev_lines; if (GetValue (bvp->newNumControl) == eNumTop) { show_top_scale = TRUE; } /* add lines for features */ if (GetValue(bvp->newFeatControl) != eShowFeaturesOff) { show_features = TRUE; num_lines += ValNodeLen (feature_list); } /* allocate lines and create */ sppp->lines = (SeqPanLinePtr PNTR) MemNew (num_lines * sizeof (SeqPanLinePtr)); if (sppp->lines == NULL) return; sppp->num_lines = num_lines; i = 0; if (show_top_scale) { /* Numbers on top */ sppp->lines[i++] = MakeSeqPanLine(eTypeTopSeqNumbers, sppp->sequenceLineOffset); sppp->lines[i++] = MakeSeqPanLine(eTypeTopScaleMarks, sppp->sequenceLineOffset); } sppp->lines[i++] = MakeSeqPanLine(eTypeSequence, sppp->sequenceLineOffset); /* Add sequence line */ if (bvp->ShowComplement) { sppp->lines[i++] = MakeSeqPanLine (eTypeSequenceComplement, sppp->sequenceLineOffset); } if (show_features) { for (vnp = feature_list; vnp != NULL; vnp = vnp->next) { sppp->lines[i] = MakeSeqPanLine (eTypeFeature, sppp->sequenceLineOffset); sppp->lines[i]->idx = vnp->data.intvalue; if (vnp->choice == PROT_PRODUCT_TYPE) { sppp->lines[i]->protProduct = TRUE; sppp->lines[i]->on_the_fly = FALSE; } else if (vnp->choice == PROT_ON_THE_FLY) { sppp->lines[i]->protProduct = TRUE; sppp->lines[i]->on_the_fly = TRUE; } else { sppp->lines[i]->protProduct = FALSE; sppp->lines[i]->on_the_fly = FALSE; } sppp->lines[i]->row = 0; i++; } } if (bvp->frames [0]) sppp->lines[i++] = MakeSeqPanLine (eTypeFrame1, sppp->sequenceLineOffset); if (bvp->frames [1]) sppp->lines[i++] = MakeSeqPanLine (eTypeFrame2, sppp->sequenceLineOffset); if (bvp->frames [2]) sppp->lines[i++] = MakeSeqPanLine (eTypeFrame3, sppp->sequenceLineOffset); if (bvp->frames [3]) sppp->lines[i++] = MakeSeqPanLine (eTypeFrame4, sppp->sequenceLineOffset); if (bvp->frames [4]) sppp->lines[i++] = MakeSeqPanLine (eTypeFrame5, sppp->sequenceLineOffset); if (bvp->frames [5]) sppp->lines[i++] = MakeSeqPanLine (eTypeFrame6, sppp->sequenceLineOffset); sppp->indexed = TRUE; bvp->TotalLines += num_lines - prev_lines; AdjustSeqEdScrollBar (bvp); } /* the array of ValNodePtr lists for each chapter will be reused. */ /* it must have been pre-allocated to SEQ_PAN_CHAPTER_SIZE lists. */ static void GetSeqChapterFeatureInfo (BioseqViewPtr bvp, BioseqPtr bsp, Int2 lineLength, Int4 sequenceLineOffset, Uint2 entityID, ValNodePtr PNTR feature_lists) { Int4 j, start, stop; SeqMgrFeatContext fcontext; SeqFeatPtr sfp = SeqEdGetNextFeature (bsp, NULL, 0, 0, &fcontext, FALSE, FALSE, entityID); Int4 chapter_start, chapter_stop; chapter_start = sequenceLineOffset * lineLength; chapter_stop = chapter_start + SEQ_PAN_CHAPTER_SIZE * lineLength; for (j = 0; j < SEQ_PAN_CHAPTER_SIZE; j++) { feature_lists [j] = ValNodeFree (feature_lists [j]); } while (sfp != NULL) { if (fcontext.seqfeattype != SEQFEAT_PUB && fcontext.seqfeattype != SEQFEAT_BIOSRC && ((fcontext.left >= chapter_start && fcontext.left < chapter_stop) || (fcontext.right >= chapter_start && fcontext.right < chapter_stop) || (fcontext.left <= chapter_start && fcontext.right > chapter_stop))) { Boolean coding = fcontext.seqfeattype == SEQFEAT_CDREGION; Int4 paraFrom = (Int4)floor(fcontext.left / lineLength); /* feature starting paragraph */ Int4 paraTo = (Int4)ceil (fcontext.right / lineLength) + 1; /* feature ending paragraph */ /*BioseqPtr bsp_prot = BioseqFind (SeqLocId(sfp->product));*/ start = SeqLocStart (sfp->location); stop = SeqLocStop (sfp->location); if (paraFrom < sequenceLineOffset) { paraFrom = sequenceLineOffset; } if (paraTo > sequenceLineOffset + SEQ_PAN_CHAPTER_SIZE) { paraTo = sequenceLineOffset + SEQ_PAN_CHAPTER_SIZE; } for (j = paraFrom; j < paraTo; j++) { ValNodeAddInt(&(feature_lists[j - sequenceLineOffset]), fcontext.seqfeattype, fcontext.itemID); if (coding) { ValNodeAddInt(&(feature_lists[j - sequenceLineOffset]), PROT_PRODUCT_TYPE, fcontext.itemID); /* add space for prot product */ if (bvp->on_the_fly) { ValNodeAddInt(&(feature_lists[j - sequenceLineOffset]), PROT_ON_THE_FLY, fcontext.itemID); /* add space for prot product */ } } } } sfp = SeqEdGetNextFeature (bsp, sfp, 0, 0, &fcontext, FALSE, FALSE, entityID); } /* while */ } /* This function indexes a chapter. It should be called whenever a chapter is about to become visible. */ static void IndexSeqPanChapter (BioseqViewPtr bvp, Int4 lineLength, SeqPanParaPtr sppp, Int4 chapter_number, ValNodePtr PNTR feature_lists) { Int4 i; Int4 start; if (sppp == NULL) return; if (sppp->indexed) return; start = chapter_number * SEQ_PAN_CHAPTER_SIZE; /* get features for this block */ GetSeqChapterFeatureInfo (bvp, bvp->bsp, lineLength, start, bvp->seq_entityID, feature_lists); for (i = 0; i < SEQ_PAN_CHAPTER_SIZE && sppp[i].sequenceLineOffset > -1; i++) { IndexSeqPanPara (bvp, sppp + i, feature_lists[i]); } AdjustSeqEdScrollBar (bvp); } /* This function counts the lines assigned to a chapter - either the estimated lines * if the chapter is unindexed, or the actual lines if the chapter is indexed. */ static Int4 CountChapterLines (ValNodePtr chapter_vnp, BioseqViewPtr bvp) { SeqPanParaPtr sppp; Int4 i; Int4 num_lines = 0; if (chapter_vnp == NULL || bvp == NULL) return 0; sppp = (SeqPanParaPtr) chapter_vnp->data.ptrvalue; if (sppp == NULL) return 0; if (sppp->indexed) { for (i = 0; i < SEQ_PAN_CHAPTER_SIZE; i++) { num_lines += sppp[i].num_lines; } } else { num_lines = SEQ_PAN_CHAPTER_SIZE * CountCommonLines (bvp); } return num_lines; } static void UnindexSeqPanChapter (BioseqViewPtr bvp, ValNodePtr chapter_vnp, Int4 chapter_number) { Int4 new_lines; Int4 old_lines; Int4 num_paragraphs; if (chapter_vnp == NULL || bvp == NULL) return; old_lines = CountChapterLines (chapter_vnp, bvp); num_paragraphs = (Int4) floor(bvp->bsp->length / bvp->CharsAtLine) + 1; /* sequence length */ InitSeqPanChapter ((SeqPanParaPtr) chapter_vnp->data.ptrvalue, chapter_number * SEQ_PAN_CHAPTER_SIZE, num_paragraphs); new_lines = CountChapterLines (chapter_vnp, bvp); bvp->TotalLines -= old_lines - new_lines; AdjustSeqEdScrollBar (bvp); } /* Given a scroll position, find the chapter that that scroll position will fall into. * This function should be used to find the first chapter that will need to be indexed * when drawing. */ static ValNodePtr FindChapterForOffset (BioseqViewPtr bvp, Int4 offset, Int4Ptr chapter_offset, Int4Ptr chapter_number) { Int4 estimated_paragraph_size; Int4 line; ValNodePtr chapter_vnp; SeqPanParaPtr sppp; Int4 j; Int4 pos; estimated_paragraph_size = CountCommonLines (bvp); line = 0; pos = 0; for (chapter_vnp = bvp->chapter_list; chapter_vnp != NULL; chapter_vnp = chapter_vnp->next) { *chapter_offset = line; sppp = (SeqPanParaPtr) chapter_vnp->data.ptrvalue; for (j = 0; j < SEQ_PAN_CHAPTER_SIZE && sppp[j].sequenceLineOffset > -1; j++) { if (sppp[j].indexed) { line += sppp[j].num_lines; } else { line += estimated_paragraph_size; } } if (line > offset) { *chapter_number = pos; return chapter_vnp; } pos++; } return NULL; } /* This function gets the SeqPanLinePtr for the line at scroll position offset. */ static SeqPanLinePtr SeqEdGetSeqPanelLineForOffset (Int4 offset, BioseqViewPtr bvp) { Int4 estimated_paragraph_size; Int4 line; ValNodePtr chapter_vnp; SeqPanParaPtr sppp; Int4 j; Int4 chapter_number; estimated_paragraph_size = CountCommonLines (bvp); line = 0; for (chapter_vnp = bvp->chapter_list, chapter_number = 0; chapter_vnp != NULL; chapter_vnp = chapter_vnp->next, chapter_number++) { sppp = (SeqPanParaPtr) chapter_vnp->data.ptrvalue; if (! sppp->indexed && line + SEQ_PAN_CHAPTER_SIZE * estimated_paragraph_size > offset) { IndexSeqPanChapter (bvp, bvp->CharsAtLine, sppp, chapter_number, bvp->feature_lists); } if (sppp->indexed) { for (j = 0; j < SEQ_PAN_CHAPTER_SIZE && sppp[j].sequenceLineOffset > -1; j++) { if (offset < line + sppp[j].num_lines) { return sppp[j].lines [offset - line]; } line += sppp[j].num_lines; } } else { line += estimated_paragraph_size * SEQ_PAN_CHAPTER_SIZE; } } return NULL; } /* This function gets the scroll position for a given sequence location */ static Int4 SeqEdGetScrollPosForSequencePos (Uint4 sequence_pos, BioseqViewPtr bvp) { Int4 desired_line; Int4 estimated_paragraph_size; Int4 line; ValNodePtr chapter_vnp; SeqPanParaPtr sppp; Int4 j; Int4 chapter_number; Int4 chapter_offset; desired_line = sequence_pos / bvp->CharsAtLine; estimated_paragraph_size = CountCommonLines (bvp); line = 0; for (chapter_vnp = bvp->chapter_list, chapter_number = 0; chapter_vnp != NULL; chapter_vnp = chapter_vnp->next, chapter_number++) { sppp = (SeqPanParaPtr) chapter_vnp->data.ptrvalue; if (desired_line < (chapter_number + 1) * SEQ_PAN_CHAPTER_SIZE) { chapter_offset = desired_line - chapter_number * SEQ_PAN_CHAPTER_SIZE; if (! sppp->indexed) { IndexSeqPanChapter (bvp, bvp->CharsAtLine, sppp, chapter_number, bvp->feature_lists); } for (j = 0; j < chapter_offset; j++) { line += sppp[j].num_lines; } return line; } else if (sppp->indexed) { for (j = 0; j < SEQ_PAN_CHAPTER_SIZE && sppp[j].sequenceLineOffset > -1; j++) { line += sppp[j].num_lines; } } else { line += estimated_paragraph_size * SEQ_PAN_CHAPTER_SIZE; } } return line; } static void onSeqEdVScrollBarSeqPanel (BaR sb, SlatE s, Int4 newval, Int4 oldval) { BioseqViewPtr bvp; RecT r_scroll; Int2 pixels; Int2 lines; ValNodePtr first_chapter_vnp; SeqPanParaPtr sppp; Int4 first_chapter_offset, chapter_number; Int4 bmax, bmax_before; Int4 totallines; Int4 pixels_same; Select (s); bvp = GetBioseqViewPtr((PaneL)s); ObjectRect (bvp->seqView, &r_scroll); /* the SEQ_Y_OFFSET border is blank */ InsetRect (&r_scroll, 4, 4); /* if we are scrolling into an unindexed chapter, we need to index the * new chapter and reset our scroll position */ if (newval != oldval) { first_chapter_vnp = FindChapterForOffset (bvp, newval, &first_chapter_offset, &chapter_number); if (first_chapter_vnp == NULL) return; sppp = (SeqPanParaPtr)first_chapter_vnp->data.ptrvalue; if (sppp == NULL) return; if (! sppp->indexed) { bmax_before = GetBarMax (sb); totallines = bvp->TotalLines; IndexSeqPanChapter (bvp, bvp->CharsAtLine, sppp, chapter_number, bvp->feature_lists); bmax = GetBarMax (sb); newval = bmax * ((double)newval / (double)bmax_before); if (newval > bmax) { newval = bmax; } CorrectBarValue (sb, newval); } } lines = (r_scroll.bottom - r_scroll.top) / bvp->LineHeight; if (abs(oldval-newval) > lines) { /* none of the old lines are visible - redraw the entire page. */ InvalRect(&r_scroll); } else { pixels = (oldval - newval) * bvp->LineHeight; pixels_same = (lines - ABS (oldval - newval)) * bvp->LineHeight; ScrollRect (&r_scroll, 0, pixels); if (pixels < 0) { /* redraw the bottom */ r_scroll.top += pixels_same; } else { /* redraw the top */ r_scroll.bottom += pixels_same; } InsetRect (&r_scroll, -1, -1); InvalRect (&r_scroll); } Update (); } /* This function draws the currently visible paragraph lines. */ static void DrawSeqChapters (BioseqViewPtr bvp) { BaR sb; Int4 start; Int4 first_chapter_offset; Int4 line; ValNodePtr first_chapter_vnp, chapter_vnp; Int4 chapter_number = 0; Int4 num_visible_lines; SeqPanParaPtr sppp; Int4 c_n; Int4 j, k; SeqPanLinePtr splp; PaneL p; RecT r; Int4 x, y; SeqPortPtr spp; Uint1Ptr buf; Int4 para_offset; Int4 seqY = 0; if (bvp == NULL) return; sb = GetSlateVScrollBar ((SlatE)bvp->seqView); start = GetBarValue (sb); p = bvp->seqView; spp = SeqPortNew (bvp->bsp, 0, bvp->bsp->length-1, Seq_strand_plus, Seq_code_iupacna); buf = MemNew (SEQ_GROUP_SIZE+1); ObjectRect (p, &r); InsetRect (&r, SEQ_Y_OFFSET, SEQ_Y_OFFSET); x = r.left + 1; y = r.top + bvp->LineHeight; SelectFont ((FonT)(bvp->displayFont)); num_visible_lines = (r.bottom - r.top) / bvp->LineHeight; /* index all the chapters that are visible */ first_chapter_vnp = FindChapterForOffset (bvp, start, &first_chapter_offset, &chapter_number); if (first_chapter_vnp == NULL) return; for (chapter_vnp = first_chapter_vnp, line = first_chapter_offset, c_n = chapter_number; chapter_vnp != NULL && line < start + num_visible_lines; chapter_vnp = chapter_vnp->next, c_n++) { sppp = (SeqPanParaPtr) chapter_vnp->data.ptrvalue; IndexSeqPanChapter (bvp, bvp->CharsAtLine, sppp, c_n, bvp->feature_lists); for (j = 0; j < SEQ_PAN_CHAPTER_SIZE && sppp[j].sequenceLineOffset > -1 && line < start + num_visible_lines; j++) { /* if this paragraph is not visible, skip it */ if (line + sppp[j].num_lines < start) { line += sppp[j].num_lines; continue; } /* skip over lines that are not visible in this paragraph */ if (line < start) { para_offset = start - line; } else { para_offset = 0; } for (k = line + para_offset; k < start + num_visible_lines && k - line < sppp[j].num_lines; k++) { /* DrawMarker (x, y, bvp->LineHeight); */ splp = sppp[j].lines [k - line]; switch ( splp->lineType ) { case eTypeTopSeqNumbers: if (bvp->DrawGrid) DrawLtGrid(bvp->SeqStartPosX+1, y+bvp->LineSpace/2, r.right, y+bvp->LineSpace/2); DrawTopSeqNums(x, y, splp->bioSeqLine, bvp); /* Draw top numbering */ break; case eTypeTopScaleMarks: if (bvp->DrawGrid) DrawLtGrid(bvp->SeqStartPosX+1, y+bvp->LineSpace/2, r.right, y+bvp->LineSpace/2); DrawTopScaleMarks(x, y, splp->bioSeqLine, bvp); /* Draw top scale marks */ break; case eTypeSequence: if (GetValue(bvp->newNumControl) != eNumNone) DrawSeqSideLineNumbers(x, y, splp->bioSeqLine, bvp); /* Draw line numbers */ DrawSequence(x, y, splp->bioSeqLine, spp, buf, bvp); /* Draw the sequence */ if (bvp->DrawGrid) DrawLtGrid(x, y+bvp->LineSpace/2, r.right, y+bvp->LineSpace/2); DrawSequenceCodonBoundaries (x, y, bvp->frame_for_codon_draw, splp->bioSeqLine, bvp); seqY = y; break; case eTypeSequenceComplement: DrawSequenceComplement(x, y, splp->bioSeqLine, spp, buf, bvp); /* Draw the sequence */ if (bvp->DrawGrid) DrawLtGrid(x, y+bvp->LineSpace/2, r.right, y+bvp->LineSpace/2); break; case eTypeFeature: if (bvp->DrawGrid) DrawLtGrid(x, y+bvp->LineSpace/2, r.right, y+bvp->LineSpace/2); DrawFeature(x, y, splp->bioSeqLine, splp->row, splp->idx, splp->protProduct, splp->on_the_fly, bvp->bsp, bvp); /* Draw Features */ DrawFeatureCodonLines (x, y, splp->bioSeqLine, splp->row, seqY, splp->idx, splp->protProduct, bvp->bsp, bvp); break; case eTypeFrame1: DrawFrame(x, y, splp->bioSeqLine, 1, bvp); if (bvp->DrawGrid) DrawLtGrid(x, y+bvp->LineSpace/2, r.right, y+bvp->LineSpace/2); break; case eTypeFrame2: DrawFrame(x, y, splp->bioSeqLine, 2, bvp); if (bvp->DrawGrid) DrawLtGrid(x, y+bvp->LineSpace/2, r.right, y+bvp->LineSpace/2); break; case eTypeFrame3: DrawFrame(x, y, splp->bioSeqLine, 3, bvp); if (bvp->DrawGrid) DrawLtGrid(x, y+bvp->LineSpace/2, r.right, y+bvp->LineSpace/2); break; case eTypeFrame4: DrawFrame(x, y, splp->bioSeqLine, 4, bvp); if (bvp->DrawGrid) DrawLtGrid(x, y+bvp->LineSpace/2, r.right, y+bvp->LineSpace/2); break; case eTypeFrame5: DrawFrame(x, y, splp->bioSeqLine, 5, bvp); if (bvp->DrawGrid) DrawLtGrid(x, y+bvp->LineSpace/2, r.right, y+bvp->LineSpace/2); break; case eTypeFrame6: DrawFrame(x, y, splp->bioSeqLine, 6, bvp); if (bvp->DrawGrid) DrawLtGrid(x, y+bvp->LineSpace/2, r.right, y+bvp->LineSpace/2); break; } y += bvp->LineHeight; } if(bvp->DrawGrid && k == sppp[j].num_lines) { DrawDkGrid(x, y+bvp->LineSpace/2, r.right, y+bvp->LineSpace/2); /* Draw Horizontal Grid */ } line += sppp[j].num_lines; } } } #define SEQ_ED_PRINT_SEQ_OFFSET 15 static void PrintMinusProtein (CharPtr dest_str, Int4 row, SeqMgrFeatContext fcontext, Int4 interval_offset, Int4 bsStart, Int4 bsFinish, Int4 frame, CharPtr str_prot, BioseqViewPtr bvp) { Int4 product_start, k; Int4 prot_pos; Int4 prot_len; Int4 aln_pos_right, aln_pos_left; Int4 product_pos; if (dest_str == NULL) return; product_start = 0; if (str_prot == NULL || interval_offset >= fcontext.numivals) return; prot_len = StringLen (str_prot); for (k = 0; k < interval_offset; k++) { product_start += fcontext.ivals [2 * k] - fcontext.ivals [2 * k + 1] + 1; } /* in the alignment coordinate system, find the mapping for the right end of the * interval. */ aln_pos_right = x_Coord(bvp, fcontext.ivals [2 * interval_offset], row); /* does this interval extend into the next line? */ if (aln_pos_right > bsFinish - 1) { if (bvp->seqAlignMode) { /* need to find out how much of the product appears in lines after this one. * Can't simply subtract the distance, because we can't count the gap characters * as part of the product. */ for (k = fcontext.ivals [2 * interval_offset]; k >= fcontext.ivals [2 * interval_offset + 1]; k--) { if (x_Coord (bvp, k, row) <= bsFinish) { break; } } product_start += fcontext.ivals [2 * interval_offset] - k + 1; } else { /* how much of the product appears in lines after this one? */ product_start += fcontext.ivals [ 2 * interval_offset] - bsFinish + 1; } } product_pos = product_start; product_pos -= frame - 1; aln_pos_left = x_Coord(bvp, fcontext.ivals [2 * interval_offset + 1], row); if (aln_pos_right > bsFinish - 1) { aln_pos_right = bsFinish - 1; } if (aln_pos_left < bsStart) { aln_pos_left = bsStart; } /* we need to step through the alignment coordinates */ for (k = aln_pos_right; k >= aln_pos_left; k--) { /* Check for gaps in this feature if in alignment mode */ if (bvp->seqAlignMode && AlnMgr2MapSeqAlignToBioseq(bvp->salp, k, row) < 0) { dest_str [k - bsStart] = '-'; continue; } else { prot_pos = product_pos / 3; if (prot_pos >= prot_len) { continue; } if (product_pos % 3 == 1) { dest_str [k - bsStart] = str_prot [prot_pos]; } product_pos ++; } } } static void PrintPlusProtein (CharPtr dest_str, Int4 row, SeqMgrFeatContext fcontext, Int4 interval_offset, Int4 bsStart, Int4 bsFinish, Int4 frame, CharPtr str_prot, BioseqViewPtr bvp) { Int4 product_start, k; Int4 prot_pos; Int4 prot_len; Int4 aln_pos_right, aln_pos_left; Int4 product_pos; product_start = 0; if (str_prot == NULL || interval_offset >= fcontext.numivals) return; prot_len = StringLen (str_prot); for (k = 0; k < interval_offset; k++) { product_start += fcontext.ivals [2 * k + 1] - fcontext.ivals [2 * k] + 1; } /* in the alignment coordinate system, find the mapping for the right end of the * interval. */ aln_pos_right = x_Coord(bvp, fcontext.ivals [2 * interval_offset + 1], row); aln_pos_left = x_Coord (bvp, fcontext.ivals [2 * interval_offset], row); /* does this interval extend into the previous line? */ if (aln_pos_left < bsStart) { if (bvp->seqAlignMode) { /* need to find out how much of the product appears in lines before this one. * Can't simply subtract the distance, because we can't count the gap characters * as part of the product. */ for (k = fcontext.ivals [2 * interval_offset]; k <= fcontext.ivals [2 * interval_offset + 1]; k++) { if (x_Coord (bvp, k, row) >= bsStart) { break; } } product_start += k - fcontext.ivals [2 * interval_offset]; } else { /* how much of the product appears in lines before this one? */ product_start += bsStart - fcontext.ivals [ 2 * interval_offset]; } } product_pos = product_start; if (frame == 2) { product_pos -= 1; } else if (frame == 3) { product_pos -= 2; } if (aln_pos_right > bsFinish - 1) { aln_pos_right = bsFinish - 1; } if (aln_pos_left < bsStart) { aln_pos_left = bsStart; } /* we need to step through the alignment coordinates */ for (k = aln_pos_left; k <= aln_pos_right; k++) { /* Check for gaps in this feature if in alignment mode */ if (bvp->seqAlignMode && AlnMgr2MapSeqAlignToBioseq(bvp->salp, k, row) < 0) { dest_str [k - bsStart] = '-'; continue; } else { prot_pos = product_pos / 3; if (prot_pos >= prot_len) { continue; } if (product_pos % 3 == 1 && prot_pos >= 0) { dest_str [k - bsStart] = str_prot [prot_pos]; } product_pos ++; } } } static void PrintFeature(CharPtr feature_line, Int4 line, Int4 row, Uint4 itemID, Boolean protProduct, BioseqPtr bsp, BioseqViewPtr bvp) { SeqMgrFeatContext fcontext; SeqFeatPtr sfp; BioseqPtr bsp_prot; CharPtr str_prot; Int4 bsStart, bsFinish, i; Int4 fLeft, fRight, swap; CharPtr no_prot_msg = "Protein sequence is not available"; Int4 aln_row = -1; Uint2 interval_strand; if (bvp->seqAlignMode) { BioseqPtr bsp_tmp = LockNthBioseqInAlignment(bvp->salp, row); sfp = SeqMgrGetDesiredFeature (ObjMgrGetEntityIDForPointer(bsp_tmp), bsp_tmp, itemID, 0, NULL, &fcontext); BioseqUnlock (bsp_tmp); aln_row = row; } else { sfp = SeqMgrGetDesiredFeature (0, bsp, itemID, 0, NULL, &fcontext); } if (sfp == NULL) return; if (feature_line == NULL) return; MemSet (feature_line, ' ', bvp->CharsAtLine + SEQ_ED_PRINT_SEQ_OFFSET); feature_line [bvp->CharsAtLine + SEQ_ED_PRINT_SEQ_OFFSET] = 0; bsStart = line * bvp->CharsAtLine; bsFinish = bsStart + bvp->CharsAtLine; fLeft = x_FeatLeft (bvp, fcontext.left, aln_row); fRight = x_FeatRight(bvp, fcontext.right, aln_row); if (fcontext.label != NULL) { StrNCpy( feature_line, fcontext.label, MIN (12, StringLen (fcontext.label))); } if (protProduct) { bsp_prot = BioseqFind (SeqLocId(sfp->product)); str_prot = GetSequenceByBsp (bsp_prot); if (str_prot == NULL) { StringNCpy (feature_line + SEQ_ED_PRINT_SEQ_OFFSET, no_prot_msg, StringLen (no_prot_msg)); return; } } for (i = 0; i != fcontext.numivals; i++) { Int4 interval_left = fcontext.strand==Seq_strand_minus ? fcontext.ivals[i*2+1] : fcontext.ivals[i*2]; Int4 interval_right = fcontext.strand==Seq_strand_minus ? fcontext.ivals[i*2] : fcontext.ivals[i*2+1]; Int4 aln_interval_left, aln_interval_right; Int4 draw_left; Int4 draw_right; interval_strand = fcontext.strand; if (bvp->seqAlignMode) { aln_interval_left = GetFeatureX(x_Coord(bvp, interval_left, row), bsStart, bsFinish, TRUE ); while (aln_interval_left == -1 && interval_left < interval_right) { interval_left ++; aln_interval_left = GetFeatureX(x_Coord(bvp, interval_left, row), bsStart, bsFinish, TRUE ); } if (aln_interval_left == -1) { continue; } aln_interval_right = GetFeatureX(x_Coord(bvp, interval_right, row), bsStart, bsFinish, FALSE); while (aln_interval_right == -1 && interval_left < interval_right) { interval_right --; aln_interval_right = GetFeatureX(x_Coord(bvp, interval_right, row), bsStart, bsFinish, FALSE); } interval_left = aln_interval_left; interval_right = aln_interval_right; if (interval_left > interval_right) { swap = interval_left; interval_left = interval_right; interval_right = swap; if (interval_strand == Seq_strand_minus) { interval_strand = Seq_strand_plus; } else { interval_strand = Seq_strand_minus; } } } draw_left = MAX (interval_left, bsStart); draw_right = MIN (interval_right, bsFinish - 1); if (interval_left < bsStart && interval_right < bsStart) continue; if (interval_left > bsFinish - 1 && interval_right > bsFinish -1) continue; if (protProduct) { /* draw protein product */ Int4 frame = 1; /* center in group of 3 */ if (sfp->data.choice == SEQFEAT_CDREGION) { CdRegionPtr crp = sfp->data.value.ptrvalue; if (crp != NULL ) { if (crp->frame == 2) frame++; if (crp->frame == 3) frame+=2; } } if (fcontext.strand == Seq_strand_minus) { PrintMinusProtein (feature_line + SEQ_ED_PRINT_SEQ_OFFSET, row, fcontext, i, bsStart, bsFinish, frame, str_prot, bvp); } else { PrintPlusProtein (feature_line + SEQ_ED_PRINT_SEQ_OFFSET, row, fcontext, i, bsStart, bsFinish, frame, str_prot, bvp); } } /* protein product */ else { /* draw ASCII feature line */ if (interval_strand == Seq_strand_minus) { if (interval_left >= draw_left) { MemSet (feature_line + SEQ_ED_PRINT_SEQ_OFFSET + draw_left - bsStart, '<', 1); draw_left ++; } } else { if (interval_right <= draw_right) { MemSet (feature_line + SEQ_ED_PRINT_SEQ_OFFSET + draw_right - bsStart, '>', 1); draw_right --; } } if (draw_right > draw_left) { MemSet (feature_line + SEQ_ED_PRINT_SEQ_OFFSET + draw_left - bsStart, '-', draw_right - draw_left + 1); } } /* feature or product */ } /* for */ } static void PrintTranslatedFrame(CharPtr file_line, Int4 line, Int4 frame, BioseqViewPtr bvp) { SeqFeatPtr fake_cds; ByteStorePtr bs; CharPtr frame_str; Uint1 strand; Int4 seqStart; Int4 bsStart, bsFinish, j; Int4 pPos, frame_len; Char tmp[2]; Char label[50]; Int4 offset; Int4 line_pos; if (file_line == NULL || bvp == NULL) return; MemSet (file_line, ' ', bvp->CharsAtLine + SEQ_ED_PRINT_SEQ_OFFSET); file_line [bvp->CharsAtLine + SEQ_ED_PRINT_SEQ_OFFSET] = 0; seqStart = line * bvp->CharsAtLine; /* determine start of line */ if (frame < 4) { offset = 3 - ((line * bvp->CharsAtLine) % 3) + frame - 1; strand = Seq_strand_plus; } else { offset = 7 - frame + ((bvp->bsp->length - (line * bvp->CharsAtLine)) % 3); strand = Seq_strand_minus; } if (offset > 2) { offset = offset % 3; } if (offset == 2 && line > 0) { offset -= 3; } bsStart = seqStart + offset; bsFinish = (line + 1) * bvp->CharsAtLine + offset; frame_len = bsFinish - bsStart + 1; bsFinish -= frame_len % 3; if (frame_len % 3 == 2 && bsFinish + 3 < bvp->bsp->length) { bsFinish += 3; } /* must not extend past end of sequence */ while (bsFinish > bvp->bsp->length - 1) { bsFinish -= 3; } /* should not extend past end of line */ while (bsFinish > seqStart + bvp->CharsAtLine) { bsFinish -= 3; } frame_len = bsFinish - bsStart + 1; fake_cds = make_fake_cds(bvp->bsp, bsStart, bsFinish, strand); bs = ProteinFromCdRegionEx(fake_cds, TRUE, FALSE); SeqFeatFree(fake_cds); if(bs == NULL) return; frame_str = BSMerge (bs, NULL); bs = BSFree (bs); if (frame_str == NULL) return; frame_len = StringLen (frame_str); if (frame < 4) { sprintf(label, "frame +%d", frame); } else { sprintf (label, "frame %d", 3 - frame); } StringNCpy ((CharPtr)file_line, label, StringLen (label)); tmp[1] = '\0'; if (frame < 4) { for (j = offset + 1, pPos = 0; j < bsFinish && pPos < frame_len; j+=3, pPos ++) { line_pos = SEQ_ED_PRINT_SEQ_OFFSET + j; if (frame_str [pPos] != 0 && line_pos < SEQ_ED_PRINT_SEQ_OFFSET + bvp->CharsAtLine) file_line [line_pos] = frame_str[pPos]; } } else { for (j = offset + 1, pPos = frame_len - 1; j < bsFinish && pPos > -1; j+=3, pPos --) { line_pos = SEQ_ED_PRINT_SEQ_OFFSET + j; if (frame_str [pPos] != 0 && line_pos < SEQ_ED_PRINT_SEQ_OFFSET + bvp->CharsAtLine) file_line [line_pos] = frame_str[pPos]; } } MemFree (frame_str); } static void PrintFrame (CharPtr file_line, Int4 frame, Int4 seq_pos, Int4 seq_end, Int4 CharsAtLine) { Int4 offset, i; if (file_line == NULL) return; MemSet (file_line, ' ', CharsAtLine + SEQ_ED_PRINT_SEQ_OFFSET); if (frame < 1 || frame > 6) return; if (frame < 4) { offset = frame + 3 - seq_pos % 3; offset = offset % 3; for (i = offset; i < CharsAtLine && i + seq_pos < seq_end; i += 3) { file_line [i + SEQ_ED_PRINT_SEQ_OFFSET] = '|'; } } else { frame = frame - 3; if (seq_end > seq_pos + CharsAtLine) { offset = frame + 3 - (seq_end - (seq_pos + CharsAtLine)) % 3; offset = offset % 3; seq_end = seq_pos + CharsAtLine; } else { offset = frame; } for (i = seq_end - offset - seq_pos - 1; i >= 0; i-=3) { file_line [i + SEQ_ED_PRINT_SEQ_OFFSET] = '|'; } } } static void PrintAligmentDivider (CharPtr file_line, Int4 chars_at_line, Int4 blocks_at_line) { Int2 block, offset = SEQ_ED_PRINT_SEQ_OFFSET; if (file_line == NULL) { return; } MemSet (file_line, ' ', chars_at_line + SEQ_ED_PRINT_SEQ_OFFSET); for (block = 0; block != blocks_at_line; block++) { MemSet (file_line + offset, '~', SEQ_GROUP_SIZE); offset += SEQ_GROUP_SIZE; } } static void PrintAlignment (CharPtr file_line, Int4 line, Int4 row, Uint1Ptr seqbuf, Uint1Ptr alnbuf, BioseqViewPtr bvp, Int4 aln_idx) { Int2 block; BioseqPtr bsp; Int4 start = line * bvp->CharsAtLine; Int4 stop = start + bvp->BlocksAtLine * SEQ_GROUP_SIZE; Int4 alnbuf_len; SeqIdPtr best_id; SeqAlignPtr tmp_salp; Int4 i; Int4 offset = SEQ_ED_PRINT_SEQ_OFFSET; if (bvp == NULL) { return; } MemSet (file_line, ' ', bvp->CharsAtLine + SEQ_ED_PRINT_SEQ_OFFSET); for (i=0, tmp_salp = bvp->salp; i < aln_idx && tmp_salp != NULL; i++, tmp_salp = tmp_salp->next) { } if (tmp_salp == NULL) return; bsp = LockNthBioseqInAlignment(tmp_salp, row); AlignmentIntervalToString (tmp_salp, row, start, stop, bvp->TargetRow, bvp->viewWholeEntity, seqbuf, alnbuf, &alnbuf_len, bvp->showAlnSubstitutions); /* Get label */ best_id = SeqIdFindBestAccession (bsp->id); SeqIdWrite (best_id, file_line, PRINTID_TEXTID_ACCESSION, SEQ_ED_PRINT_SEQ_OFFSET - 1); file_line [StringLen (file_line)] = ' '; /* print alignment blocks */ block = 0; for (block = 0; block != bvp->BlocksAtLine; block++) { Int4 len = SEQ_GROUP_SIZE; Int4 from = block * SEQ_GROUP_SIZE; if (from >= alnbuf_len) break; if (from + SEQ_GROUP_SIZE > alnbuf_len) len = alnbuf_len - from; MemCpy(file_line + offset, alnbuf + from, len); offset += SEQ_GROUP_SIZE; } BioseqUnlock (bsp); } static void ShiftToRemoveDataBeforeToAfterFrom (CharPtr file_line, Int4 from, Int4 to, Int4 seq_pos) { Int4 line_len, space_len, i; if (file_line == NULL) return; if (to > seq_pos) { line_len = StringLen (file_line) - SEQ_ED_PRINT_SEQ_OFFSET; if (to < seq_pos + line_len) { file_line [SEQ_ED_PRINT_SEQ_OFFSET + to - seq_pos + 1] = 0; } } space_len = from - seq_pos; if (space_len > 0) { for (i = 0; i < space_len; i++) { file_line [SEQ_ED_PRINT_SEQ_OFFSET + i] = ' '; } } } static void SeqEdPrintTextLineToFile (CharPtr file_line, Int4 from, Int4 to, Int4 seq_pos, FILE *fp) { if (file_line == NULL) return; ShiftToRemoveDataBeforeToAfterFrom (file_line, from, to, seq_pos); if (StringHasNoText (file_line + SEQ_ED_PRINT_SEQ_OFFSET)) { return; } fprintf (fp, "%s\n", file_line); } /* We need to adjust the output so that it starts with from and ends with to, * which means some of the lines may need to be shifted. * Problems: lines from different paragraphs may have different numbers of * feature lines, and if we are constructing a merged paragraph, we will need * to make sure that feature lines for the same features line up. * We could either print on a delay, or have some form of look-ahead to get the next * paragraph... */ static void ExportSequenceText (SeqEdFormPtr sefp, Int4 from, Int4 to, FILE *fp) { Int4 c_n, first_c_n, last_c_n; ValNodePtr chapter_vnp; SeqPanParaPtr sppp; Int4 first_paragraph_number, last_paragraph_number, p_n, l_n; Int4 ctr, k; Uint1Ptr buf; SeqPortPtr spp; BioseqViewPtr bvp; SeqPanLinePtr splp; Int4 seq_pos; Uint1Ptr file_line; Char label[SEQ_ED_PRINT_SEQ_OFFSET]; ValNodePtr curr_para_strings = NULL; Int4 line_shift; if (sefp == NULL) return; bvp = &(sefp->bfp->bvd); line_shift = from % bvp->CharsAtLine; /* find the first chapter and paragraph we'd want to use */ first_c_n = from / (SEQ_PAN_CHAPTER_SIZE * bvp->CharsAtLine); last_c_n = to / (SEQ_PAN_CHAPTER_SIZE * bvp->CharsAtLine); first_paragraph_number = (from % (SEQ_PAN_CHAPTER_SIZE * bvp->CharsAtLine)) / bvp->CharsAtLine; last_paragraph_number = (to % (SEQ_PAN_CHAPTER_SIZE * bvp->CharsAtLine)) / bvp->CharsAtLine; spp = SeqPortNew (bvp->bsp, 0, bvp->bsp->length-1, Seq_strand_plus, Seq_code_iupacna); buf = MemNew (bvp->CharsAtLine + 1); file_line = MemNew (SEQ_ED_PRINT_SEQ_OFFSET + bvp->CharsAtLine + 1); if (file_line == NULL) return; file_line [bvp->CharsAtLine + 13] = 0; for (c_n = 0, chapter_vnp = bvp->chapter_list; chapter_vnp != NULL && c_n <= last_c_n; chapter_vnp = chapter_vnp->next, c_n ++) { if (c_n < first_c_n) { continue; } /* index our chapter */ sppp = (SeqPanParaPtr)chapter_vnp->data.ptrvalue; IndexSeqPanChapter (bvp, bvp->CharsAtLine, sppp, c_n, bvp->feature_lists); if (c_n == last_c_n) { l_n = last_paragraph_number + 1; } else { l_n = SEQ_PAN_CHAPTER_SIZE; } if (c_n > first_c_n) { first_paragraph_number = 0; } for (p_n = first_paragraph_number; p_n < l_n; p_n++) { /* print sequence lines, feature lines, and translation lines - other lines can * be skipped */ curr_para_strings = NULL; for (k = 0; k < sppp [p_n].num_lines; k++) { splp = sppp[p_n].lines [k]; switch ( splp->lineType ) { case eTypeSequence: MemSet (file_line, ' ', bvp->CharsAtLine + SEQ_ED_PRINT_SEQ_OFFSET); seq_pos = (c_n * SEQ_PAN_CHAPTER_SIZE + p_n) * bvp->CharsAtLine; if (seq_pos < from) { sprintf (label, "%d", seq_pos + 1 + line_shift); } else { sprintf (label, "%d", seq_pos + 1); } StringNCpy ((CharPtr)file_line, label, StringLen (label)); ctr = 0; SeqPortSeek (spp, seq_pos, SEEK_SET); ctr = SeqPortRead (spp, file_line + SEQ_ED_PRINT_SEQ_OFFSET, bvp->CharsAtLine); if (ctr > 0) { /* set end to NULL if at end of sequence */ if (ctr < bvp->CharsAtLine) { MemSet(file_line + SEQ_ED_PRINT_SEQ_OFFSET + ctr, '\0', 1); } SeqEdPrintTextLineToFile ((CharPtr)file_line, from, to, seq_pos, fp); if (bvp->frame_for_codon_draw != 0) { PrintFrame ((CharPtr)file_line, bvp->frame_for_codon_draw, (c_n * SEQ_PAN_CHAPTER_SIZE + p_n) * bvp->CharsAtLine, bvp->bsp->length, bvp->CharsAtLine); SeqEdPrintTextLineToFile ((CharPtr)file_line, from, to, seq_pos, fp); } } break; case eTypeFeature: PrintFeature((CharPtr)file_line, splp->bioSeqLine, splp->row, splp->idx, splp->protProduct, bvp->bsp, bvp); SeqEdPrintTextLineToFile ((CharPtr)file_line, from, to, seq_pos, fp); break; case eTypeFrame1: PrintTranslatedFrame((CharPtr)file_line, splp->bioSeqLine, 1, bvp); SeqEdPrintTextLineToFile ((CharPtr)file_line, from, to, seq_pos, fp); break; case eTypeFrame2: PrintTranslatedFrame((CharPtr)file_line, splp->bioSeqLine, 2, bvp); SeqEdPrintTextLineToFile ((CharPtr)file_line, from, to, seq_pos, fp); break; case eTypeFrame3: PrintTranslatedFrame((CharPtr)file_line, splp->bioSeqLine, 3, bvp); SeqEdPrintTextLineToFile ((CharPtr)file_line, from, to, seq_pos, fp); break; case eTypeFrame4: PrintTranslatedFrame((CharPtr)file_line, splp->bioSeqLine, 4, bvp); SeqEdPrintTextLineToFile ((CharPtr)file_line, from, to, seq_pos, fp); break; case eTypeFrame5: PrintTranslatedFrame((CharPtr)file_line, splp->bioSeqLine, 5, bvp); SeqEdPrintTextLineToFile ((CharPtr)file_line, from, to, seq_pos, fp); break; case eTypeFrame6: PrintTranslatedFrame((CharPtr)file_line, splp->bioSeqLine, 6, bvp); SeqEdPrintTextLineToFile ((CharPtr)file_line, from, to, seq_pos, fp); break; case eTypeSequenceComplement: MemSet (file_line, ' ', bvp->CharsAtLine + SEQ_ED_PRINT_SEQ_OFFSET); seq_pos = (c_n * SEQ_PAN_CHAPTER_SIZE + p_n) * bvp->CharsAtLine; sprintf (label, "complement"); StringNCpy ((CharPtr)file_line, label, StringLen (label)); ctr = 0; SeqPortSeek (spp, seq_pos, SEEK_SET); /* clear last message, might have read to end with last sequence line */ spp->lastmsg = 0; ctr = SeqPortRead (spp, file_line + SEQ_ED_PRINT_SEQ_OFFSET, bvp->CharsAtLine); if (ctr > 0) { /* set end to NULL if at end of sequence */ if (ctr < bvp->CharsAtLine) MemSet(file_line + SEQ_ED_PRINT_SEQ_OFFSET + ctr, '\0', 1); /* complement */ complement_string (file_line + SEQ_ED_PRINT_SEQ_OFFSET); SeqEdPrintTextLineToFile ((CharPtr)file_line, from, to, seq_pos, fp); } break; } } fprintf (fp, "\n"); } if (c_n == first_c_n) { first_paragraph_number = 0; } } } /* This function initializes the SeqEdForm structure */ static SeqEdFormPtr SeqEdFormNew (void) { SeqEdFormPtr sefp; sefp = (SeqEdFormPtr) MemNew (sizeof (SeqEdFormData)); if (sefp != NULL) { sefp->bfp = NULL; sefp->spliteditmode = FALSE; sefp->edit_pos_start = 0; sefp->edit_pos_end = 0; sefp->current_pattern = NULL; sefp->gapvnp = NULL; sefp->locked_aln_bioseqs = NULL; } InitJournal (sefp); return sefp; } static void SeqEdScrollToSeqPosition (SeqEdFormPtr sefp, Int4 pos) { BaR sb; Int4 scroll_pos; WindoW currentport, temport; if (sefp == NULL) return; if (pos < 0 || pos > sefp->bfp->bvd.bsp->length) return; sb = GetSlateVScrollBar ((SlatE) sefp->bfp->bvd.seqView); if (sb == NULL) return; scroll_pos = SeqEdGetScrollPosForSequencePos (pos, &(sefp->bfp->bvd)); SetBarValue (sb, scroll_pos); currentport = ParentWindow (sefp->bfp->bvd.seqView); temport = SavePort (currentport); Select (sefp->bfp->bvd.seqView); inval_panel (sefp->bfp->bvd.seqView, -1, -1); RestorePort (temport); } static void SeqEdUpdateStatus (SeqEdFormPtr sefp) { Char str[255]; Int4 seq_pos, seq_end_pos; SeqIdPtr sip; BioseqPtr bsp; Char tmp_buf[42]; Int4 aln_pos, aln_end_pos, aln_len; if (sefp == NULL || sefp->position_label == NULL) return; if (sefp->bfp != NULL && sefp->bfp->bvd.salp != NULL && sefp->bfp->bvd.seqAlignMode) { if (sefp->bfp->bvd.last_aln_row_clicked > 0) { sip = AlnMgr2GetNthSeqIdPtr(sefp->bfp->bvd.salp, sefp->bfp->bvd.last_aln_row_clicked); bsp = BioseqFind (sip); if (bsp != NULL) { sip = SeqIdFindBestAccession (bsp->id); } SeqIdWrite (sip, tmp_buf, PRINTID_TEXTID_ACCESSION, sizeof(tmp_buf) - 1); aln_len = AlnMgr2GetAlnLength(sefp->bfp->bvd.salp, FALSE); if (sefp->edit_pos_start >= aln_len) { sefp->edit_pos_start = aln_len - 1; } aln_pos = sefp->edit_pos_start; aln_end_pos = sefp->edit_pos_end; seq_pos = AlnMgr2MapSeqAlignToBioseq (sefp->bfp->bvd.salp, aln_pos, sefp->bfp->bvd.last_aln_row_clicked); seq_end_pos = AlnMgr2MapSeqAlignToBioseq (sefp->bfp->bvd.salp, aln_end_pos, sefp->bfp->bvd.last_aln_row_clicked); while (aln_pos > -1 && seq_pos < 0) { aln_pos--; seq_pos = AlnMgr2MapSeqAlignToBioseq (sefp->bfp->bvd.salp, aln_pos, sefp->bfp->bvd.last_aln_row_clicked); } while (aln_end_pos < aln_len && seq_end_pos < 0) { seq_end_pos = AlnMgr2MapSeqAlignToBioseq (sefp->bfp->bvd.salp, aln_end_pos, sefp->bfp->bvd.last_aln_row_clicked); aln_end_pos ++; } if (seq_pos < 0 && seq_end_pos >= 0) { seq_pos = 0; } if (seq_pos < 0) { sprintf (str, "%s", tmp_buf); } else if (seq_pos == seq_end_pos) { sprintf (str, "%s %d", tmp_buf, seq_pos); } else { sprintf (str, "%s %d-%d", tmp_buf, seq_pos + 1, seq_end_pos); } } else { str[0] = 0; } } else { if (sefp->edit_pos_start == sefp->edit_pos_end) { sprintf (str, "Position %d", sefp->edit_pos_start); } else { sprintf (str, "Selected %d - %d", sefp->edit_pos_start + 1, sefp->edit_pos_end); } } SetTitle (sefp->position_label, str); } static void SeqEdGoToButton (ButtoN b) { SeqEdFormPtr sefp; Char str [16]; Int4 val; sefp = (SeqEdFormPtr) GetObjectExtra ((WindoW)ParentWindow (b)); if (sefp == NULL || sefp->bfp == NULL) return; GetTitle (sefp->goto_txt, str, 15); if (! CCStrToLong (str, &val)) { return; } if (val < 0) { val = 0; } else if (val > sefp->bfp->bvd.bsp->length) { val = sefp->bfp->bvd.bsp->length; } sefp->edit_pos_start = val; sefp->edit_pos_end = val; SeqEdScrollToSeqPosition (sefp, val); SeqEdUpdateStatus (sefp); } static void SeqEdLookAtButton (ButtoN b) { SeqEdFormPtr sefp; Char str [16]; Int4 val; sefp = (SeqEdFormPtr) GetObjectExtra ((WindoW)ParentWindow (b)); if (sefp == NULL || sefp->bfp == NULL) return; GetTitle (sefp->lookat_txt, str, 15); if (! CCStrToLong (str, &val)) { return; } if (val < 0) { val = 0; } else if (val > sefp->bfp->bvd.bsp->length) { val = sefp->bfp->bvd.bsp->length; } SeqEdScrollToSeqPosition (sefp, val); } static void SeqEdSelectFeatEditMode (PopuP p) { Int2 val; SeqEdFormPtr sefp; sefp = (SeqEdFormPtr) GetObjectExtra ((WindoW)ParentWindow (p)); val = GetValue(p); if (val==1) sefp->spliteditmode = FALSE; else if (val==2) sefp->spliteditmode = TRUE; CaptureSlateFocus ((SlatE) sefp->bfp->bvd.seqView); } static void RepositionSeqEdPanel (WindoW w) { SeqEdFormPtr sefp; RecT rw; /* window rect */ RecT rp; /* panel rect */ RecT rct; /* new rect for panel */ RecT rb; /* button group rect */ Int4 buttonheight, buttonwidth; sefp = (SeqEdFormPtr) GetObjectExtra (w); if (sefp == NULL) return; ObjectRect (w, &rw); GetPosition (sefp->bfp->bvd.seqView, &rp); GetPosition ((GrouP) sefp->lower_button_group, &rb); buttonwidth = rb.right - rb.left; buttonheight = rb.bottom - rb.top; LoadRect ( &rct, rp.left, rp.top, (Int4)(rw.right - rw.left - rp.left), (Int4)(rw.bottom - rw.top - buttonheight - 3 * SEQ_Y_OFFSET)); SetPosition (sefp->bfp->bvd.seqView, &rct ); AdjustPrnt (sefp->bfp->bvd.seqView, &rct, FALSE); LoadRect (&rb, rb.left, rct.bottom + SEQ_Y_OFFSET, rb.left + buttonwidth, rct.bottom + buttonheight + SEQ_Y_OFFSET); SetPosition(sefp->lower_button_group, &rb); AdjustPrnt (sefp->lower_button_group, &rb, FALSE); } static Int4 XCoordToSeqPos (Int2 x, Int2 xcoord, BioseqViewPtr bvp) { Int4 num_chars; Int4 seqXPos; if (bvp == NULL) return 0; xcoord -= x; xcoord -= SEQ_X_OFFSET; xcoord -= bvp->SeqStartPosX; num_chars = xcoord / bvp->CharWidth; seqXPos = 0; while (num_chars > SEQ_GROUP_SIZE) { seqXPos += SEQ_GROUP_SIZE; num_chars -= SEQ_GROUP_SIZE + 1; } seqXPos += num_chars; return seqXPos; } static Int4 SeqEdGetLineForPosition (SeqEdFormPtr sefp, PoinT pt, Int4Ptr x, Int4Ptr y) { BaR sb; RecT rp; Int4 start, screen_offset; Int4 rval; Int4 max; Int4 direction = 0; Int4 screen_lines; if (sefp == NULL || x == NULL || y == NULL) return 0; sb = GetSlateVScrollBar ((SlatE)sefp->bfp->bvd.seqView); max = GetBarMax (sb); ObjectRect (sefp->bfp->bvd.seqView, &rp); InsetRect (&rp, SEQ_Y_OFFSET, SEQ_Y_OFFSET); start = GetBarValue (sb); screen_offset = (pt.y - rp.top) / sefp->bfp->bvd.LineHeight; if (screen_offset < 0) { if (start > 0) { direction = -1; rval = start - 1; } else { rval = 0; } } else if (pt.y >= rp.bottom - sefp->bfp->bvd.LineHeight) { screen_lines = (rp.bottom - rp.top) / sefp->bfp->bvd.LineHeight; if (start < max) { direction = 1; rval = start + screen_lines + 1; } else { rval = sefp->bfp->bvd.TotalLines - 1; } } else { rval = start + screen_offset; } *x = XCoordToSeqPos (rp.left, pt.x, &(sefp->bfp->bvd)); if (rval > sefp->bfp->bvd.TotalLines - 1) { rval = sefp->bfp->bvd.TotalLines - 1; } *y = rval; return direction; } static Int4 FindClickedFeatureInterval (Int4 seq_pos, SeqMgrFeatContext fcontext, BoolPtr is_left_end, BoolPtr is_right_end) { Int4 j = 0; if (fcontext.ivals == NULL || is_left_end == NULL || is_right_end == NULL) return -1; for (j = 0; j < fcontext.numivals; j ++) { if (seq_pos >= fcontext.ivals [2 * j] && seq_pos <= fcontext.ivals [2 * j + 1]) { /* inside plus strand interval */ if (seq_pos == fcontext.ivals [2 * j]) { *is_left_end = TRUE; } else { *is_left_end = FALSE; } if (seq_pos == fcontext.ivals [2 * j + 1]) { *is_right_end = TRUE; } else { *is_right_end = FALSE; } return j; } else if (seq_pos >= fcontext.ivals [2 * j + 1] && seq_pos <= fcontext.ivals [2 * j]) { /* inside minus strand interval */ if (seq_pos == fcontext.ivals [2 * j + 1]) { *is_left_end = TRUE; } else { *is_left_end = FALSE; } if (seq_pos == fcontext.ivals [2 * j]) { *is_right_end = TRUE; } else { *is_right_end = FALSE; } return j; } } return -1; } static void SeqEdTranslateAndJournalOneCDS (SeqFeatPtr sfp, SeqEdFormPtr sefp) { SeqEdJournalPtr end, next, prev, sejp; if (sefp == NULL) return; /* find correct position in journal list */ for (end = sefp->last_journal_entry; end != NULL && end->action != eSeqEdJournalEnd; end = end->next) { } if (sefp->last_journal_entry != end) { next = (SeqEdJournalPtr) sefp->last_journal_entry->next; if (next != end) { /* set prev for next in list to NULL */ next->prev = NULL; /* set next for next to last in list to NULL */ ((SeqEdJournalPtr)(end->prev))->next = NULL; /* free middle of list */ SeqEdJournalFree (next); /* reattach end */ sefp->last_journal_entry->next = end; end->prev = sefp->last_journal_entry; } sefp->last_journal_entry = end; } sejp = SeqEdJournalNewTranslate (sfp, sefp->bfp->bvd.bsp, sefp->input_entityID); prev = end->prev; prev->next = sejp; sejp->prev = prev; sejp->next = end; end->prev = sejp; sefp->last_journal_entry = sejp; SeqEdTranslateOneCDS (sfp, sefp->bfp->bvd.bsp, sefp->input_entityID, Sequin_GlobalAlign2Seq); SetUndoRedoStatus (sefp); } static void SeqEdTranslateCDSCmd (SeqEdFormPtr sefp) { SeqFeatPtr sfp; SeqMgrFeatContext fcontext; SelStructPtr sel; if (sefp == NULL || sefp->bfp == NULL) return; for (sel = sefp->bfp->bvd.sel_list; sel != NULL; sel = sel->next) { if (sel->itemtype != OBJ_SEQFEAT) { continue; } sfp = SeqMgrGetDesiredFeature (0, sefp->bfp->bvd.bsp, sel->itemID, 0, NULL, &fcontext); SeqEdTranslateAndJournalOneCDS (sfp, sefp); } Select (sefp->bfp->bvd.seqView); inval_panel (sefp->bfp->bvd.seqView, -1, -1); CaptureSlateFocus ((SlatE) sefp->bfp->bvd.seqView); } static void SeqEdTranslateCDSBtn (ButtoN b) { SeqEdFormPtr sefp; sefp = (SeqEdFormPtr) GetObjectExtra (b); SeqEdTranslateCDSCmd (sefp); } static void SeqEdTranslateCDSItem (IteM i) { SeqEdFormPtr sefp; sefp = (SeqEdFormPtr) GetObjectExtra (i); SeqEdTranslateCDSCmd (sefp); } static Int4 FindBestNonGapPosition (Int4 seq_offset, BioseqPtr bsp, Boolean push_left) { DeltaSeqPtr dsp; Int4 cum_offset = 0, seg_len; SeqLocPtr slp; SeqLitPtr slip; if (seq_offset < 0 || bsp == NULL) { return 0; } else if (seq_offset > bsp->length) { return bsp->length; } else if (bsp->repr != Seq_repr_delta || bsp->seq_ext_type != 4) { return seq_offset; } dsp = (DeltaSeqPtr) bsp->seq_ext; while (dsp != NULL) { seg_len = 0; if (dsp->choice == 1) { /* SeqLoc */ slp = (SeqLocPtr)(dsp->data.ptrvalue); seg_len = SeqLocLen (slp); if (seq_offset >= cum_offset && seq_offset < cum_offset + seg_len) { return seq_offset; } cum_offset += seg_len; } else if (dsp->choice == 2) { slip = (SeqLitPtr) (dsp->data.ptrvalue); seg_len = slip->length; if (seq_offset >= cum_offset && seq_offset < cum_offset + seg_len) { if ((slip->seq_data == NULL || slip->seq_data_type == Seq_code_gap) && slip->fuzz != NULL && slip->fuzz->choice == 4) { if (push_left) { return cum_offset; } else { return cum_offset + seg_len; } } else { return seq_offset; } } cum_offset += seg_len; } dsp = dsp->next; } return cum_offset; } static void RemapSeqEdIntervalForGap (SeqEdFormPtr sefp) { Int4 start_remap, end_remap; if (sefp == NULL || sefp->bfp == NULL || sefp->bfp->bvd.bsp == NULL || sefp->bfp->bvd.bsp->repr != Seq_repr_delta || sefp->bfp->bvd.bsp->seq_ext_type != 4) { return; } /* cannot select nucleotides inside a gap of unknown length. * selection must include all of a gap of unknown length or none * of a gap of unknown length. */ start_remap = FindBestNonGapPosition (sefp->edit_pos_start, sefp->bfp->bvd.bsp, TRUE); if (sefp->edit_pos_start == sefp->edit_pos_end) { sefp->edit_pos_start = start_remap; sefp->edit_pos_end = start_remap; sefp->edit_pos_orig = start_remap; } else { end_remap = FindBestNonGapPosition (sefp->edit_pos_end, sefp->bfp->bvd.bsp, FALSE); if (sefp->edit_pos_start == sefp->edit_pos_orig) { sefp->edit_pos_orig = start_remap; } else { sefp->edit_pos_orig = end_remap; } sefp->edit_pos_start = start_remap; sefp->edit_pos_end = end_remap; } } static void SeqEdOnClick (PaneL pnl, PoinT pt) { WindoW w; SeqEdFormPtr sefp; Int4 direction; Int4 x, y; SeqPanLinePtr splp; SeqMgrFeatContext fcontext; SeqFeatPtr sfp; Boolean is_double_click; Boolean is_left_end, is_right_end; Boolean partial5, partial3; w = ParentWindow(pnl); if (w == NULL) return; sefp = (SeqEdFormPtr) GetObjectExtra (w); if (sefp == NULL) return; /* need to get double_click state before functions that might call * CountCommonLines, which checks the state of popups, which clears * the dblClick flag */ is_double_click = dblClick; direction = SeqEdGetLineForPosition (sefp, pt, &x, &y); splp = SeqEdGetSeqPanelLineForOffset (y, &(sefp->bfp->bvd)); if (splp->lineType == eTypeSequence) { sefp->feature_to_drag = NULL; sefp->feature_orig_loc = SeqLocFree (sefp->feature_orig_loc); if (x < 0) { sefp->edit_pos_start = 0; sefp->edit_pos_end = sefp->bfp->bvd.bsp->length; sefp->edit_pos_orig = sefp->edit_pos_start; } else { sefp->edit_pos_start = x + splp->bioSeqLine * sefp->bfp->bvd.CharsAtLine; if (sefp->edit_pos_start > sefp->bfp->bvd.bsp->length) { sefp->edit_pos_start = sefp->bfp->bvd.bsp->length; } sefp->edit_pos_end = sefp->edit_pos_start; sefp->edit_pos_orig = sefp->edit_pos_start; } RemapSeqEdIntervalForGap (sefp); Select (sefp->bfp->bvd.seqView); inval_panel (sefp->bfp->bvd.seqView, -1, -1); SeqEdUpdateStatus (sefp); CaptureSlateFocus ((SlatE) sefp->bfp->bvd.seqView); } else if (splp->lineType == eTypeFeature) { /* make sure this is a feature that is "real" (i.e., not a gap, which we can't edit) */ sfp = SeqMgrGetDesiredFeature (0, sefp->bfp->bvd.bsp, splp->idx, 0, NULL, &fcontext); if (sfp == NULL || sfp->idx.subtype == FEATDEF_gap) { return; } if (is_double_click) { sefp->feature_to_drag = NULL; sefp->feature_orig_loc = SeqLocFree (sefp->feature_orig_loc); WatchCursor (); Update (); GatherProcLaunch (OMPROC_EDIT, FALSE, sfp->idx.entityID, splp->idx, OBJ_SEQFEAT, 0, 0, OBJ_SEQFEAT, 0); ArrowCursor (); Update (); } else { if (!isSelected (sefp->bfp->bvd.bsp->idx.entityID, splp->idx, OBJ_SEQFEAT, &(sefp->bfp->bvd))) { SeqEdSelectFeature ( &(sefp->bfp->bvd), splp->idx); } else { sefp->bfp->bvd.sel_list = SelStructListFree (sefp->bfp->bvd.sel_list); } sefp->feature_to_drag = SeqMgrGetDesiredFeature (0, sefp->bfp->bvd.bsp, splp->idx, 0, NULL, &fcontext); sefp->feature_orig_loc = SeqLocFree (sefp->feature_orig_loc); sefp->feature_drag_interval = FindClickedFeatureInterval (x + splp->bioSeqLine * sefp->bfp->bvd.CharsAtLine, fcontext, &is_left_end, &is_right_end); if (is_left_end) { sefp->feature_drag_type = eLeftEnd; } else if (is_right_end) { sefp->feature_drag_type = eRightEnd; } else { sefp->feature_drag_type = eSlide; } sefp->feature_orig_loc = SeqLocMerge (sefp->bfp->bvd.bsp, sefp->feature_to_drag->location, NULL, FALSE, FALSE, FALSE); CheckSeqLocForPartial (sefp->feature_to_drag->location, &partial5, &partial3); SetSeqLocPartial (sefp->feature_orig_loc, partial5, partial3); sefp->feature_drag_origin = x + splp->bioSeqLine * sefp->bfp->bvd.CharsAtLine; sefp->last_drag_change = 0; Select (sefp->bfp->bvd.seqView); inval_panel (sefp->bfp->bvd.seqView, -1, -1); CaptureSlateFocus ((SlatE) sefp->bfp->bvd.seqView); } } else if (splp->lineType == eTypeFrame1) { if (sefp->bfp->bvd.frame_for_codon_draw == 1) { sefp->bfp->bvd.frame_for_codon_draw = 0; } else { sefp->bfp->bvd.frame_for_codon_draw = 1; } Select (sefp->bfp->bvd.seqView); inval_panel (sefp->bfp->bvd.seqView, -1, -1); sefp->feature_to_drag = NULL; sefp->feature_orig_loc = SeqLocFree (sefp->feature_orig_loc); CaptureSlateFocus ((SlatE) sefp->bfp->bvd.seqView); } else if (splp->lineType == eTypeFrame2) { if (sefp->bfp->bvd.frame_for_codon_draw == 2) { sefp->bfp->bvd.frame_for_codon_draw = 0; } else { sefp->bfp->bvd.frame_for_codon_draw = 2; } Select (sefp->bfp->bvd.seqView); inval_panel (sefp->bfp->bvd.seqView, -1, -1); sefp->feature_to_drag = NULL; sefp->feature_orig_loc = SeqLocFree (sefp->feature_orig_loc); CaptureSlateFocus ((SlatE) sefp->bfp->bvd.seqView); } else if (splp->lineType == eTypeFrame3) { if (sefp->bfp->bvd.frame_for_codon_draw == 3) { sefp->bfp->bvd.frame_for_codon_draw = 0; } else { sefp->bfp->bvd.frame_for_codon_draw = 3; } Select (sefp->bfp->bvd.seqView); inval_panel (sefp->bfp->bvd.seqView, -1, -1); sefp->feature_to_drag = NULL; sefp->feature_orig_loc = SeqLocFree (sefp->feature_orig_loc); CaptureSlateFocus ((SlatE) sefp->bfp->bvd.seqView); } else if (splp->lineType == eTypeFrame4) { if (sefp->bfp->bvd.frame_for_codon_draw == 4) { sefp->bfp->bvd.frame_for_codon_draw = 0; } else { sefp->bfp->bvd.frame_for_codon_draw = 4; } Select (sefp->bfp->bvd.seqView); inval_panel (sefp->bfp->bvd.seqView, -1, -1); sefp->feature_to_drag = NULL; sefp->feature_orig_loc = SeqLocFree (sefp->feature_orig_loc); CaptureSlateFocus ((SlatE) sefp->bfp->bvd.seqView); } else if (splp->lineType == eTypeFrame5) { if (sefp->bfp->bvd.frame_for_codon_draw == 5) { sefp->bfp->bvd.frame_for_codon_draw = 0; } else { sefp->bfp->bvd.frame_for_codon_draw = 5; } Select (sefp->bfp->bvd.seqView); inval_panel (sefp->bfp->bvd.seqView, -1, -1); sefp->feature_to_drag = NULL; sefp->feature_orig_loc = SeqLocFree (sefp->feature_orig_loc); CaptureSlateFocus ((SlatE) sefp->bfp->bvd.seqView); } else if (splp->lineType == eTypeFrame6) { if (sefp->bfp->bvd.frame_for_codon_draw == 6) { sefp->bfp->bvd.frame_for_codon_draw = 0; } else { sefp->bfp->bvd.frame_for_codon_draw = 6; } Select (sefp->bfp->bvd.seqView); inval_panel (sefp->bfp->bvd.seqView, -1, -1); sefp->feature_to_drag = NULL; sefp->feature_orig_loc = SeqLocFree (sefp->feature_orig_loc); CaptureSlateFocus ((SlatE) sefp->bfp->bvd.seqView); } else { sefp->feature_to_drag = NULL; sefp->feature_orig_loc = SeqLocFree (sefp->feature_orig_loc); CaptureSlateFocus ((SlatE) sefp->bfp->bvd.seqView); } } /* we only need to recalculate the feature lines for the paragraph we have just dragged * the feature ends into or out of. */ static Boolean NeedToReindex (SeqEdFormPtr sefp, Int4 last_change, Int4 this_change) { Int4 left, right; Int4 old_top_line, old_bottom_line; Int4 new_top_line, new_bottom_line; Int4 change_line_top, change_line_bottom; Int4 top_chapter_number, bottom_chapter_number, c_n; BioseqViewPtr bvp; ValNodePtr chapter_vnp; if (sefp == NULL || sefp->feature_to_drag == NULL || last_change == this_change) { return FALSE; } if (! SeqEdGetNthIntervalEndPoints (sefp->feature_orig_loc, sefp->feature_drag_interval, &left, &right)) { return FALSE; } bvp = &(sefp->bfp->bvd); old_top_line = (left + last_change) / bvp->CharsAtLine; new_top_line = (left + this_change) / bvp->CharsAtLine; old_bottom_line = (right + last_change) / bvp->CharsAtLine; new_bottom_line = (right + this_change) / bvp->CharsAtLine; if (old_top_line == new_top_line && old_bottom_line == new_bottom_line) { return FALSE; } if (old_top_line != new_top_line) { change_line_top = MIN (old_top_line, new_top_line); } else { change_line_top = MIN (old_bottom_line, new_bottom_line); } if (old_bottom_line != new_bottom_line) { change_line_bottom = MAX (old_bottom_line, new_bottom_line); } else { change_line_bottom = MAX (old_top_line, new_top_line); } top_chapter_number = change_line_top / SEQ_PAN_CHAPTER_SIZE; bottom_chapter_number = change_line_bottom / SEQ_PAN_CHAPTER_SIZE; for (chapter_vnp = sefp->bfp->bvd.chapter_list, c_n = 0; chapter_vnp != NULL && c_n <= bottom_chapter_number; chapter_vnp = chapter_vnp->next, c_n++) { if (c_n >= top_chapter_number) { UnindexSeqPanChapter (bvp, chapter_vnp, c_n); IndexSeqPanChapter (bvp, bvp->CharsAtLine, (SeqPanParaPtr)chapter_vnp->data.ptrvalue, c_n, bvp->feature_lists); } } return TRUE; } static void ScrollToDragPos (SeqEdFormPtr sefp, Int4 change, Int4 direction) { BioseqViewPtr bvp; Int4 desired_scroll_pos, current_scroll_pos; BaR sb; Int4 bar_max; RecT r; Int4 height, num_visible_lines, paragraph_number = 0, feat_offset; Int4 chapter_number, chapter_offset; ValNodePtr chapter_vnp; SeqPanParaPtr sppp; if (sefp == NULL) return; bvp = &(sefp->bfp->bvd); sb = GetSlateVScrollBar ((SlatE)bvp->seqView); if (sb == NULL) return; bar_max = GetBarMax (sb); desired_scroll_pos = SeqEdGetScrollPosForSequencePos (sefp->feature_drag_origin + change, bvp); if (direction > 0 && desired_scroll_pos < bar_max) { desired_scroll_pos ++; } else if (direction < 0 && desired_scroll_pos > 0) { desired_scroll_pos --; } current_scroll_pos = GetBarValue (sb); if (desired_scroll_pos < current_scroll_pos) { SetBarValue (sb, current_scroll_pos - 1); } else { ObjectRect (bvp->seqView, &r); InsetRect (&r, SEQ_Y_OFFSET, SEQ_Y_OFFSET); height = r.bottom - r.top; num_visible_lines = height / bvp->LineHeight; chapter_vnp = FindChapterForOffset (bvp, desired_scroll_pos, &chapter_offset, &chapter_number); if (chapter_vnp == NULL) { return; } paragraph_number = (sefp->feature_drag_origin + change / bvp->CharsAtLine) % SEQ_PAN_CHAPTER_SIZE; sppp = (SeqPanParaPtr) chapter_vnp->data.ptrvalue; for (feat_offset = 0; feat_offset < sppp[paragraph_number].num_lines && sppp[paragraph_number].lines[feat_offset]->idx != sefp->feature_to_drag->idx.itemID; feat_offset ++) { } if (desired_scroll_pos + feat_offset > current_scroll_pos + num_visible_lines - 2) { SetBarValue (sb, current_scroll_pos + 1); } } } /* we don't want to drag the right end up past the left end * and we don't want to drag the left end down past the right end. */ static Int4 SeqEdCorrectFeatureChange (SeqLocPtr slp, Int4 interval_offset, Int4 change, EMoveType move_type, BioseqPtr bsp) { Int4 left, right; Int4 corrected_change; if (slp == NULL || bsp == NULL) return 0; if (! SeqEdGetNthIntervalEndPoints (slp, interval_offset, &left, &right)) return 0; corrected_change = change; switch (move_type) { case eLeftEnd: if (left + change < 0) { corrected_change = 0 - left; } else if (left + change > bsp->length - 1) { corrected_change = bsp->length - 1 - left; } break; case eRightEnd: if (right + change < 0) { corrected_change = 0 - right; } else if (right + change > bsp->length - 1) { corrected_change = bsp->length - 1 - right; } break; case eSlide: if (change < 0) { if (left + change < 0) { corrected_change = 0 - left; } } else { if (right + change > bsp->length - 1) { corrected_change = bsp->length - 1 - right; } } break; } return corrected_change; } static void SeqEdOnDrag (PaneL pnl, PoinT pt) { WindoW w; SeqEdFormPtr sefp; Int4 direction; Int4 x, y, drag_pos, old_scroll_pos; SeqPanLinePtr splp; BaR sb; Int4 corrected_pos, drag_line; Int4 change, corrected_change; w = ParentWindow(pnl); if (w == NULL) return; sefp = (SeqEdFormPtr) GetObjectExtra (w); if (sefp == NULL) return; direction = SeqEdGetLineForPosition (sefp, pt, &x, &y); splp = SeqEdGetSeqPanelLineForOffset (y, &(sefp->bfp->bvd)); if (splp == NULL) return; if (sefp->feature_to_drag != NULL) { if (!isSelected (sefp->feature_to_drag->idx.entityID, sefp->feature_to_drag->idx.itemID, OBJ_SEQFEAT, &(sefp->bfp->bvd))) { SeqEdSelectFeature ( &(sefp->bfp->bvd), splp->idx); } change = x + splp->bioSeqLine * sefp->bfp->bvd.CharsAtLine - sefp->feature_drag_origin; corrected_change = SeqEdCorrectFeatureChange (sefp->feature_orig_loc, sefp->feature_drag_interval, change, sefp->feature_drag_type, sefp->bfp->bvd.bsp); corrected_pos = sefp->feature_drag_origin + corrected_change; if (corrected_pos < 0) { return; } drag_line = corrected_pos / sefp->bfp->bvd.CharsAtLine; SeqEdFeatureAdjust (sefp->feature_to_drag, sefp->feature_orig_loc, corrected_pos - sefp->feature_drag_origin, sefp->feature_drag_type, sefp->feature_drag_interval, sefp->bfp->bvd.bsp); if (direction < 0 && drag_line > 0) { drag_line --; } if (direction > 0) { drag_line ++; } if (NeedToReindex (sefp, sefp->last_drag_change, corrected_change) || direction != 0) { ScrollToDragPos (sefp, corrected_change, direction); } sefp->last_drag_change = corrected_change; Select (sefp->bfp->bvd.seqView); inval_panel (sefp->bfp->bvd.seqView, -1, -1); CaptureSlateFocus ((SlatE) sefp->bfp->bvd.seqView); } else if (splp->lineType == eTypeSequence) { drag_pos = x + splp->bioSeqLine * sefp->bfp->bvd.CharsAtLine; if (drag_pos >= sefp->edit_pos_orig) { drag_pos++; } if (drag_pos < 0) { drag_pos = 0; } if (drag_pos > sefp->bfp->bvd.bsp->length) { drag_pos = sefp->bfp->bvd.bsp->length; } if (drag_pos < sefp->edit_pos_orig) { sefp->edit_pos_start = drag_pos; sefp->edit_pos_end = sefp->edit_pos_orig; } else { sefp->edit_pos_start = sefp->edit_pos_orig; sefp->edit_pos_end = drag_pos; } RemapSeqEdIntervalForGap (sefp); if (direction != 0) { sb = GetSlateVScrollBar ((SlatE)sefp->bfp->bvd.seqView); old_scroll_pos = GetBarValue (sb); SetBarValue (sb, old_scroll_pos + direction); } Select (sefp->bfp->bvd.seqView); inval_panel (sefp->bfp->bvd.seqView, -1, -1); SeqEdUpdateStatus (sefp); } else { sefp->feature_to_drag = NULL; if (direction != 0) { sb = GetSlateVScrollBar ((SlatE)sefp->bfp->bvd.seqView); old_scroll_pos = GetBarValue (sb); SetBarValue (sb, old_scroll_pos + direction); } } } static void SeqEdOnRelease (PaneL pnl, PoinT pt) { WindoW w; SeqEdFormPtr sefp; SeqEdJournalPtr sejp, prev, end, next; w = ParentWindow(pnl); if (w == NULL) return; sefp = (SeqEdFormPtr) GetObjectExtra (w); if (sefp == NULL || sefp->last_journal_entry == NULL) return; if (sefp->feature_to_drag == NULL) { return; } /* don't bother adding a journal entry if the location didn't change */ if (SeqLocCompare (sefp->feature_to_drag->location, sefp->feature_orig_loc) == SLC_A_EQ_B) { return; } for (end = sefp->last_journal_entry; end != NULL && end->action != eSeqEdJournalEnd; end = end->next) { } if (sefp->last_journal_entry != end) { next = (SeqEdJournalPtr) sefp->last_journal_entry->next; if (next != end) { /* set prev for next in list to NULL */ next->prev = NULL; /* set next for next to last in list to NULL */ ((SeqEdJournalPtr)(end->prev))->next = NULL; /* free middle of list */ SeqEdJournalFree (next); /* reattach end */ sefp->last_journal_entry->next = end; end->prev = sefp->last_journal_entry; } sefp->last_journal_entry = end; } SeqEdRepairIntervalOrder (sefp->feature_to_drag, sefp->bfp->bvd.bsp); sejp = SeqEdJournalNewFeatEdit (eSeqEdFeatMove, sefp->feature_to_drag, sefp->feature_orig_loc, sefp->bfp->bvd.bsp, sefp->bfp->bvd.bsp->mol, sefp->input_entityID); sefp->feature_orig_loc = NULL; sefp->feature_to_drag = NULL; prev = end->prev; prev->next = sejp; sejp->prev = prev; sejp->next = end; end->prev = sejp; sefp->last_journal_entry = sejp; SetUndoRedoStatus (sefp); } static void SetSeqEdPanelClick (SeqEdFormPtr sefp) { if (sefp == NULL) return; SetPanelClick(sefp->bfp->bvd.seqView, SeqEdOnClick, SeqEdOnDrag, NULL, SeqEdOnRelease); } static void SeqAlnToggleItemSelection (BioseqViewPtr bvp, Uint2 entityID, Uint4 itemID, Int2 itemtype) { SelStructPtr sel, prev = NULL; if (bvp->salp == NULL) { return; } if (isSelected (entityID, itemID, itemtype, bvp)) { ObjMgrDeSelect (entityID, itemID, itemtype, 0, NULL); if (entityID == 0) { /* ObjMgr won't handle selected items in the desktop */ sel = bvp->sel_list; while (sel != NULL) { if (sel->entityID == entityID && sel->itemID == itemID && sel->itemtype == itemtype) { if (prev == NULL) { bvp->sel_list = sel->next; } else { prev->next = sel->next; } sel->next = NULL; sel = SelStructListFree (sel); } else { prev = sel; sel = sel->next; } } } } else { if (itemtype == OBJ_BIOSEQ) { ObjMgrAlsoSelect (entityID, itemID, itemtype, 0, NULL); if (entityID == 0) { sel = SelStructNew (entityID, itemID, itemtype, 0, 0, NULL, 0, FALSE); sel->next = bvp->sel_list; bvp->sel_list = sel; } } else { ObjMgrSelect (entityID, itemID, itemtype, 0, NULL); if (entityID == 0) { sel = SelStructNew (entityID, itemID, itemtype, 0, 0, NULL, 0, FALSE); bvp->sel_list = SelStructListFree (bvp->sel_list); bvp->sel_list = sel; } } } } static void SeqAlnOnClick (PaneL pnl, PoinT pt) { WindoW w; SeqEdFormPtr sefp; Int4 direction; Int4 x, y; SeqPanLinePtr splp; SeqIdPtr sip; BioseqPtr bsp; Boolean is_double_click; Boolean is_ctrl; Int4 aln_pos; Int4 row; Int4 idx; Int4 bioSeqLine; SeqEntryPtr oldscope; w = ParentWindow(pnl); if (w == NULL) return; sefp = (SeqEdFormPtr) GetObjectExtra (w); if (sefp == NULL) return; is_double_click = dblClick; is_ctrl = ctrlKey; direction = SeqEdGetLineForPosition (sefp, pt, &x, &y); if (y < 0 || y > sefp->bfp->bvd.TotalLines - 1 || direction != 0) { return; } splp = sefp->bfp->bvd.SeqPanLines [y]; row = splp->row; idx = splp->idx; bioSeqLine = splp->bioSeqLine; if (splp->lineType == eTypeAlignSequence) { sip = AlnMgr2GetNthSeqIdPtr(sefp->bfp->bvd.salp, row); bsp = BioseqFind (sip); if (bsp == NULL) { oldscope = SeqEntrySetScope (NULL); bsp = BioseqFind (sip); SeqEntrySetScope (oldscope); } if (bsp != NULL) { if (!is_ctrl) { /* NOTE - this triggers a resize, which will free the SeqPanLines, * which makes splp invalid! */ ObjMgrDeSelectAll (); } SeqAlnToggleItemSelection (&(sefp->bfp->bvd), bsp->idx.entityID, bsp->idx.itemID, OBJ_BIOSEQ); /* if user double-clicks on sequence, make it the target */ if (is_double_click) { sefp->bfp->bvd.TargetRow = GetAlnRowForBsp (bsp, sefp->bfp->bvd.salp); } inval_panel (sefp->bfp->bvd.seqView, -1, -1); aln_pos = x + bioSeqLine * sefp->bfp->bvd.CharsAtLine; sefp->edit_pos_start = aln_pos; sefp->edit_pos_end = sefp->edit_pos_start; sefp->edit_pos_orig = sefp->edit_pos_start; sefp->bfp->bvd.last_aln_row_clicked = row; SeqEdUpdateStatus (sefp); } } else if (splp->lineType == eTypeFeature) { if (is_double_click) { WatchCursor (); Update (); GatherProcLaunch (OMPROC_EDIT, FALSE, sefp->input_entityID, idx, OBJ_SEQFEAT, 0, 0, OBJ_SEQFEAT, 0); ArrowCursor (); Update (); return; } else { sip = AlnMgr2GetNthSeqIdPtr(sefp->bfp->bvd.salp, row); bsp = BioseqFind (sip); if (bsp != NULL) { SeqAlnToggleItemSelection (&(sefp->bfp->bvd), bsp->idx.entityID, idx, OBJ_SEQFEAT); /* make target sequence the one the feature belongs to */ sefp->bfp->bvd.TargetRow = GetAlnRowForBsp (bsp, sefp->bfp->bvd.salp); Select (sefp->bfp->bvd.seqView); inval_panel (sefp->bfp->bvd.seqView, -1, -1); } } } CaptureSlateFocus ((SlatE) sefp->bfp->bvd.seqView); } static void SeqAlnOnDrag (PaneL pnl, PoinT pt) { WindoW w; SeqEdFormPtr sefp; Boolean is_double_click, is_ctrl; Int4 direction; SeqPanLinePtr splp; Int4 x, y, drag_pos, old_scroll_pos; BaR sb; w = ParentWindow(pnl); if (w == NULL) return; sefp = (SeqEdFormPtr) GetObjectExtra (w); if (sefp == NULL) return; is_double_click = dblClick; is_ctrl = ctrlKey; direction = SeqEdGetLineForPosition (sefp, pt, &x, &y); if (y < 0 || y > sefp->bfp->bvd.TotalLines - 1) { return; } splp = sefp->bfp->bvd.SeqPanLines [y]; if (splp->lineType == eTypeAlignSequence && splp->row == sefp->bfp->bvd.last_aln_row_clicked) { drag_pos = x + splp->bioSeqLine * sefp->bfp->bvd.CharsAtLine; if (drag_pos >= sefp->edit_pos_orig) { drag_pos++; } if (drag_pos < 0) { drag_pos = 0; } if (drag_pos > sefp->bfp->bvd.bsp->length) { drag_pos = sefp->bfp->bvd.bsp->length; } if (drag_pos < sefp->edit_pos_orig) { sefp->edit_pos_start = drag_pos; sefp->edit_pos_end = sefp->edit_pos_orig; } else { sefp->edit_pos_start = sefp->edit_pos_orig; sefp->edit_pos_end = drag_pos; } } if (direction != 0) { sb = GetSlateVScrollBar ((SlatE)sefp->bfp->bvd.seqView); old_scroll_pos = GetBarValue (sb); SetBarValue (sb, old_scroll_pos + direction); } Select (sefp->bfp->bvd.seqView); inval_panel (sefp->bfp->bvd.seqView, -1, -1); SeqEdUpdateStatus (sefp); } static void SetSeqAlnPanelClick (SeqEdFormPtr sefp) { if (sefp == NULL) return; /* SetPanelClick(sefp->bfp->bvd.seqView, SeqAlnOnClick, SeqEdOnDrag, NULL, SeqEdOnRelease);*/ SetPanelClick(sefp->bfp->bvd.seqView, SeqAlnOnClick, SeqAlnOnDrag, NULL, NULL); } static void ResizeSeqEdView (SeqEdFormPtr sefp) { RecT r; Int4 height, width; BioseqViewPtr bvp; BaR sb; Int4 scroll_pos; SeqPanLinePtr splp; Int4 sequence_pos = 0; if (sefp == NULL) return; bvp = &(sefp->bfp->bvd); if (bvp->seqAlignMode) { ResizeSeqView (bvp); SetSeqAlnPanelClick (sefp); return; } sb = GetSlateVScrollBar ((SlatE)bvp->seqView); scroll_pos = GetBarValue(sb); splp = SeqEdGetSeqPanelLineForOffset (scroll_pos, bvp); if (splp != NULL) { sequence_pos = splp->bioSeqLine * bvp->CharsAtLine; } ObjectRect (bvp->seqView, &r); InsetRect (&r, SEQ_Y_OFFSET, SEQ_Y_OFFSET); width = r.right - r.left; height = r.bottom - r.top; bvp->BlocksAtLine = (width - SEQ_X_OFFSET - bvp->SeqStartPosX) / ((SEQ_GROUP_SIZE + 1) * bvp->CharWidth); if (bvp->BlocksAtLine == 0) bvp->BlocksAtLine = 1; /* Always at least 1 block */ bvp->CharsAtLine = SEQ_GROUP_SIZE * bvp->BlocksAtLine; /* This function will add to the chapter list if it is not already big enough. */ CreateSeqPanChapterList (bvp->CharsAtLine, bvp); AdjustSeqEdScrollBar (bvp); scroll_pos = SeqEdGetScrollPosForSequencePos (sefp->edit_pos_start, bvp); SetBarValue (sb, scroll_pos); SetSeqEdPanelClick(sefp); } static void ResizeSeqEditorWindow (WindoW w) { SeqEdFormPtr sefp; WindoW temport; sefp = (SeqEdFormPtr) GetObjectExtra (w); if (sefp == NULL) return; temport = SavePort(w); Select (sefp->bfp->bvd.seqView); RepositionSeqEdPanel (w); if (sefp->bfp->bvd.seqAlignMode) { ResizeSeqView (&(sefp->bfp->bvd)); SetSeqAlnPanelClick (sefp); } else { ResizeSeqEdView (sefp); } Select (sefp->bfp->bvd.seqView); inval_panel (sefp->bfp->bvd.seqView, -1, -1); RestorePort (temport); Update (); return; } static void ChangeSeqEditControls (PopuP p) { SeqEdFormPtr sefp; sefp = (SeqEdFormPtr) GetObjectExtra (p); if (sefp == NULL) return; sefp->bfp->bvd.DrawGrid = GetValue (sefp->bfp->bvd.newGridControl) == 1; ResizeSeqEdView (sefp); Select (sefp->bfp->bvd.seqView); inval_panel (sefp->bfp->bvd.seqView, -1, -1); } static void SeqEdAccept (SeqEdFormPtr sefp) { Uint2 entityID; if (sefp == NULL) return; Hide (sefp->form); entityID = ObjMgrGetEntityIDForPointer (sefp->bfp->bvd.bsp); ObjMgrSetDirtyFlag (entityID, TRUE); ObjMgrSendMsg (OM_MSG_UPDATE, entityID, 0, 0); Remove (sefp->form); Update (); } static void SeqEdAcceptButton (ButtoN b) { SeqEdFormPtr sefp; sefp = (SeqEdFormPtr) GetObjectExtra (b); SeqEdAccept (sefp); } static void SeqEdAcceptMenuItem (IteM i) { SeqEdFormPtr sefp; sefp = (SeqEdFormPtr) GetObjectExtra (i); SeqEdAccept (sefp); } static void SetUndoRedoStatus (SeqEdFormPtr sefp); static void SeqEdCancel (SeqEdFormPtr sefp) { Uint2 entityID; if (sefp == NULL) return; Hide (sefp->form); if (UnplayJournal ( &sefp->last_journal_entry, -1, sefp)) { entityID = ObjMgrGetEntityIDForPointer (sefp->bfp->bvd.bsp); ObjMgrSetDirtyFlag (entityID, TRUE); ObjMgrSendMsg (OM_MSG_UPDATE, entityID, 0, 0); ObjMgrFreeUserData (sefp->input_entityID, sefp->procid, sefp->proctype, sefp->userkey); Remove (sefp->form); Update (); } } static void SeqEdCancelButton (ButtoN b) { SeqEdFormPtr sefp; sefp = (SeqEdFormPtr) GetObjectExtra (b); SeqEdCancel (sefp); } static void SeqEdCancelMenuItem (IteM i) { SeqEdFormPtr sefp; sefp = (SeqEdFormPtr) GetObjectExtra (i); SeqEdCancel (sefp); } static void SeqEdComplement (IteM i) { SeqEdFormPtr sefp; sefp = (SeqEdFormPtr) GetObjectExtra (i); if (sefp == NULL) return; sefp->bfp->bvd.ShowComplement = GetStatus (i); ResizeSeqEdView (sefp); Select (sefp->bfp->bvd.seqView); inval_panel (sefp->bfp->bvd.seqView, -1, -1); } static void SetFrameMenuMulti (SeqEdFormPtr sefp) { if (sefp == NULL) return; /* set all plus flag */ if (sefp->bfp->bvd.frames [0] && sefp->bfp->bvd.frames [1] && sefp->bfp->bvd.frames [2]) { SetStatus (sefp->frames[3], TRUE); } else { SetStatus (sefp->frames[3], FALSE); } /* set all minus flag */ if (sefp->bfp->bvd.frames [3] && sefp->bfp->bvd.frames [4] && sefp->bfp->bvd.frames [5]) { SetStatus (sefp->frames[7], TRUE); } else { SetStatus (sefp->frames[7], FALSE); } /* set all flag */ if (sefp->bfp->bvd.frames [0] && sefp->bfp->bvd.frames [1] && sefp->bfp->bvd.frames [2] && sefp->bfp->bvd.frames [3] && sefp->bfp->bvd.frames [4] && sefp->bfp->bvd.frames [5]) { SetStatus (sefp->frames[8], TRUE); } else { SetStatus (sefp->frames[8], FALSE); } /* set none flag */ if (sefp->bfp->bvd.frames [0] || sefp->bfp->bvd.frames [1] || sefp->bfp->bvd.frames [2] || sefp->bfp->bvd.frames [3] || sefp->bfp->bvd.frames [4] || sefp->bfp->bvd.frames [5]) { SetStatus (sefp->frames[9], FALSE); } else { SetStatus (sefp->frames[9], TRUE); } /* set individual frame flags */ SetStatus (sefp->frames[0], sefp->bfp->bvd.frames [0]); SetStatus (sefp->frames[1], sefp->bfp->bvd.frames [1]); SetStatus (sefp->frames[2], sefp->bfp->bvd.frames [2]); SetStatus (sefp->frames[4], sefp->bfp->bvd.frames [3]); SetStatus (sefp->frames[5], sefp->bfp->bvd.frames [4]); SetStatus (sefp->frames[6], sefp->bfp->bvd.frames [5]); ResizeSeqEdView (sefp); Select (sefp->bfp->bvd.seqView); inval_panel (sefp->bfp->bvd.seqView, -1, -1); } static void SeqEdFrame1 (IteM i) { SeqEdFormPtr sefp; sefp = (SeqEdFormPtr) GetObjectExtra (i); if (sefp == NULL) return; sefp->bfp->bvd.frames [0] = GetStatus (i); SetFrameMenuMulti (sefp); } static void SeqEdFrame2 (IteM i) { SeqEdFormPtr sefp; sefp = (SeqEdFormPtr) GetObjectExtra (i); if (sefp == NULL) return; sefp->bfp->bvd.frames [1] = GetStatus (i); SetFrameMenuMulti (sefp); } static void SeqEdFrame3 (IteM i) { SeqEdFormPtr sefp; sefp = (SeqEdFormPtr) GetObjectExtra (i); if (sefp == NULL) return; sefp->bfp->bvd.frames [2] = GetStatus (i); SetFrameMenuMulti (sefp); } static void SeqEdFrameAllPlus (IteM i) { SeqEdFormPtr sefp; Boolean b; sefp = (SeqEdFormPtr) GetObjectExtra (i); if (sefp == NULL) return; b = GetStatus (i); sefp->bfp->bvd.frames [0] = b; sefp->bfp->bvd.frames [1] = b; sefp->bfp->bvd.frames [2] = b; SetFrameMenuMulti (sefp); } static void SeqEdFrame4 (IteM i) { SeqEdFormPtr sefp; sefp = (SeqEdFormPtr) GetObjectExtra (i); if (sefp == NULL) return; sefp->bfp->bvd.frames [3] = GetStatus (i); SetFrameMenuMulti (sefp); } static void SeqEdFrame5 (IteM i) { SeqEdFormPtr sefp; sefp = (SeqEdFormPtr) GetObjectExtra (i); if (sefp == NULL) return; sefp->bfp->bvd.frames [4] = GetStatus (i); SetFrameMenuMulti (sefp); } static void SeqEdFrame6 (IteM i) { SeqEdFormPtr sefp; sefp = (SeqEdFormPtr) GetObjectExtra (i); if (sefp == NULL) return; sefp->bfp->bvd.frames [5] = GetStatus (i); SetFrameMenuMulti (sefp); } static void SeqEdFrameAllMinus (IteM i) { SeqEdFormPtr sefp; Boolean b; sefp = (SeqEdFormPtr) GetObjectExtra (i); if (sefp == NULL) return; b = GetStatus (i); sefp->bfp->bvd.frames [3] = b; sefp->bfp->bvd.frames [4] = b; sefp->bfp->bvd.frames [5] = b; SetFrameMenuMulti (sefp); } static void SeqEdFrameAll (IteM i) { SeqEdFormPtr sefp; Boolean b; sefp = (SeqEdFormPtr) GetObjectExtra (i); if (sefp == NULL) return; b = GetStatus (i); sefp->bfp->bvd.frames [0] = b; sefp->bfp->bvd.frames [1] = b; sefp->bfp->bvd.frames [2] = b; sefp->bfp->bvd.frames [3] = b; sefp->bfp->bvd.frames [4] = b; sefp->bfp->bvd.frames [5] = b; SetFrameMenuMulti (sefp); } static void SeqEdFrameNone (IteM i) { SeqEdFormPtr sefp; sefp = (SeqEdFormPtr) GetObjectExtra (i); if (sefp == NULL) return; sefp->bfp->bvd.frames [0] = FALSE; sefp->bfp->bvd.frames [1] = FALSE; sefp->bfp->bvd.frames [2] = FALSE; sefp->bfp->bvd.frames [3] = FALSE; sefp->bfp->bvd.frames [4] = FALSE; sefp->bfp->bvd.frames [5] = FALSE; SetFrameMenuMulti (sefp); } static void SeqEdToggleProteinMismatch (IteM i) { SeqEdFormPtr sefp; sefp = (SeqEdFormPtr) GetObjectExtra (i); if (sefp == NULL) return; sefp->bfp->bvd.show_translation_errors = ! sefp->bfp->bvd.show_translation_errors; Select (sefp->bfp->bvd.seqView); inval_panel (sefp->bfp->bvd.seqView, -1, -1); } static void SeqEdToggleProteinOnTheFly (IteM i) { SeqEdFormPtr sefp; sefp = (SeqEdFormPtr) GetObjectExtra (i); if (sefp == NULL) return; sefp->bfp->bvd.on_the_fly = GetStatus (i); ResizeSeqEdView (sefp); Select (sefp->bfp->bvd.seqView); inval_panel (sefp->bfp->bvd.seqView, -1, -1); } static void SeqEdDeleteDeltaSeq (SeqEdFormPtr sefp, Boolean save_clip) { Int4 curr_pos = 0, slip_start, delete_start, delete_len; ESeqEdJournalAction action; SeqLocPtr slp; SeqLitPtr slip = NULL; DeltaSeqPtr dsp, dsp_next; Boolean ok_to_continue = TRUE; Boolean is_unknown_gap; CharPtr clip_string = NULL, tmp_string; Int4 clip_len = 0; if (sefp == NULL || sefp->bfp->bvd.bsp == NULL || sefp->bfp->bvd.bsp->repr != Seq_repr_delta || sefp->bfp->bvd.bsp->seq_ext_type != 4 || sefp->bfp->bvd.bsp->seq_ext == NULL || sefp->edit_pos_start < 0) { return; } dsp = (DeltaSeqPtr) sefp->bfp->bvd.bsp->seq_ext; while (dsp != NULL && curr_pos < sefp->edit_pos_end && ok_to_continue) { dsp_next = dsp->next; if (dsp->data.ptrvalue == NULL) continue; slip_start = curr_pos; slip = NULL; if (dsp->choice == 1) { /* SeqLoc */ slp = (SeqLocPtr)(dsp->data.ptrvalue); curr_pos += SeqLocLen (slp); } else if (dsp->choice == 2) { slip = (SeqLitPtr) (dsp->data.ptrvalue); curr_pos += slip->length; } if (slip != NULL && curr_pos > sefp->edit_pos_start) { is_unknown_gap = FALSE; if (slip->seq_data == NULL || slip->seq_data_type == Seq_code_gap) { action = eSeqEdDeleteGap; if (slip->fuzz != NULL && slip->fuzz->choice == 4) { is_unknown_gap = TRUE; } } else { action = eSeqEdDelete; } if (slip_start < sefp->edit_pos_start) { delete_start = sefp->edit_pos_start; } else { delete_start = slip_start; } if (sefp->edit_pos_end > slip_start + slip->length) { delete_len = slip->length - (delete_start - slip_start); } else { delete_len = sefp->edit_pos_end - delete_start; } if (is_unknown_gap && (delete_start > slip_start || delete_len < slip->length)) { /* don't delete part of an unknown gap. delete if all is selected, * otherwise leave it alone */ if (delete_start > slip_start) { /* we won't be deleting in the unknown gap, so move the cursor to the end */ sefp->edit_pos_start = slip_start + slip->length; } } else { ok_to_continue = AddJournalEntryEx (action, delete_start - clip_len, delete_len, NULL, sefp, is_unknown_gap); clip_len += delete_len; tmp_string = (CharPtr) MemNew ((clip_len + 1) * sizeof (Char)); if (tmp_string != NULL) { if (clip_string != NULL) { StringCpy (tmp_string, clip_string); } if (action == eSeqEdDeleteGap) { MemSet (tmp_string + clip_len - delete_len, 'N', delete_len); } else { StringNCpy (tmp_string, sefp->last_journal_entry->char_data, delete_len); } tmp_string [clip_len] = 0; clip_string = MemFree (clip_string); clip_string = tmp_string; } } } dsp = dsp_next; } if (clip_string != NULL) { if (save_clip) { StringToClipboard (clip_string); } clip_string = MemFree (clip_string); } sefp->edit_pos_end = sefp->edit_pos_start; } static void SeqEdDelete (SeqEdFormPtr sefp, Boolean save_clip) { if (sefp == NULL || sefp->edit_pos_start == sefp->edit_pos_end) return; if (sefp->bfp->bvd.bsp->repr == Seq_repr_delta) { /* construct separate journal entries for gaps and non-gaps */ SeqEdDeleteDeltaSeq (sefp, save_clip); } else { if (AddJournalEntry (eSeqEdDelete, sefp->edit_pos_start, sefp->edit_pos_end - sefp->edit_pos_start, NULL, sefp)) { sefp->edit_pos_end = sefp->edit_pos_start; if (save_clip) { StringToClipboard (sefp->last_journal_entry->char_data); } } } } static void SeqEdCut (SeqEdFormPtr sefp) { SeqEdDelete (sefp, TRUE); ResizeSeqEdView (sefp); Select (sefp->bfp->bvd.seqView); inval_panel (sefp->bfp->bvd.seqView, -1, -1); SeqEdUpdateStatus (sefp); } static void SeqEdCutMenuItem (IteM i) { SeqEdFormPtr sefp; if (i == NULL) return; sefp = (SeqEdFormPtr) GetObjectExtra (i); SeqEdCut (sefp); } static void SeqEdPaste (SeqEdFormPtr sefp) { CharPtr str; CharPtr insert_str; if (sefp == NULL) return; str = ClipboardToString (); insert_str = char_to_insert (str, StringLen (str), sefp->bfp->bvd.bsp->mol); if (insert_str == NULL) return; if (sefp->edit_pos_start != sefp->edit_pos_end) { SeqEdDelete (sefp, FALSE); } if (AddJournalEntry (eSeqEdInsert, sefp->edit_pos_start, StringLen (insert_str), insert_str, sefp)) { sefp->edit_pos_start += StringLen (str); sefp->edit_pos_end += StringLen (str); ResizeSeqEdView (sefp); Select (sefp->bfp->bvd.seqView); inval_panel (sefp->bfp->bvd.seqView, -1, -1); SeqEdUpdateStatus (sefp); } } static void SeqEdPasteMenuItem (IteM i) { SeqEdFormPtr sefp; if (i == NULL) return; sefp = (SeqEdFormPtr) GetObjectExtra (i); SeqEdPaste (sefp); } static void ChooseGapType (GrouP g) { TexT t; t = GetObjectExtra (g); if (t == NULL) { return; } if (GetValue (g) == 2) { Enable (t); } else { Disable (t); } } static void MakeGapFeats ( BioseqPtr bsp, Pointer userdata ) { Char buf [32]; Int4 currpos = 0; BioseqPtr fakebsp = NULL; IntFuzzPtr fuzz; ValNodePtr PNTR gapvnp; ImpFeatPtr ifp; SeqLitPtr litp; SeqAnnotPtr sap = NULL; SeqFeatPtr sfp; SeqIdPtr sip; SeqLocPtr slp; ValNodePtr vnp; if (bsp == NULL || bsp->repr != Seq_repr_delta) return; gapvnp = (ValNodePtr PNTR) userdata; sip = SeqIdFindBest (bsp->id, 0); if (sip == NULL) return; for (vnp = (ValNodePtr)(bsp->seq_ext); vnp != NULL; vnp = vnp->next) { if (vnp->choice == 1) { slp = (SeqLocPtr) vnp->data.ptrvalue; if (slp == NULL) continue; currpos += SeqLocLen (slp); } if (vnp->choice == 2) { litp = (SeqLitPtr) vnp->data.ptrvalue; if (litp == NULL) continue; if ((litp->seq_data == NULL || litp->seq_data_type == Seq_code_gap) && litp->length > 0) { if (fakebsp == NULL) { /* to be freed with MemFree, not BioseqFree */ fakebsp = MemNew (sizeof (Bioseq)); if (fakebsp == NULL) return; sap = SeqAnnotNew (); if (sap == NULL) return; sap->type = 1; fakebsp->annot = sap; ValNodeAddPointer (gapvnp, 0, (Pointer) fakebsp); } ifp = ImpFeatNew (); if (ifp == NULL) continue; ifp->key = StringSave ("gap"); sfp = SeqFeatNew (); if (sfp == NULL) continue; sfp->data.choice = SEQFEAT_IMP; sfp->data.value.ptrvalue = (Pointer) ifp; sfp->next = (SeqFeatPtr) sap->data; sap->data = (Pointer) sfp; fuzz = litp->fuzz; if (fuzz != NULL && fuzz->choice == 4 && fuzz->a == 0) { AddQualifierToFeature (sfp, "estimated_length", "unknown"); sfp->location = AddIntervalToLocation (NULL, sip, currpos, currpos + litp->length - 1, FALSE, FALSE); } else { sprintf (buf, "%ld", (long) litp->length); AddQualifierToFeature (sfp, "estimated_length", buf); sfp->location = AddIntervalToLocation (NULL, sip, currpos, currpos + litp->length - 1, FALSE, FALSE); } } currpos += litp->length; } } } static void FreeSeqEdFormGapFeatList (SeqEdFormPtr sefp) { BioseqPtr bsp; SeqAnnotPtr sap, sapnext; if (sefp == NULL || sefp->gapvnp == NULL) { return; } bsp = (BioseqPtr) sefp->gapvnp->data.ptrvalue; if (bsp != NULL) { sap = bsp->annot; while (sap != NULL) { sapnext = sap->next; SeqAnnotFree (sap); sap = sapnext; } } /* frees fake Bioseq that was created by MemNew, not BioseqNew */ sefp->gapvnp = ValNodeFreeData (sefp->gapvnp); } static void SeqEdReindexGaps (SeqEdFormPtr sefp, BioseqPtr edit_bsp) { if (sefp == NULL || edit_bsp == NULL || edit_bsp->repr != Seq_repr_delta) { return; } FreeSeqEdFormGapFeatList (sefp); MakeGapFeats (edit_bsp, &(sefp->gapvnp)); SeqMgrClearFeatureIndexes (sefp->input_entityID, NULL); SeqMgrIndexFeaturesExEx (sefp->input_entityID, NULL, FALSE, FALSE, sefp->gapvnp); } static void SeqEdInsertGapMenuItem (IteM i) { SeqEdFormPtr sefp; ModalAcceptCancelData acd; WindoW w; GrouP h, g, k, gap_type_grp, c; TexT gap_len_txt; ButtoN b; Boolean done; CharPtr gap_len_str; Int4 gap_type, gap_len; Boolean is_unknown_gap; Boolean changed = FALSE; Char len_text [20]; sefp = (SeqEdFormPtr) GetObjectExtra (i); if (sefp == NULL || sefp->edit_pos_start < 0) { return; } w = MovableModalWindow(-20, -13, -10, -10, "Insert Gap", NULL); h = HiddenGroup (w, -1, 0, NULL); g = HiddenGroup (h, 2, 0, NULL); gap_type_grp = HiddenGroup (g, 0, 2, ChooseGapType); RadioButton (gap_type_grp, "Unknown length"); RadioButton (gap_type_grp, "Known length:"); k = HiddenGroup (g, 0, 2, NULL); StaticPrompt (k, "", 0, popupMenuHeight, programFont, 'l'); if (sefp->edit_pos_end > sefp->edit_pos_start) { sprintf (len_text, "%d", sefp->edit_pos_end - sefp->edit_pos_start); } else { sprintf (len_text, "100"); } gap_len_txt = DialogText (k, len_text, 5, NULL); SetObjectExtra (gap_type_grp, gap_len_txt, NULL); SetValue (gap_type_grp, 1); ChooseGapType (gap_type_grp); c = HiddenGroup (h, 2, 0, NULL); b = PushButton (c, "Accept", ModalAcceptButton); SetObjectExtra (b, &acd, NULL); b = PushButton (c, "Cancel", ModalCancelButton); SetObjectExtra (b, &acd, NULL); AlignObjects (ALIGN_CENTER, (HANDLE) g, (HANDLE) c, NULL); Show (w); Select (w); done = FALSE; while (!done) { acd.accepted = FALSE; acd.cancelled = FALSE; while (!acd.accepted && ! acd.cancelled) { ProcessExternalEvent (); Update (); } ProcessAnEvent (); if (acd.cancelled) { done = TRUE; } else { gap_type = GetValue (gap_type_grp); if (gap_type == 2) { is_unknown_gap = FALSE; } else { is_unknown_gap = TRUE; } gap_len = 100; if (! is_unknown_gap) { gap_len = 0; gap_len_str = SaveStringFromText (gap_len_txt); if (!StringHasNoText (gap_len_str)) { gap_len = atoi (gap_len_str); } gap_len_str = MemFree (gap_len_str); } if (gap_len < 1) { Message (MSG_ERROR, "Gap length must be greater than zero!"); } else { RemapSeqEdIntervalForGap (sefp); SeqEdDelete (sefp, FALSE); AddJournalEntryEx (eSeqEdInsertGap, sefp->edit_pos_start, gap_len, NULL, sefp, is_unknown_gap); changed = TRUE; done = TRUE; } } } Remove (w); if (changed) { ResizeSeqEdView (sefp); Select (sefp->bfp->bvd.seqView); inval_panel (sefp->bfp->bvd.seqView, -1, -1); } } static void SeqEdCopy (SeqEdFormPtr sefp) { SeqLocPtr slp; SeqPortPtr spp; Int4 len; CharPtr str; if (sefp == NULL || sefp->edit_pos_start == sefp->edit_pos_end) return; len = sefp->edit_pos_end - sefp->edit_pos_start + 1; str = (CharPtr) MemNew ((len + 1) * sizeof (Char)); if (str == NULL) return; slp = SeqLocIntNew (sefp->edit_pos_start, sefp->edit_pos_end - 1, Seq_strand_plus, sefp->bfp->bvd.bsp->id); spp = SeqPortNewByLoc (slp, Seq_code_iupacna); SeqPortRead (spp, (Uint1Ptr)str, len); SeqPortFree (spp); SeqLocFree (slp); StringToClipboard (str); } static void SeqEdCopyMenuItem (IteM i) { SeqEdFormPtr sefp; if (i == NULL) return; sefp = (SeqEdFormPtr) GetObjectExtra (i); SeqEdCopy (sefp); } static void SeqEdOnKey (SlatE s, Char ch) { PaneL pnl; WindoW w; SeqEdFormPtr sefp; Int4 new_pos; BaR sb; Int4 scroll_pos; CharPtr str; Int4 del_start, del_stop; if ( (int) ch == 0 ) return; pnl = (PaneL) s; Select (pnl); w = ParentWindow(pnl); if (w == NULL) return; sefp = (SeqEdFormPtr) GetObjectExtra (w); if (sefp == NULL) return; CaptureSlateFocus ((SlatE) sefp->bfp->bvd.seqView); /* later, handle control key combos */ #ifdef WIN_MSWIN if (ch == 3) { SeqEdCopy (sefp); } else if (ch == 24) { SeqEdCut (sefp); } else if (ch == 22) { SeqEdPaste (sefp); } #else if (ctrlKey) { if (ch == 'c') { SeqEdCopy (sefp); } else if (ch == 'x') { SeqEdCut (sefp); } else if (ch == 'v') { SeqEdPaste (sefp); } return; } #endif else { /* look at key pressed - if it's a good sequence character, insert it */ if ( (str = char_to_insert (&ch, 1, sefp->bfp->bvd.bsp->mol)) != NULL) { if (sefp->edit_pos_start != sefp->edit_pos_end) { SeqEdDelete (sefp, FALSE); } if (AddJournalEntry (eSeqEdInsert, sefp->edit_pos_start, StringLen (str), str, sefp)) { sefp->edit_pos_start += StringLen (str); sefp->edit_pos_end += StringLen (str); ResizeSeqEdView (sefp); Select (sefp->bfp->bvd.seqView); inval_panel (pnl, -1, -1); } } else { /* handle movements and deletions */ new_pos = sefp->edit_pos_start; switch (ch) { case NLM_LEFT: new_pos--; break; case NLM_RIGHT: new_pos++; break; case NLM_UP: new_pos -= sefp->bfp->bvd.CharsAtLine; break; case NLM_DOWN: new_pos += sefp->bfp->bvd.CharsAtLine; if (new_pos > sefp->bfp->bvd.bsp->length && new_pos - sefp->bfp->bvd.bsp->length < sefp->bfp->bvd.CharsAtLine) { new_pos = sefp->bfp->bvd.bsp->length; } break; case NLM_DEL: /* handle deletion */ if (sefp->edit_pos_end == sefp->edit_pos_start) { sefp->edit_pos_end = sefp->edit_pos_start + 1; if (sefp->edit_pos_end > sefp->bfp->bvd.bsp->length) { sefp->edit_pos_end = sefp->edit_pos_start; return; } } RemapSeqEdIntervalForGap (sefp); SeqEdDelete (sefp, FALSE); ResizeSeqEdView (sefp); Select (sefp->bfp->bvd.seqView); inval_panel (pnl, -1, -1); break; case NLM_BACK: /* handle backspace */ if (sefp->edit_pos_start == sefp->edit_pos_end) { if (sefp->edit_pos_start == 0) { del_start = -1; } else { del_start = sefp->edit_pos_start - 1; del_stop = sefp->edit_pos_start; } } else { del_start = sefp->edit_pos_start; del_stop = sefp->edit_pos_end; } if (del_start >= 0) { sefp->edit_pos_start = del_start; sefp->edit_pos_end = del_stop; RemapSeqEdIntervalForGap (sefp); new_pos = sefp->edit_pos_start; SeqEdDelete (sefp, FALSE); ResizeSeqEdView (sefp); Select (sefp->bfp->bvd.seqView); inval_panel (pnl, -1, -1); } break; } if (new_pos < 0 || new_pos > sefp->bfp->bvd.bsp->length) { Beep (); } else { sefp->edit_pos_start = new_pos; sefp->edit_pos_end = new_pos; sb = GetSlateVScrollBar (s); if (sb != NULL) { scroll_pos = SeqEdGetScrollPosForSequencePos (sefp->edit_pos_start, &(sefp->bfp->bvd)); SetBarValue (sb, scroll_pos); } Select (sefp->bfp->bvd.seqView); inval_panel (pnl, -1, -1); } } SeqEdUpdateStatus (sefp); } } static void SeqEdFormMessage (ForM f, Int2 mssg) { SeqEdFormPtr sefp; sefp = (SeqEdFormPtr) GetObjectExtra (f); if (sefp != NULL) { switch (mssg) { case VIB_MSG_CLOSE : Beep (); break; default : if (sefp->appmessage != NULL) { sefp->appmessage (f, mssg); } break; } } } static void CleanupSeqEdForm (GraphiC g, VoidPtr data) { SeqEdFormPtr sefp; sefp = (SeqEdFormPtr) data; if (sefp != NULL) { ObjMgrFreeUserData (sefp->input_entityID, sefp->procid, sefp->proctype, sefp->userkey); FreeSeqEdFormGapFeatList (sefp); if (sefp->find_window != NULL) { Remove (sefp->find_window); } BioseqUnlock (sefp->bfp->bvd.bsp); sefp->locked_aln_bioseqs = UnlockFarComponents (sefp->locked_aln_bioseqs); if (sefp->on_close_func != NULL) { (sefp->on_close_func)(sefp->on_close_data); } } StdCleanupFormProc (g, data); } NLM_EXTERN void RemoveSeqEdCloseFunc (WindoW w) { SeqEdFormPtr sefp; sefp = (SeqEdFormPtr) GetObjectExtra (w); if (sefp != NULL) { sefp->on_close_func = NULL; sefp->on_close_data = NULL; } } static void onCloseSeqEdPanel (PaneL p) { BioseqViewPtr bvp; bvp = GetBioseqViewPtr (p); bvp->chapter_list = FreeChapterList (bvp->chapter_list); bvp->feature_lists = FreeFeatureLists (bvp->feature_lists); bvp->sel_list = SelStructListFree (bvp->sel_list); } static void SetUndoRedoStatus (SeqEdFormPtr sefp) { SeqEdJournalPtr sejp; if (sefp == NULL || sefp->last_journal_entry == NULL) return; sejp = sefp->undo_list->next; if (sejp->action == eSeqEdJournalEnd) { Disable (sefp->undo_menu); Disable (sefp->redo_menu); return; } /* Set redo */ if (sefp->last_journal_entry->action == eSeqEdJournalEnd) { Disable (sefp->redo_menu); } else { sejp = sefp->last_journal_entry->next; if (sefp->last_journal_entry->action == eSeqEdJournalEnd) { Disable (sefp->redo_menu); } else { Enable (sefp->redo_menu); } } /* Set undo */ if (sefp->last_journal_entry->action == eSeqEdJournalStart) { Disable (sefp->undo_menu); } else if (sefp->last_journal_entry->action == eSeqEdJournalEnd) { sejp = sefp->last_journal_entry->prev; if (sejp->action == eSeqEdJournalStart) { Disable (sefp->undo_menu); } else { Enable (sefp->undo_menu); } } else { Enable (sefp->undo_menu); } } static void SeqEdUndoMenuItem (IteM i) { SeqEdFormPtr sefp; sefp = (SeqEdFormPtr) GetObjectExtra (i); if (sefp == NULL) return; if (UnplayJournal (&sefp->last_journal_entry, 1, sefp)) { RemapSeqEdIntervalForGap (sefp); SetUndoRedoStatus (sefp); ResizeSeqEdView (sefp); Select (sefp->bfp->bvd.seqView); inval_panel (sefp->bfp->bvd.seqView, -1, -1); } } static void SeqEdRedoMenuItem (IteM i) { SeqEdFormPtr sefp; sefp = (SeqEdFormPtr) GetObjectExtra (i); if (sefp == NULL) return; if (PlayJournal (sefp->last_journal_entry->next, &sefp->last_journal_entry, 1, NULL, sefp)) { RemapSeqEdIntervalForGap (sefp); SetUndoRedoStatus (sefp); ResizeSeqEdView (sefp); Select (sefp->bfp->bvd.seqView); inval_panel (sefp->bfp->bvd.seqView, -1, -1); } } typedef struct seqedexportform { ForM form; SeqEdFormPtr sefp; Boolean isFasta; TexT start; TexT stop; } SeqEdExportForm, PNTR SeqEdExportFormPtr; static void SeqEdExportProc (ButtoN b) { SeqEdExportFormPtr sxfp; Char namep [PATH_MAX]; Char val [100]; Int4 start, stop; FILE * fout; if (b == NULL) return; sxfp = (SeqEdExportFormPtr) GetObjectExtra (b); if (sxfp == NULL || sxfp->sefp == NULL) return; GetTitle (sxfp->start, val, sizeof (val) - 1); start = atoi (val); GetTitle (sxfp->stop, val, sizeof (val) - 1); stop = atoi (val); if (start >= stop) return; if (stop > sxfp->sefp->bfp->bvd.bsp->length) stop = sxfp->sefp->bfp->bvd.bsp->length; if (!GetOutputFileName (namep, PATH_MAX, NULL)) return; fout = FileOpen (namep, "w"); if (fout != NULL) { if (sxfp->isFasta) { EditBioseqToFasta (sxfp->sefp->bfp->bvd.bsp, fout, start - 1, stop - 1); } else { ExportSequenceText (sxfp->sefp, start - 1, stop - 1, fout); } FileClose (fout); Hide (sxfp->form); Remove (sxfp->form); } } static void SeqEdExportMenu (IteM i, Boolean isFasta) { WindoW w; SeqEdFormPtr sefp; SeqEdExportFormPtr sxfp; GrouP h, c; Char str[255]; ButtoN b; if (i == NULL) return; sefp = (SeqEdFormPtr) GetObjectExtra (i); if (sefp == NULL) return; sxfp = (SeqEdExportFormPtr) MemNew (sizeof (SeqEdExportForm)); if (sxfp == NULL) return; if (isFasta) { w = FixedWindow (-50, -33, -10, -10, "Export FASTA", StdCloseWindowProc); } else { w = FixedWindow (-50, -33, -10, -10, "Export Text", StdCloseWindowProc); } SetObjectExtra (w, sxfp, NULL); sxfp->form = (ForM) w; sxfp->sefp = sefp; sxfp->isFasta = isFasta; h = HiddenGroup (w, -1, 0, NULL); SetGroupSpacing (h, 2, 0); StaticPrompt (h, "From", 0, dialogTextHeight, systemFont, '1'); if (sefp->edit_pos_start != sefp->edit_pos_end) { sprintf (str, "%d", sefp->edit_pos_start + 1); } else { sprintf (str, "%d", 1); } sxfp->start = DialogText (h, str, 5, NULL); StaticPrompt (h, "To", 0, dialogTextHeight, systemFont, '1'); if (sefp->edit_pos_end != sefp->edit_pos_start) { sprintf (str, "%d", sefp->edit_pos_end); } else { sprintf (str, "%d", sefp->bfp->bvd.bsp->length); } sxfp->stop = DialogText (h, str, 5, NULL); c = HiddenGroup (h, 4, 0, NULL); b = PushButton (c, "Accept", SeqEdExportProc); SetObjectExtra (b, sxfp, NULL); PushButton (c, "Cancel", StdCancelButtonProc); RealizeWindow (w); Show (w); } static void SeqEdExportFastaMenuItem (IteM i) { SeqEdExportMenu (i, TRUE); } static void SeqEdExportTextMenuItem (IteM i) { SeqEdExportMenu (i, FALSE); } static void ShowNextSeqEdPattern (SeqEdFormPtr sefp) { ValNodePtr vnp; SeqLocPtr slp = NULL; Int4 pattern_start; Int4 pattern_len; if (sefp == NULL) return; /* Look at current edit position, find next position in list, scroll to it */ vnp = sefp->match_list; pattern_len = StringLen (sefp->current_pattern); if (sefp->current_pattern_translate) { pattern_len *= 3; } while (vnp != NULL) { slp = (SeqLocPtr) vnp->data.ptrvalue; pattern_start = GetOffsetInBioseq (slp, sefp->bfp->bvd.bsp, SEQLOC_LEFT_END); if ((pattern_start == sefp->edit_pos_start && sefp->edit_pos_end - sefp->edit_pos_start < pattern_len - 1) || pattern_start > sefp->edit_pos_start) { sefp->edit_pos_start = pattern_start; sefp->edit_pos_end = pattern_start + pattern_len; SeqEdScrollToSeqPosition (sefp, sefp->edit_pos_start); SeqEdUpdateStatus (sefp); return; } vnp = vnp->next; } if (sefp->match_list != NULL) { slp = (SeqLocPtr) sefp->match_list->data.ptrvalue; sefp->edit_pos_start = GetOffsetInBioseq (slp, sefp->bfp->bvd.bsp, SEQLOC_LEFT_END); sefp->edit_pos_end = sefp->edit_pos_start + pattern_len; SeqEdScrollToSeqPosition (sefp, sefp->edit_pos_start); SeqEdUpdateStatus (sefp); } } static ValNodePtr MatchListFree (ValNodePtr list) { SeqLocPtr slp; if (list == NULL) return NULL; MatchListFree (list->next); list->next = NULL; slp = (SeqLocPtr) list->data.ptrvalue; SeqLocFree (slp); ValNodeFree (list); return NULL; } static CharPtr GetPatternFromDialogText (TexT txt) { Char str [128]; Int4 len; CharPtr strp, sp, dp; GetTitle (txt, str, sizeof (str) - 1); len = StringLen (str) + 1; if (len < 2) return NULL; strp = (CharPtr) MemNew (sizeof (Char) * len); sp = str; dp = strp; while (*sp != 0) { if (*sp == '*') { *dp = *sp; dp++; } else if (isalpha ((Int4)(*sp))) { *dp = TO_UPPER (*sp); dp++; } sp++; } *dp = 0; if (*strp == 0) { MemFree (strp); strp = NULL; } return strp; } typedef struct finddlgdata { FORM_MESSAGE_BLOCK WindoW w; TexT pattern_txt; GrouP search_choice_grp; ButtoN reverse_complement_btn; PopuP frame_choice_popup; PrompT prompt; WindoW PNTR find_window; GrouP exact_match_choice; } FindDlgData, PNTR FindDlgPtr; static void LIBCALLBACK MatchProc (Int4 position, CharPtr name, CharPtr pattern, Int2 cutSite, Uint1 strand, Pointer userdata) { ValNodePtr PNTR loc_list; loc_list = (ValNodePtr PNTR) userdata; if (loc_list == NULL) return; ValNodeAddInt (loc_list, 0, position); } static void LIBCALLBACK ProtMatchProc (Int4 position, CharPtr name, CharPtr pattern, Pointer userdata) { ValNodePtr PNTR loc_list; loc_list = (ValNodePtr PNTR) userdata; if (loc_list == NULL) return; ValNodeAddInt (loc_list, 0, position); } static void ConvertIntListToLocList (ValNodePtr loc_list, BioseqPtr bsp, Int4 pattern_len) { ValNodePtr vnp; Int4 start; Int4 stop; SeqLocPtr slp; if (loc_list == NULL || bsp == NULL || pattern_len == 0) { return; } for (vnp = loc_list; vnp != NULL; vnp = vnp->next) { start = vnp->data.intvalue; stop = start + pattern_len - 1; slp = SeqLocIntNew(start, stop, Seq_strand_plus, SeqIdDup(bsp->id)); vnp->data.ptrvalue = slp; } } static ValNodePtr FindProteinMatch (BioseqPtr bsp, CharPtr pattern, Boolean exact_match) { ProtSearchPtr psp; ValNodePtr pattern_loc_list = NULL; SearchFlgType flags = 0; if (bsp == NULL || StringHasNoText (pattern) || ! ISA_aa (bsp->mol) || bsp->repr != Seq_repr_raw || bsp->seq_data_type != Seq_code_ncbieaa) { return NULL; } psp = ProtSearchNew (ProtMatchProc, &pattern_loc_list); if (!exact_match) { flags |= SEQ_SEARCH_EXPAND_PATTERN; } ProtSearchAddProteinPattern (psp, "Find", pattern, flags); ProtSearchProcessBioseq (psp, bsp); psp = ProtSearchFree (psp); ConvertIntListToLocList (pattern_loc_list, bsp, StringLen (pattern)); return pattern_loc_list; } static ValNodePtr FindSeqMatch (BioseqPtr bsp, CharPtr pattern, Boolean exact_match) { SeqSearchPtr tbl; ValNodePtr pattern_loc_list = NULL; Uint4 flags = SEQ_SEARCH_JUST_TOP_STRAND; if (bsp == NULL || StringHasNoText (pattern)) { return NULL; } if (ISA_aa (bsp->mol)) { return FindProteinMatch(bsp, pattern, exact_match); } tbl = SeqSearchNew (MatchProc, &pattern_loc_list); if (tbl == NULL) return NULL; if (!exact_match) { flags |= SEQ_SEARCH_EXPAND_PATTERN; } SeqSearchAddNucleotidePattern (tbl, "Find", pattern, 1, flags); SeqSearchProcessBioseq (tbl, bsp); SeqSearchFree (tbl); ConvertIntListToLocList (pattern_loc_list, bsp, StringLen (pattern)); return pattern_loc_list; } static ValNodePtr MergeIntLists (ValNodePtr list1, ValNodePtr list2) { ValNodePtr vnp1, vnp2, new_list = NULL; vnp1 = list1; vnp2 = list2; while (vnp1 != NULL || vnp2 != NULL) { if (vnp1 == NULL) { ValNodeAddInt (&new_list, 0, vnp2->data.intvalue); vnp2 = vnp2->next; } else if (vnp2 == NULL) { ValNodeAddInt (&new_list, 0, vnp1->data.intvalue); vnp1 = vnp1->next; } else if (vnp1->data.intvalue < vnp2->data.intvalue) { ValNodeAddInt (&new_list, 0, vnp1->data.intvalue); vnp1 = vnp1->next; } else if (vnp2->data.intvalue < vnp1->data.intvalue) { ValNodeAddInt (&new_list, 0, vnp2->data.intvalue); vnp2 = vnp2->next; } else { /* values are equal, take only one */ ValNodeAddInt (&new_list, 0, vnp1->data.intvalue); vnp1 = vnp1->next; vnp2 = vnp2->next; } } return new_list; } static ValNodePtr ReverseValNodeList (ValNodePtr vnp_list) { ValNodePtr tmp_list = NULL, vnp_next; if (vnp_list == NULL || vnp_list->next == NULL) { return vnp_list; } while (vnp_list != NULL) { vnp_next = vnp_list->next; vnp_list->next = tmp_list; tmp_list = vnp_list; vnp_list = vnp_next; } return tmp_list; } static ValNodePtr FindInCDSTranslation (SeqFeatPtr fake_cds, CharPtr pattern, Boolean exact_match) { ByteStorePtr bs; BioseqPtr prot_bsp; ValNodePtr match_list = NULL, vnp; Int4 start, stop, pattern_len; ProtSearchPtr psp; SearchFlgType flags = 0; if (fake_cds == NULL || fake_cds->data.choice != SEQFEAT_CDREGION || StringHasNoText (pattern)) { return NULL; } bs = ProteinFromCdRegionEx(fake_cds, TRUE, FALSE); if(bs == NULL) return NULL; prot_bsp = BioseqNew(); prot_bsp->mol = Seq_mol_aa; prot_bsp->repr = Seq_repr_raw; prot_bsp->seq_data = (SeqDataPtr) bs; prot_bsp->seq_data_type = Seq_code_iupacaa; start = SeqLocStart (fake_cds->location); stop = SeqLocStop (fake_cds->location); prot_bsp->length = ABS (stop - start) + 1; psp = ProtSearchNew (ProtMatchProc, &match_list); if (!exact_match) { flags |= SEQ_SEARCH_EXPAND_PATTERN; } ProtSearchAddProteinPattern (psp, "Find", pattern, flags); ProtSearchProcessBioseq (psp, prot_bsp); psp = ProtSearchFree (psp); prot_bsp = BioseqFree (prot_bsp); if (SeqLocStrand (fake_cds->location) == Seq_strand_minus) { /* reverse the locations */ match_list = ReverseValNodeList (match_list); /* position is relative to the end of the coding region */ pattern_len = StringLen (pattern); for (vnp = match_list; vnp != NULL; vnp = vnp->next) { vnp->data.intvalue = stop - (3 * (vnp->data.intvalue + pattern_len)) + 1; } } else { /* position is relative to the start of the coding region */ for (vnp = match_list; vnp != NULL; vnp = vnp->next) { vnp->data.intvalue = start + 3 * (vnp->data.intvalue); } } return match_list; } static ValNodePtr FindTranslationMatchOneFrame (BioseqPtr bsp, CharPtr pattern, Int4 frame, Boolean exact_match) { SeqFeatPtr fake_cds; Uint1 strand; Int4 start; Int4 stop; ValNodePtr pattern_loc_list = NULL; if (bsp == NULL || StringHasNoText (pattern)) { return NULL; } switch (frame) { case 1: start = 0; stop = bsp->length - 1; strand = Seq_strand_plus; break; case 2: start = 1; stop = bsp->length - 1; strand = Seq_strand_plus; break; case 3: start = 2; stop = bsp->length - 1; strand = Seq_strand_plus; break; case 4: start = 0; stop = bsp->length - 1; strand = Seq_strand_minus; break; case 5: start = 0; stop = bsp->length - 2; strand = Seq_strand_minus; break; case 6: start = 0; stop = bsp->length - 3; strand = Seq_strand_minus; break; default: return NULL; break; } fake_cds = make_fake_cds(bsp, start, stop, strand); pattern_loc_list = FindInCDSTranslation (fake_cds, pattern, exact_match); SeqFeatFree(fake_cds); return pattern_loc_list; } static ValNodePtr FindTranslation (BioseqPtr bsp, CharPtr pattern, Int4 pick_frame, Boolean exact_match) { Int4 i; ValNodePtr loc_list = NULL; ValNodePtr new_list, comb_list; if (bsp == NULL || StringHasNoText (pattern)) { return NULL; } if (pick_frame < 1 || pick_frame > 6) { for (i = 1; i <= 6; i++) { new_list = FindTranslationMatchOneFrame (bsp, pattern, i, exact_match); comb_list = MergeIntLists (loc_list, new_list); ValNodeFree (new_list); ValNodeFree (loc_list); loc_list = comb_list; } } else { loc_list = FindTranslationMatchOneFrame (bsp, pattern, pick_frame, exact_match); } ConvertIntListToLocList (loc_list, bsp, StringLen (pattern)); return loc_list; } static void CleanPattern (CharPtr pattern, Int4 search_choice) { CharPtr cp; if (pattern == NULL) return; for (cp = pattern; *cp != 0; cp++) { if (search_choice == 3) { *cp = toupper (*cp); } else { *cp = tolower (*cp); } } } static void FindPatternButton (ButtoN b) { SeqEdFormPtr sefp; FindDlgPtr fdp; WindoW wdialog; CharPtr strp; Int4 count; Char str[255]; Uint1 pick_frame; Int4 search_choice = 0; Boolean exact_match = TRUE; if (b == NULL) return; sefp = (SeqEdFormPtr) GetObjectExtra (b); if (sefp == NULL) return; wdialog = ParentWindow (b); fdp = (FindDlgPtr) GetObjectExtra (wdialog); strp = GetPatternFromDialogText (fdp->pattern_txt); if (fdp->search_choice_grp != NULL) { search_choice = GetValue (fdp->search_choice_grp); } if (fdp->exact_match_choice != NULL && GetValue (fdp->exact_match_choice) != 1) { exact_match = FALSE; } CleanPattern (strp, search_choice); if (GetStatus (fdp->reverse_complement_btn) && search_choice != 3) { complement_string (strp); reverse_string (strp); } if (strp == NULL) { SetTitle (fdp->prompt, "No item found"); return; } if (sefp->current_pattern != NULL) { if ((StringStr(sefp->current_pattern, strp)) && (StringLen(sefp->current_pattern) == StringLen (strp)) && (fdp->search_choice_grp == NULL || (search_choice == 1 && !sefp->current_pattern_translate && sefp->current_pattern_revcomp == GetStatus (fdp->reverse_complement_btn)) || (search_choice == 3 && sefp->current_pattern_translate && sefp->current_pattern_translate_frame_choice == GetValue (fdp->frame_choice_popup))) && (exact_match == sefp->current_pattern_exact_match)) { MemFree (strp); ShowNextSeqEdPattern (sefp); return; } else { MemFree (sefp->current_pattern); } } sefp->current_pattern = strp; if (sefp->match_list != NULL) sefp->match_list = MatchListFree (sefp->match_list); if (search_choice == 1) { sefp->current_pattern_revcomp = (Boolean) GetStatus (fdp->reverse_complement_btn); sefp->current_pattern_translate = FALSE; } else if (search_choice == 3) { sefp->current_pattern_translate = TRUE; sefp->current_pattern_translate_frame_choice = GetValue (fdp->frame_choice_popup); } if (sefp->current_pattern_translate) { pick_frame = sefp->current_pattern_translate_frame_choice; if (pick_frame > 0) { pick_frame --; } sefp->match_list = FindTranslation (sefp->bfp->bvd.bsp, strp, pick_frame, exact_match); } else { sefp->match_list = FindSeqMatch (sefp->bfp->bvd.bsp, strp, exact_match); } sefp->current_pattern_exact_match = exact_match; if (sefp->match_list != NULL) { count = ValNodeLen (sefp->match_list); if (count ==0) SetTitle (fdp->prompt, "No item found"); else if (count ==1) { SetTitle (fdp->prompt, "1 item found"); } else { sprintf (str, "%d items found - next=CTRL->, previous=CTRL<- ", (int) count); SetTitle (fdp->prompt, str); } ShowNextSeqEdPattern (sefp); } else { SetTitle (fdp->prompt, "No item found"); } Update (); return; } static void ChangeSearchChoice (GrouP g) { WindoW wdialog; FindDlgPtr fdp; Int4 val; wdialog = ParentWindow (g); fdp = (FindDlgPtr) GetObjectExtra (wdialog); if (fdp == NULL) return; val = GetValue (g); if (val == 1) { Enable (fdp->reverse_complement_btn); Disable (fdp->frame_choice_popup); } else { Disable (fdp->reverse_complement_btn); Enable (fdp->frame_choice_popup); } } static void CleanupFindWindow (GraphiC g, Pointer data) { FindDlgPtr fdp; fdp = (FindDlgPtr) data; if (fdp != NULL) { if (fdp->find_window != NULL) { *(fdp->find_window) = NULL; } fdp = MemFree (fdp); } } static void SeqEdFindPatternDialog (IteM i) { WindoW w; FindDlgPtr fdp; SeqEdFormPtr sefp; GrouP h, g1, g2; ButtoN b; PrompT p1; if (i == NULL) return; sefp = (SeqEdFormPtr) GetObjectExtra (i); if (sefp == NULL) return; if (sefp->find_window != NULL) { Show (sefp->find_window); Select (sefp->find_window); return; } w = ParentWindow (i); sefp->find_window=FixedWindow (-50, -33, -10, -10, "Find", StdCloseWindowProc); fdp = (FindDlgPtr) MemNew (sizeof (FindDlgData)); SetObjectExtra (sefp->find_window, (Pointer) fdp, CleanupFindWindow); fdp->w = w; fdp->find_window = &(sefp->find_window); fdp->search_choice_grp = NULL; CreateStandardEditMenu (sefp->find_window); h = HiddenGroup (sefp->find_window, -1, 0, NULL); p1 = StaticPrompt (h, "Find pattern:", 0, popupMenuHeight, programFont, 'l'); fdp->pattern_txt = ScrollText (h, 25, 8, programFont, TRUE, NULL); fdp->prompt = StaticPrompt (h, "", (Int2)(25*stdCharWidth), stdLineHeight, programFont, 'l'); if (ISA_na(sefp->bfp->bvd.bsp->mol)) { fdp->search_choice_grp = NormalGroup (h, 2, 0, "Search in", systemFont, ChangeSearchChoice); RadioButton (fdp->search_choice_grp, "Nucleotide sequence"); fdp->reverse_complement_btn = CheckBox (fdp->search_choice_grp, "reverse complement", NULL); SetStatus (fdp->reverse_complement_btn, FALSE); RadioButton (fdp->search_choice_grp, "Translated frame"); fdp->frame_choice_popup = PopupList (fdp->search_choice_grp, TRUE, NULL); PopupItem (fdp->frame_choice_popup, "Any"); PopupItem (fdp->frame_choice_popup, "+1"); PopupItem (fdp->frame_choice_popup, "+2"); PopupItem (fdp->frame_choice_popup, "+3"); PopupItem (fdp->frame_choice_popup, "-1"); PopupItem (fdp->frame_choice_popup, "-2"); PopupItem (fdp->frame_choice_popup, "-3"); SetValue (fdp->frame_choice_popup, 1); Disable (fdp->frame_choice_popup); SetValue (fdp->search_choice_grp, 1); g1 = fdp->search_choice_grp; } fdp->exact_match_choice = HiddenGroup (h, 2, 0, NULL); RadioButton (fdp->exact_match_choice, "Exact Match"); RadioButton (fdp->exact_match_choice, "Ambiguous Match"); SetValue (fdp->exact_match_choice, 1); if (ISA_na (sefp->bfp->bvd.bsp->mol)) { g2 = HiddenGroup (h, 2, 0, NULL); b = PushButton (g2, "Find Next", FindPatternButton); SetObjectExtra (b, sefp, NULL); PushButton (g2, "Dismiss", StdCancelButtonProc); } else { g1 = HiddenGroup (h, 2, 0, NULL); b = PushButton (g1, "Find Next", FindPatternButton); SetObjectExtra (b, sefp, NULL); PushButton (g1, "Close", StdCancelButtonProc); g2 = NULL; } AlignObjects (ALIGN_CENTER, (HANDLE) p1, (HANDLE) fdp->pattern_txt, (HANDLE)fdp->prompt, (HANDLE) g1, (HANDLE) fdp->exact_match_choice, (HANDLE) g2, NULL); RealizeWindow (sefp->find_window); Show (sefp->find_window); return; } static void ObjMgrSelectSeqEdSelection (SeqEdFormPtr sefp, BioseqPtr target_bsp) { SeqLocPtr slp; Uint4 itemID; Uint2 entityID; Int4 real_start, real_stop; Int4 aln_len; Uint1 strand; if (sefp == NULL || sefp->edit_pos_start == sefp->edit_pos_end || target_bsp == NULL) { return; } if (sefp->bfp->bvd.salp == NULL) { real_start = sefp->edit_pos_start; real_stop = sefp->edit_pos_end - 1; strand = Seq_strand_plus; } else { real_start = sefp->edit_pos_start + 1; real_stop = sefp->edit_pos_end; aln_len = SeqAlignLength (sefp->bfp->bvd.salp); AdjustFromForGap (&real_start, sefp->bfp->bvd.salp, aln_len, sefp->bfp->bvd.TargetRow); AdjustToForGap (&real_stop, sefp->bfp->bvd.salp, sefp->bfp->bvd.TargetRow); strand = AlnMgr2GetNthStrand (sefp->bfp->bvd.salp, sefp->bfp->bvd.TargetRow); real_start --; real_stop --; } slp = SeqLocIntNew (real_start, real_stop, strand, target_bsp->id); entityID = ObjMgrGetEntityIDForPointer (target_bsp); BioseqFindEntity (target_bsp->id, &itemID); ObjMgrSelect (entityID, itemID, OBJ_BIOSEQ, OM_REGION_SEQLOC, slp); } typedef struct newfeaturedata { ObjMgrProcPtr ompp; IteM item; Uint1 molgroup; struct newfeaturedata PNTR next; } NewFeatureData, PNTR NewFeaturePtr; static CharPtr editOldSrcDescMsg = "\ You may really want to edit an existing BioSource descriptor instead.\n\ Proceed anyway?"; static void SeqEditNewFeatureMenuProc (IteM i) { MsgAnswer ans; NewFeaturePtr nfp; OMProcControl ompc; ObjMgrProcPtr ompp; Int2 retval; SeqEdFormPtr sefp; Uint4 itemID; SeqIdPtr sip; BioseqPtr target_bsp; sefp = (SeqEdFormPtr) GetObjectExtra ((WindoW) ParentWindow (i)); if (sefp == NULL) return; nfp = (NewFeaturePtr) GetObjectExtra (i); if (nfp == NULL) return; ompp = nfp->ompp; if (ompp == NULL || ompp->func == NULL) return; if (ompp->subinputtype == FEATDEF_BIOSRC) { ans = Message (MSG_YN, editOldSrcDescMsg); if (ans == ANS_NO) return; } MemSet ((Pointer) (&ompc), 0, sizeof (OMProcControl)); if (sefp->bfp->bvd.salp == NULL) { target_bsp = sefp->bfp->bvd.bsp; } else { sip = AlnMgr2GetNthSeqIdPtr(sefp->bfp->bvd.salp, sefp->bfp->bvd.TargetRow); target_bsp = BioseqFind (sip); } if (target_bsp == NULL) { return; } ompc.input_entityID = ObjMgrGetEntityIDForPointer (sefp->bfp->bvd.bsp); BioseqFindEntity (target_bsp->id, &itemID); ompc.input_itemID = itemID; ompc.input_itemtype = OBJ_BIOSEQ; ObjMgrSelectSeqEdSelection (sefp, target_bsp); GatherDataForProc (&ompc, FALSE); ompc.proc = ompp; retval = (*(ompp->func)) (&ompc); if (retval == OM_MSG_RET_ERROR) { ErrShow (); } } static void SeqEdNewFeaturesMenu (MenU m, Boolean is_na) { FeatDispGroupPtr fdgp; FeatDefPtr fdp; NewFeaturePtr first; IteM i; Uint1 key; CharPtr label; NewFeaturePtr last; NewFeaturePtr nfp; ObjMgrPtr omp; ObjMgrProcPtr ompp; ObjMgrTypePtr omtp; MenU sub; Uint2 subtype; if (m == NULL) return; omp = ObjMgrGet (); if (omp == NULL) return; ompp = ObjMgrProcFindNext (omp, OMPROC_EDIT, 0, 0, NULL); if (ompp == NULL) return; omtp = NULL; first = NULL; last = NULL; while ((omtp = ObjMgrTypeFindNext (omp, omtp)) != NULL) { ompp = ObjMgrProcFindNext (omp, OMPROC_EDIT, omtp->datatype, 0, NULL); if (ompp != NULL) { switch (omtp->datatype) { case OBJ_SEQFEAT : fdgp = NULL; while ((fdgp = DispGroupFindNext (fdgp, &key, &label)) != NULL) { if (fdgp->groupkey != 0) { sub = SubMenu (m, fdgp->groupname); fdp = NULL; label = NULL; while ((fdp = FeatDefFindNext (fdp, &key, &label, fdgp->groupkey, FALSE)) != NULL) { if (key != FEATDEF_BAD) { ompp = NULL; while ((ompp = ObjMgrProcFindNext (omp, OMPROC_EDIT, omtp->datatype, 0, ompp)) != NULL) { if (ompp->subinputtype == fdp->featdef_key && ompp->subinputtype != FEATDEF_PUB) { i = CommandItem (sub, ompp->proclabel, SeqEditNewFeatureMenuProc); nfp = (NewFeaturePtr) MemNew (sizeof (NewFeatureData)); if (nfp != NULL) { nfp->ompp = ompp; nfp->item = i; nfp->molgroup = fdp->molgroup; } if (first == NULL) { first = nfp; } if (last != NULL) { last->next = nfp; } last = nfp; SetObjectExtra (i, (Pointer) nfp, StdCleanupExtraProc); if ((is_na && (fdp->molgroup == 2 || fdp->molgroup == 3)) || ((! is_na) && (fdp->molgroup == 1 || fdp->molgroup == 3))) { } else { Disable (i); } } } } } } } sub = SubMenu (m, "Remaining Features"); fdp = NULL; label = NULL; while ((fdp = FeatDefFindNext (fdp, &key, &label, 0, FALSE)) != NULL) { if (key != FEATDEF_BAD) { ompp = NULL; while ((ompp = ObjMgrProcFindNext (omp, OMPROC_EDIT, omtp->datatype, 0, ompp)) != NULL) { subtype = ompp->subinputtype; if (subtype == fdp->featdef_key && OkToListFeatDefInRemainingFeatures (subtype)) { i = CommandItem (sub, ompp->proclabel, SeqEditNewFeatureMenuProc); nfp = (NewFeaturePtr) MemNew (sizeof (NewFeatureData)); if (nfp != NULL) { nfp->ompp = ompp; nfp->item = i; nfp->molgroup = fdp->molgroup; } if (first == NULL) { first = nfp; } if (last != NULL) { last->next = nfp; } last = nfp; SetObjectExtra (i, (Pointer) nfp, StdCleanupExtraProc); if ((is_na && (fdp->molgroup == 2 || fdp->molgroup == 3)) || ((! is_na) && (fdp->molgroup == 1 || fdp->molgroup == 3))) { } else { Disable (i); } } } } } break; default : break; } } } } static void CreateSeqEdMenus (WindoW w) { MenU edit_menu; IteM localItem; MenU sub; SeqEdFormPtr sefp; Int4 i; Boolean is_na; if (w == NULL) return; sefp = (SeqEdFormPtr) GetObjectExtra (w); if (sefp == NULL) return; /* File Menu */ edit_menu = PulldownMenu (w, "File"); sub = SubMenu (edit_menu, "Export"); localItem = CommandItem (sub, "FASTA", SeqEdExportFastaMenuItem); SetObjectExtra (localItem, sefp, NULL); localItem = CommandItem (sub, "Text", SeqEdExportTextMenuItem); SetObjectExtra (localItem, sefp, NULL); localItem = CommandItem (edit_menu, "Accept", SeqEdAcceptMenuItem); SetObjectExtra (localItem, sefp, NULL); localItem = CommandItem (edit_menu, "Cancel", SeqEdCancelMenuItem); SetObjectExtra (localItem, sefp, NULL); /* Edit Menu */ edit_menu = PulldownMenu (w, "Edit"); sefp->undo_menu = CommandItem (edit_menu, "Undo", SeqEdUndoMenuItem); SetObjectExtra (sefp->undo_menu, sefp, NULL); Disable (sefp->undo_menu); sefp->redo_menu = CommandItem (edit_menu, "Redo", SeqEdRedoMenuItem); SetObjectExtra (sefp->redo_menu, sefp, NULL); Disable (sefp->redo_menu); localItem = CommandItem (edit_menu, "Cut", SeqEdCutMenuItem); SetObjectExtra (localItem, sefp, NULL); localItem = CommandItem (edit_menu, "Paste", SeqEdPasteMenuItem); SetObjectExtra (localItem, sefp, NULL); localItem = CommandItem (edit_menu, "Copy", SeqEdCopyMenuItem); SetObjectExtra (localItem, sefp, NULL); localItem = CommandItem (edit_menu, "Find", SeqEdFindPatternDialog); SetObjectExtra (localItem, sefp, NULL); localItem = CommandItem (edit_menu, "Translate CDS", SeqEdTranslateCDSItem); SetObjectExtra (localItem, sefp, NULL); if (sefp->bfp != NULL && sefp->bfp->bvd.bsp != NULL && sefp->bfp->bvd.bsp->repr == Seq_repr_delta && sefp->bfp->bvd.bsp->seq_ext_type == 4) { localItem = CommandItem (edit_menu, "Insert Gap", SeqEdInsertGapMenuItem); SetObjectExtra (localItem, sefp, NULL); } /* View menu */ edit_menu = PulldownMenu (w, "View"); localItem = StatusItem (edit_menu, "Complement", SeqEdComplement); SetStatus ( localItem, FALSE); SetObjectExtra (localItem, sefp, NULL); sub = SubMenu (edit_menu, "Reading frames"); sefp->frames[0] = StatusItem (sub, " +1", SeqEdFrame1); sefp->frames[1] = StatusItem (sub, " +2", SeqEdFrame2); sefp->frames[2] = StatusItem (sub, " +3", SeqEdFrame3); sefp->frames[3] = StatusItem (sub, "All +", SeqEdFrameAllPlus); sefp->frames[4] = StatusItem (sub, " -1", SeqEdFrame4); sefp->frames[5] = StatusItem (sub, " -2", SeqEdFrame5); sefp->frames[6] = StatusItem (sub, " -3", SeqEdFrame6); sefp->frames[7] = StatusItem (sub, "All -", SeqEdFrameAllMinus); sefp->frames[8] = StatusItem (sub, "All", SeqEdFrameAll); sefp->frames[9] = StatusItem (sub, "None", SeqEdFrameNone); for (i = 0; i < 10; i++) { SetObjectExtra (sefp->frames[i], sefp, NULL); SetStatus (sefp->frames[i], FALSE); } SetStatus (sefp->frames[9], TRUE); localItem = StatusItem (edit_menu, "Protein Mismatches", SeqEdToggleProteinMismatch); SetObjectExtra (localItem, sefp, NULL); SetStatus (localItem, FALSE); localItem = StatusItem (edit_menu, "On-the-fly Protein Translations", SeqEdToggleProteinOnTheFly); SetObjectExtra (localItem, sefp, NULL); SetStatus (localItem, sefp->bfp->bvd.on_the_fly); edit_menu = PulldownMenu (w, "Features"); is_na = ISA_na (sefp->bfp->bvd.bsp->mol); SeqEdNewFeaturesMenu (edit_menu, is_na); } static Uint1 GetMoleculeType (BioseqPtr bsp) { SeqDescPtr sdp; MolInfoPtr mip; SeqMgrDescContext dcontext; if (bsp == NULL) return MOLECULE_TYPE_GENOMIC; sdp = SeqMgrGetNextDescriptor (bsp, NULL, Seq_descr_molinfo, &dcontext); if (sdp == NULL) return MOLECULE_TYPE_GENOMIC; mip = (MolInfoPtr) sdp->data.ptrvalue; if (mip == NULL) return MOLECULE_TYPE_GENOMIC; return mip->biomol; } /************************************************************* **************************************************************/ static Int2 LIBCALLBACK SeqEditMsgFunc (OMMsgStructPtr ommsp) { WindoW currentport, temport; OMUserDataPtr omudp; SeqEdFormPtr sefp = NULL; omudp = (OMUserDataPtr)(ommsp->omuserdata); if (omudp == NULL) return OM_MSG_RET_ERROR; sefp = (SeqEdFormPtr) omudp->userdata.ptrvalue; if (sefp == NULL) return OM_MSG_RET_ERROR; currentport = ParentWindow (sefp->bfp->bvd.seqView); temport = SavePort (currentport); UseWindow (currentport); Select (sefp->bfp->bvd.seqView); switch (ommsp->message) { case OM_MSG_UPDATE: if (sefp->bfp->bvd.seqAlignMode && sefp->annot != NULL && sefp->annot->type == 2) { sefp->bfp->bvd.salp = sefp->annot->data; } ResizeSeqEdView (sefp); Select (sefp->bfp->bvd.seqView); inval_panel (sefp->bfp->bvd.seqView, -1, -1); break; case OM_MSG_DESELECT: ResizeSeqEdView (sefp); Select (sefp->bfp->bvd.seqView); inval_panel (sefp->bfp->bvd.seqView, -1, -1); break; case OM_MSG_SELECT: ResizeSeqEdView (sefp); Select (sefp->bfp->bvd.seqView); inval_panel (sefp->bfp->bvd.seqView, -1, -1); break; case OM_MSG_DEL: Hide (sefp->form); Remove (sefp->form); break; case OM_MSG_HIDE: break; case OM_MSG_SHOW: break; case OM_MSG_FLUSH: SeqEdCancel (sefp); break; default: break; } RestorePort (temport); UseWindow (temport); return OM_MSG_RET_OK; } static void OnDrawSeqEdPanel (PaneL p) { BioseqViewPtr bvp; bvp = GetBioseqViewPtr (p); if (bvp == NULL) return; DrawSeqChapters (bvp); } extern ForM CreateSeqEditorWindow (Int2 left, Int2 top, CharPtr windowname, BioseqPtr bsp) { SeqEdFormPtr sefp; WindoW w; GrouP g; PopuP pop; Char str [16]; Int2 window_width = 650; Int2 window_hgt = 300, charwidth, lineheight; FonT font; Boolean is_prot = FALSE; Int4 btns_across; OMUserDataPtr omudp; Uint1 seqtype; ButtoN b; if (bsp==NULL || (bsp->repr != Seq_repr_raw && bsp->repr != Seq_repr_delta)) { return NULL; } is_prot = (Boolean)(ISA_aa(bsp->mol)); sefp = SeqEdFormNew (); if (sefp == NULL) { return NULL; } /* prepare BSP for editing */ if (ISA_na(bsp->mol)) { seqtype = Seq_code_iupacna; } else { seqtype = Seq_code_ncbieaa; } if (bsp->seq_data_type != seqtype && bsp->repr != Seq_repr_delta) { BioseqRawConvert(bsp, seqtype); } #ifdef WIN_MAC font = ParseFont ("Monaco, 9"); #endif #ifdef WIN_MSWIN font = ParseFont ("Courier, 9"); #endif #ifdef WIN_MOTIF font = ParseFont ("fixed, 12"); #endif SelectFont (font); charwidth = CharWidth ('0'); lineheight = FontHeight () + SEQ_Y_OFFSET; w = DocumentWindow (left, top, (Int2)(-10), (Int2)(-10), windowname, NULL, ResizeSeqEditorWindow); SetObjectExtra (w, (Pointer) sefp, CleanupSeqEdForm); sefp->form = (ForM) w; sefp->formmessage = SeqEdFormMessage; sefp->input_entityID = ObjMgrGetEntityIDForPointer (bsp); /* initialize view pointer */ sefp->bfp = (BioseqViewFormPtr) MemNew (sizeof (BioseqViewForm)); if (sefp->bfp == NULL) return NULL; sefp->bfp->bvd.bsp = bsp; sefp->moltype = GetMoleculeType (bsp); sefp->bfp->bvd.seqAlignMode = FALSE; sefp->bfp->bvd.DrawGrid = FALSE; sefp->bfp->bvd.SeqStartPosX = 100; sefp->bfp->bvd.CharHeight = FontHeight (); sefp->bfp->bvd.displayFont = font; sefp->bfp->bvd.LineHeight = lineheight; sefp->bfp->bvd.CharWidth = charwidth; sefp->bfp->bvd.seq_entityID = sefp->input_entityID; sefp->bfp->bvd.on_the_fly = FALSE; CreateSeqEdMenus (w); if (is_prot) { btns_across = 4; } else { btns_across = 5; } sefp->upper_button_group = HiddenGroup (w, -10, -10, NULL); SetGroupSpacing (sefp->upper_button_group, 10, 3); g = HiddenGroup (sefp->upper_button_group, btns_across, 0, NULL); SetGroupSpacing (g, 10, 3); sprintf (str, "%ld", (long) sefp->edit_pos_start); sefp->goto_btn = PushButton (g, "Go to:", SeqEdGoToButton); sefp->goto_txt = DialogText (g, str, (Int2)6, NULL); sefp->lookat_btn = PushButton (g, "Look at:", SeqEdLookAtButton); sefp->lookat_txt = DialogText (g, str, (Int2)6, NULL); if (!is_prot) { pop = PopupList (g, TRUE, SeqEdSelectFeatEditMode); PopupItem (pop, "Merge feature mode"); PopupItem (pop, "Split feature mode"); SetValue (pop, 1); } /* numbering location and grid controls */ StaticPrompt (g, " Numbering: ", 0, popupMenuHeight, programFont, 'l'); sefp->bfp->bvd.newNumControl = PopupList (g, TRUE, ChangeSeqEditControls); SetObjectExtra (sefp->bfp->bvd.newNumControl, sefp, NULL); PopupItem (sefp->bfp->bvd.newNumControl, "None"); PopupItem (sefp->bfp->bvd.newNumControl, "Side"); PopupItem (sefp->bfp->bvd.newNumControl, "Top"); SetValue (sefp->bfp->bvd.newNumControl, 3); StaticPrompt (g, " Grid: ", 0, popupMenuHeight, programFont, 'l'); sefp->bfp->bvd.newGridControl = PopupList (g, TRUE, ChangeSeqEditControls); SetObjectExtra (sefp->bfp->bvd.newGridControl, sefp, NULL); PopupItem (sefp->bfp->bvd.newGridControl, "On"); PopupItem (sefp->bfp->bvd.newGridControl, "Off"); SetValue (sefp->bfp->bvd.newGridControl, 2); g = HiddenGroup (w, 1, 0, NULL); sefp->position_label = StaticPrompt (g, "", window_width, dialogTextHeight, programFont, 'l'); SeqEdUpdateStatus (sefp); g = HiddenGroup (w, 1, 0, NULL); sefp->bfp->bvd.seqView = AutonomousPanel4 (g, window_width, window_hgt, OnDrawSeqEdPanel, onSeqEdVScrollBarSeqPanel, NULL, sizeof (BioseqViewPtr), onCloseSeqEdPanel, NULL); SetObjectExtra (sefp->bfp->bvd.seqView, sefp->bfp, NULL); sefp->lower_button_group = HiddenGroup (w, 6, 0, NULL); SetGroupSpacing (sefp->lower_button_group, 10, 3); StaticPrompt (sefp->lower_button_group, "Features:", 0, dialogTextHeight, programFont, 'l'); sefp->bfp->bvd.newFeatControl = PopupList (sefp->lower_button_group, TRUE, ChangeSeqEditControls); PopupItem (sefp->bfp->bvd.newFeatControl, "Shown"); PopupItem (sefp->bfp->bvd.newFeatControl, "Hidden"); SetValue (sefp->bfp->bvd.newFeatControl, 1); SetObjectExtra (sefp->bfp->bvd.newFeatControl, sefp, NULL); sefp->accept = PushButton (sefp->lower_button_group, "Accept", SeqEdAcceptButton); SetObjectExtra (sefp->accept, sefp, NULL); sefp->cancel = PushButton (sefp->lower_button_group, "Cancel", SeqEdCancelButton); SetObjectExtra (sefp->cancel, sefp, NULL); if (!is_prot) { b = PushButton (sefp->lower_button_group, "Translate CDS", SeqEdTranslateCDSBtn); SetObjectExtra (b, sefp, NULL); } ResizeSeqEdView (sefp); RealizeWindow (w); SetSlateChar ((SlatE) sefp->bfp->bvd.seqView, SeqEdOnKey); SetSeqEdPanelClick (sefp); /* register to receive update messages */ sefp->userkey = OMGetNextUserKey (); sefp->procid = 0; sefp->proctype = OMPROC_EDIT; omudp = ObjMgrAddUserData (sefp->input_entityID, sefp->procid, sefp->proctype, sefp->userkey); if (omudp != NULL) { omudp->userdata.ptrvalue = (Pointer) sefp; omudp->messagefunc = SeqEditMsgFunc; } return (ForM) w; } static Int4 GetScrollPosForAlnPos (Int4 aln_pos, BioseqViewPtr bvp) { Int4 aln_line = 0, display_line, mult; if (bvp == NULL || aln_pos < 0) { return 0; } aln_line = aln_pos / bvp->CharsAtLine; if (aln_line >= bvp->TotalLines) { return bvp->TotalLines - 1; } if (bvp->SeqPanLines[aln_line]->bioSeqLine > 0) { mult = aln_line / bvp->SeqPanLines[aln_line]->bioSeqLine; if (mult > 1) { display_line = aln_line * mult; } else { display_line = aln_line; } } else { display_line = aln_line; } if (display_line >= bvp->TotalLines) { display_line = bvp->TotalLines - 1; } while (bvp->SeqPanLines[display_line]->bioSeqLine > aln_line && display_line > -1) { display_line --; } while (bvp->SeqPanLines[display_line]->bioSeqLine < aln_line && display_line < bvp->TotalLines - 1) { display_line++; } if (bvp->SeqPanLines[display_line]->bioSeqLine == aln_line) { while (display_line > -1 && bvp->SeqPanLines[display_line]->bioSeqLine == aln_line) { display_line --; } display_line++; } return display_line; } static void SeqAlnScrollToAlnPosEx (SeqEdFormPtr sefp, Int4 pos, Int4 seq_num) { BaR sb; Int4 scroll_pos, bmax; WindoW currentport, temport; Int4 aln_len; if (sefp == NULL || sefp->bfp == NULL || sefp->bfp->bvd.salp == NULL) { return; } aln_len = AlnMgr2GetAlnLength(sefp->bfp->bvd.salp, FALSE); if (pos < 0) { pos = 0; } else if (pos > aln_len) { pos = aln_len; } sb = GetSlateVScrollBar ((SlatE) sefp->bfp->bvd.seqView); if (sb == NULL) return; bmax = GetBarMax (sb); scroll_pos = GetScrollPosForAlnPos (pos, &(sefp->bfp->bvd)); if (seq_num > -1) { /* need to skip two in order to move past header rows for block */ scroll_pos += seq_num + 2; } if (scroll_pos > bmax) { scroll_pos = bmax; } SetBarValue (sb, scroll_pos); currentport = ParentWindow (sefp->bfp->bvd.seqView); temport = SavePort (currentport); Select (sefp->bfp->bvd.seqView); inval_panel (sefp->bfp->bvd.seqView, -1, -1); RestorePort (temport); } static void SeqAlnScrollToAlnPos (SeqEdFormPtr sefp, Int4 pos) { SeqAlnScrollToAlnPosEx (sefp, pos, -1); } NLM_EXTERN void SeqAlnWindowScrollToAlnPos (WindoW w, Int4 aln_pos, Int4 seq_num) { SeqEdFormPtr sefp; sefp = (SeqEdFormPtr) GetObjectExtra (w); if (sefp != NULL) { SeqAlnScrollToAlnPosEx (sefp, aln_pos, seq_num); } } static void SeqAlnGoToAlnPosBtn (ButtoN b) { SeqEdFormPtr sefp; Int4 aln_pos; Char str [16]; sefp = (SeqEdFormPtr) GetObjectExtra ((WindoW)ParentWindow (b)); if (sefp == NULL || sefp->bfp == NULL) return; GetTitle (sefp->goto_txt, str, 15); if (! CCStrToLong (str, &aln_pos)) { return; } aln_pos -= 1; SeqAlnScrollToAlnPos (sefp, aln_pos); } static void SeqAlnGoToSeqPosBtn (ButtoN b) { SeqEdFormPtr sefp; Int4 seq_pos, aln_pos; Char str [16]; SeqIdPtr sip; BioseqPtr bsp; sefp = (SeqEdFormPtr) GetObjectExtra ((WindoW)ParentWindow (b)); if (sefp == NULL || sefp->bfp == NULL || sefp->bfp->bvd.salp == NULL) { return; } sip = AlnMgr2GetNthSeqIdPtr(sefp->bfp->bvd.salp, sefp->bfp->bvd.TargetRow); bsp = BioseqFind (sip); if (bsp == NULL) { return; } GetTitle (sefp->lookat_txt, str, 15); if (! CCStrToLong (str, &seq_pos)) { return; } if (seq_pos < 0) { seq_pos = 0; } else if (seq_pos >= bsp->length) { seq_pos = bsp->length - 1; } aln_pos = AlnMgr2MapBioseqToSeqAlign (sefp->bfp->bvd.salp, seq_pos, sefp->bfp->bvd.TargetRow); SeqAlnScrollToAlnPos (sefp, aln_pos); } static void SeqAlnClose (SeqEdFormPtr sefp) { if (sefp == NULL) return; Hide (sefp->form); Remove (sefp->form); Update (); } static void SeqAlnCloseButton (ButtoN b) { SeqEdFormPtr sefp; sefp = (SeqEdFormPtr) GetObjectExtra (b); SeqAlnClose (sefp); } static void SeqAlnCloseMenuItem (IteM i) { SeqEdFormPtr sefp; sefp = (SeqEdFormPtr) GetObjectExtra (i); SeqAlnClose (sefp); } static Int4 FindMaxLabelLen (SeqAlignPtr salp) { SeqIdPtr sip; BioseqPtr bsp; Char tmpbuf[256]; Int4 i; Int4 max_len = 0; Int4 len; if (salp == NULL) return 0; for (i = 0; i < salp->dim; i++) { sip = AlnMgr2GetNthSeqIdPtr(salp, i + 1); bsp = BioseqFind (sip); if (bsp != NULL) { sip = SeqIdFindBestAccession (bsp->id); } SeqIdWrite (sip, tmpbuf, PRINTID_TEXTID_ACCESSION, sizeof(tmpbuf) - 1); len = StringLen (tmpbuf) + 2; if (len > max_len) { max_len = len; } } return max_len; } static CharPtr GetSeqAlignLabels (SeqAlignPtr salp, Int4Ptr label_len) { CharPtr labels; BioseqPtr bsp; SeqIdPtr sip; Int4 i; if (salp == NULL || label_len == NULL) { return NULL; } *label_len = FindMaxLabelLen (salp); if (*label_len < 1) return NULL; labels = (CharPtr) MemNew ((*label_len + 1) * salp->dim * sizeof (Char)); if (labels == NULL) return NULL; MemSet (labels, 0, *label_len * salp->dim * sizeof (Char)); for (i = 0; i < salp->dim; i++) { sip = AlnMgr2GetNthSeqIdPtr(salp, i + 1); bsp = BioseqFind (sip); if (bsp != NULL) { sip = SeqIdFindBestAccession (bsp->id); } SeqIdWrite (sip, labels + i * (*label_len + 1) * sizeof (Char), PRINTID_TEXTID_ACCESSION, *label_len); } return labels; } static Int4 GetMaxCoordLen (SeqAlignPtr salp) { BioseqPtr bsp; SeqIdPtr sip; Int4 i; Int4 max_len = 0; SeqEntryPtr oldscope; if (salp == NULL) { return 0; } for (i = 0; i < salp->dim; i++) { sip = AlnMgr2GetNthSeqIdPtr(salp, i + 1); bsp = BioseqFind (sip); if (bsp == NULL) { oldscope = SeqEntrySetScope (NULL); bsp = BioseqFind (sip); SeqEntrySetScope (oldscope); } if (bsp->length > max_len) max_len = bsp->length; } i = log (max_len) + 1; return i; } static void AddCoordToPrintedLine (CharPtr printed_line, SeqAlignPtr salp, Int4 row, Int4 start, Int4 stop, Int4 coord_len) { Uint1 strand; Int4 seqstart; if (printed_line == NULL || salp == NULL || start < 0 || row < 1 || coord_len < 2) return; strand = AlnMgr2GetNthStrand (salp, row); if (strand == Seq_strand_minus) { *printed_line = '<'; } else { *printed_line = '>'; } printed_line += 2; seqstart = AlnMgr2MapSeqAlignToBioseq(salp, start, row); if (strand == Seq_strand_minus) { while ((seqstart == ALNMGR_GAP || seqstart == ALNMGR_ROW_UNDEFINED) && start > 0) { /* count backward if we are in the gap */ start--; seqstart = AlnMgr2MapSeqAlignToBioseq(salp, start, row); } } else { while ((seqstart == ALNMGR_GAP || seqstart == ALNMGR_ROW_UNDEFINED) && start < stop) { /* count forward if we are in the gap */ start++; seqstart = AlnMgr2MapSeqAlignToBioseq(salp, start, row); } } sprintf (printed_line, "%*d", coord_len, seqstart); *(printed_line + coord_len) = ' '; } extern void WriteAlignmentInterleaveToFileEx (SeqAlignPtr salp, FILE *fp, Int4 seq_chars_per_row, Boolean show_substitutions, Boolean show_coordinates) { Int4 row, start, stop; Uint1Ptr alnbuf; Uint1Ptr seqbuf; Int4 alnbuf_len; Int4 aln_len = AlnMgr2GetAlnLength(salp, FALSE); CharPtr alnlabels; CharPtr printed_line; Int4 printed_line_len; CharPtr label_pos; Int4 label_len = 0; Int4 coord_len; if (salp == NULL || fp == NULL) return; alnlabels = GetSeqAlignLabels (salp, &label_len); if (alnlabels != NULL) { alnbuf = (Uint1Ptr) MemNew ((seq_chars_per_row + 1)* sizeof (Uint1)); if (alnbuf != NULL) { seqbuf = (Uint1Ptr) MemNew ((seq_chars_per_row + 1) * sizeof (Uint1)); if (seqbuf != NULL) { if (show_coordinates) { coord_len = GetMaxCoordLen(salp) + 3; } else { coord_len = 0; } printed_line_len = label_len + 1 + coord_len + seq_chars_per_row + 3; printed_line = (CharPtr) MemNew (printed_line_len * sizeof (Char)); if (printed_line != NULL) { printed_line [ printed_line_len - 1] = 0; printed_line [ printed_line_len - 2] = '\n'; start = 0; stop = seq_chars_per_row - 1; while (start < aln_len) { for (row = 1; row <= salp->dim; row++) { MemSet (printed_line, ' ', printed_line_len - 2); label_pos = alnlabels + (row - 1) * (label_len + 1) * sizeof (Char); MemCpy (printed_line, label_pos, StringLen (label_pos)); /* add coordinates and strand marker */ AddCoordToPrintedLine (printed_line + label_len + 1, salp, row, start, stop, coord_len - 3); AlignmentIntervalToString (salp, row, start, stop, 1, FALSE, seqbuf, alnbuf, &alnbuf_len, show_substitutions); MemCpy (printed_line + label_len + 1 + coord_len, alnbuf, alnbuf_len); fprintf (fp, printed_line); } fprintf (fp, "\n"); start = stop + 1; stop += seq_chars_per_row; } MemFree (printed_line); } MemFree (seqbuf); } MemFree (alnbuf); } MemFree (alnlabels); } } extern void WriteAlignmentInterleaveToFile (SeqAlignPtr salp, FILE *fp, Int4 seq_chars_per_row, Boolean show_substitutions) { WriteAlignmentInterleaveToFileEx (salp, fp, seq_chars_per_row, show_substitutions, FALSE); } extern void WriteAlignmentContiguousToFile (SeqAlignPtr salp, FILE *fp, Int4 seq_chars_per_row, Boolean show_substitutions) { Int4 num_segments; SeqAlignPtr tmp_salp; Int4 idx; CharPtr PNTR alnlabels = NULL; Int4Ptr label_len = NULL; Int4Ptr aln_len = NULL; Uint1Ptr alnbuf = NULL; Uint1Ptr seqbuf = NULL; CharPtr printed_line = NULL; Int4 alnbuf_len; Int4 printed_line_len; CharPtr label_pos; Int4 row, start, stop; if (salp == NULL || fp == NULL) return; num_segments = 0; for (tmp_salp = salp; tmp_salp != NULL; tmp_salp = tmp_salp->next) { num_segments++; } /* get labels and lengths for all segments */ alnlabels = (CharPtr PNTR) MemNew (sizeof (CharPtr) * num_segments); label_len = (Int4Ptr) MemNew (sizeof (Int4) * num_segments); aln_len = (Int4Ptr) MemNew (sizeof (Int4) * num_segments); if (alnlabels != NULL && label_len != NULL && aln_len != NULL) { for (tmp_salp = salp, idx = 0; tmp_salp != NULL && idx < num_segments; tmp_salp = tmp_salp->next, idx++) { alnlabels [idx] = GetSeqAlignLabels (tmp_salp, &label_len[idx]); aln_len [idx]= AlnMgr2GetAlnLength(tmp_salp, FALSE); } /* get buffers */ alnbuf = (Uint1Ptr) MemNew (seq_chars_per_row * sizeof (Uint1)); seqbuf = (Uint1Ptr) MemNew (seq_chars_per_row * sizeof (Uint1)); printed_line_len = seq_chars_per_row + 3; printed_line = (CharPtr) MemNew (printed_line_len * sizeof (Char)); if (alnbuf != NULL && seqbuf != NULL && printed_line != NULL) { printed_line [ printed_line_len - 1] = 0; printed_line [ printed_line_len - 2] = '\n'; for (row = 1; row <= salp->dim; row++) { if (salp->next != NULL) { fprintf (fp, "[\n"); } for (tmp_salp = salp, idx = 0; tmp_salp != NULL && idx < num_segments; tmp_salp = tmp_salp->next, idx++) { label_pos = alnlabels [idx] + (row - 1) * (label_len[idx] + 1) * sizeof (Char); fprintf (fp, ">%s\n", label_pos); start = 0; stop = seq_chars_per_row - 1; while (start < aln_len [idx]) { MemSet (printed_line, ' ', printed_line_len - 2); AlignmentIntervalToString (tmp_salp, row, start, stop, 1, TRUE, seqbuf, alnbuf, &alnbuf_len, show_substitutions); MemCpy (printed_line, alnbuf, alnbuf_len); fprintf (fp, printed_line); start = stop + 1; stop += seq_chars_per_row; } fprintf (fp, "\n"); } if (salp->next != NULL) { fprintf (fp, "]\n"); } } } MemFree (alnbuf); MemFree (seqbuf); MemFree (printed_line); } MemFree (label_len); MemFree (alnlabels); MemFree (aln_len); } static void SeqAlnExportAln (SeqEdFormPtr sefp, Boolean interleave) { FILE *fp; Char path[PATH_MAX]; if (sefp == NULL || sefp->bfp == NULL || sefp->bfp->bvd.salp == NULL) { return; } if (! GetOutputFileName (path, sizeof (path), "")) return; fp = FileOpen (path, "w"); if (fp == NULL) { Message (MSG_ERROR, "Unable to open %s", path); return; } if (interleave) { WriteAlignmentInterleaveToFile (sefp->bfp->bvd.salp, fp, sefp->bfp->bvd.CharsAtLine, sefp->bfp->bvd.showAlnSubstitutions); } else { WriteAlignmentContiguousToFile (sefp->bfp->bvd.salp, fp, sefp->bfp->bvd.CharsAtLine, sefp->bfp->bvd.showAlnSubstitutions); } FileClose (fp); } static void SeqAlnExportAlnMenuItem (IteM i, Boolean interleave) { SeqEdFormPtr sefp; sefp = (SeqEdFormPtr) GetObjectExtra (i); SeqAlnExportAln (sefp, interleave); } static void SeqAlnExportInterleave (IteM i) { SeqAlnExportAlnMenuItem (i, TRUE); } static void SeqAlnExportContiguous (IteM i) { SeqAlnExportAlnMenuItem (i, FALSE); } static void SeqAlnExportText (IteM m) { SeqEdFormPtr sefp; FILE *fp; Char path[PATH_MAX]; BioseqViewPtr bvp; SeqPanLinePtr splp; Uint1Ptr file_line; Int4 line; Int4 aln_idx; Uint1Ptr seqbuf = NULL, alnbuf = NULL; Int4 prev_line; sefp = (SeqEdFormPtr) GetObjectExtra (m); if (sefp == NULL) return; if (! GetOutputFileName (path, sizeof (path), "")) return; fp = FileOpen (path, "w"); if (fp == NULL) { Message (MSG_ERROR, "Unable to open %s", path); return; } bvp = &(sefp->bfp->bvd); if (bvp == NULL || bvp->bsp == NULL) return; seqbuf = MemNew ((bvp->BlocksAtLine * SEQ_GROUP_SIZE + 3) * sizeof (Uint1)); alnbuf = MemNew ((bvp->BlocksAtLine * SEQ_GROUP_SIZE + 3) * sizeof (Uint1)); file_line = MemNew (SEQ_ED_PRINT_SEQ_OFFSET + bvp->CharsAtLine + 1); if (file_line == NULL) return; file_line [bvp->CharsAtLine + 13] = 0; aln_idx = 0; prev_line = 0; for (line = 0; line < bvp->TotalLines; line++) { splp = bvp->SeqPanLines[line]; switch ( splp->lineType ) { case eTypeAlignSequence: if (splp->bioSeqLine != prev_line) { prev_line = splp->bioSeqLine; fprintf (fp, "\n"); } PrintAlignment ((CharPtr)file_line, splp->bioSeqLine, splp->row, seqbuf, alnbuf, bvp, aln_idx); fprintf (fp, "%s\n", file_line); break; case eTypeAlignDivider: PrintAligmentDivider ((CharPtr)file_line, bvp->CharsAtLine, bvp->BlocksAtLine); aln_idx++; break; case eTypeFeature: PrintFeature((CharPtr)file_line, splp->bioSeqLine, splp->row, splp->idx, splp->protProduct, bvp->bsp, bvp); fprintf (fp, "%s\n", file_line); break; } } seqbuf = MemFree (seqbuf); alnbuf = MemFree (alnbuf); MemFree (file_line); FileClose (fp); } static void SeqAlnShowSubstitutionsMenuItem (IteM i) { SeqEdFormPtr sefp; WindoW temport; sefp = (SeqEdFormPtr) GetObjectExtra (i); if (sefp != NULL && sefp->bfp != NULL) { sefp->bfp->bvd.showAlnSubstitutions = GetStatus (i); temport = SavePort(sefp->form); Select (sefp->bfp->bvd.seqView); inval_panel (sefp->bfp->bvd.seqView, -1, -1); RestorePort (temport); Update (); } } static void UpdateTargetMenu (SeqEdFormPtr sefp); static void RemoveSequencesFromAlignment (IteM i) { SeqEdFormPtr sefp; Int4 n; SeqIdPtr sip; BioseqPtr bsp; SeqEntryPtr sep; ValNodePtr sip_list = NULL, vnp; Int4 num_to_remove; SeqEntryPtr oldscope; sefp = (SeqEdFormPtr) GetObjectExtra (i); if (sefp != NULL && sefp->bfp != NULL && sefp->bfp->bvd.salp != NULL) { if (sefp->bfp->bvd.salp->segtype != SAS_DENSEG) { Message (MSG_ERROR, "You cannot remove sequences from a pairwise alignment. You must convert it first."); return; } sep = GetTopSeqEntryForEntityID (sefp->input_entityID); /* first, check for pairwise alignments */ for (n = 1; n <= sefp->bfp->bvd.salp->dim; n++) { sip = AlnMgr2GetNthSeqIdPtr(sefp->bfp->bvd.salp, n); bsp = BioseqFind (sip); if (bsp == NULL) { oldscope = SeqEntrySetScope (NULL); bsp = BioseqFind (sip); SeqEntrySetScope (oldscope); } if (bsp != NULL && isSelected (bsp->idx.entityID, bsp->idx.itemID, OBJ_BIOSEQ, &(sefp->bfp->bvd))) { if (IsSequenceFirstInPairwise (sep, sip)) { Message (MSG_ERROR, "One of the selected sequences is the first in a pairwise alignment." " You must convert the alignment to a multiple alignment before trying to remove this sequence."); sip_list = ValNodeFree (sip_list); return; } else { ValNodeAddPointer (&sip_list, bsp->idx.itemID, sip); } } } if (sip_list == NULL) { Message (MSG_ERROR, "You must select a sequence to remove!"); return; } num_to_remove = ValNodeLen (sip_list); if (ANS_CANCEL == Message (MSG_OKC, "You are about to remove %d sequence%s from the alignment. Are you sure?", num_to_remove, num_to_remove == 1 ? "" : "s")) { sip_list = ValNodeFree (sip_list); return; } for (vnp = sip_list; vnp != NULL; vnp = vnp->next) { SeqAlignBioseqDeleteById (sefp->bfp->bvd.salp, vnp->data.ptrvalue); ObjMgrDeSelect (sefp->input_entityID, vnp->choice, OBJ_BIOSEQ, 0, NULL); } sip_list = ValNodeFree (sip_list); DeleteMarkedObjects (sefp->input_entityID, 0, NULL); ObjMgrSetDirtyFlag (sefp->input_entityID, TRUE); ObjMgrSendMsg (OM_MSG_UPDATE, sefp->input_entityID, 0, 0); /* reindex alignment */ SAIndex2Free2(sefp->bfp->bvd.salp->saip); sefp->bfp->bvd.salp->saip = NULL; AlnMgr2IndexSeqAlign(sefp->bfp->bvd.salp); /* update target selector */ UpdateTargetMenu (sefp); /* update alignment editor window */ ResizeSeqEditorWindow ((WindoW)sefp->form); } } static void ReverseSequenceStrandsInAlignment (IteM i) { SeqEdFormPtr sefp; Int4 n; SeqIdPtr sip; BioseqPtr bsp; SeqEntryPtr sep; ValNodePtr order_list = NULL, vnp; Int4 num_to_reverse; SeqEntryPtr oldscope; sefp = (SeqEdFormPtr) GetObjectExtra (i); if (sefp != NULL && sefp->bfp != NULL && sefp->bfp->bvd.salp != NULL) { if (sefp->bfp->bvd.salp->segtype != SAS_DENSEG) { Message (MSG_ERROR, "You cannot reverse sequence strands in a pairwise alignment. You must convert it first."); return; } sep = GetTopSeqEntryForEntityID (sefp->input_entityID); /* first, check for pairwise alignments */ for (n = 1; n <= sefp->bfp->bvd.salp->dim; n++) { sip = AlnMgr2GetNthSeqIdPtr(sefp->bfp->bvd.salp, n); bsp = BioseqFind (sip); if (bsp == NULL) { oldscope = SeqEntrySetScope (NULL); bsp = BioseqFind (sip); SeqEntrySetScope (oldscope); } if (bsp != NULL && isSelected (bsp->idx.entityID, bsp->idx.itemID, OBJ_BIOSEQ, &(sefp->bfp->bvd))) { ValNodeAddInt (&order_list, 0, n); } } if (order_list == NULL) { Message (MSG_ERROR, "You must select a sequence for strand reversal!"); return; } num_to_reverse = ValNodeLen (order_list); if (ANS_CANCEL == Message (MSG_OKC, "You are about to reverse %d sequence%s in the alignment. Are you sure?", num_to_reverse, num_to_reverse == 1 ? "" : "s")) { order_list = ValNodeFree (order_list); return; } for (vnp = order_list; vnp != NULL; vnp = vnp->next) { ReverseAlignmentStrand (sefp->bfp->bvd.salp, vnp->data.intvalue); } order_list = ValNodeFree (order_list); ObjMgrSetDirtyFlag (sefp->input_entityID, TRUE); ObjMgrSendMsg (OM_MSG_UPDATE, sefp->input_entityID, 0, 0); /* reindex alignment */ SAIndex2Free2(sefp->bfp->bvd.salp->saip); sefp->bfp->bvd.salp->saip = NULL; AlnMgr2IndexSeqAlign(sefp->bfp->bvd.salp); /* update alignment editor window */ ResizeSeqEditorWindow ((WindoW)sefp->form); } } typedef struct setalntarget { SeqEdFormPtr sefp; Int4 target; } SetAlnTargetData, PNTR SetAlnTargetPtr; static void SeqAlnSetTarget (IteM i) { SetAlnTargetPtr satp; satp = (SetAlnTargetPtr) GetObjectExtra (i); if (satp != NULL && satp->sefp != NULL && satp->sefp->bfp != NULL && satp->sefp->bfp->bvd.salp != NULL && satp->target > 0 && satp->target <= satp->sefp->bfp->bvd.salp->dim) { satp->sefp->bfp->bvd.TargetRow = satp->target; ResizeSeqEditorWindow ((WindoW) satp->sefp->form); } } static void SeqAlnValidateAlignment (IteM i) { SeqEdFormPtr sefp; sefp = (SeqEdFormPtr) GetObjectExtra (i); if (sefp == NULL) return; ValidateSeqAlign (sefp->bfp->bvd.salp, 0, TRUE, TRUE, TRUE, FALSE, FALSE, NULL); } static void SeqAlnFeaturePropagate (IteM i) { SeqEdFormPtr sefp; BioseqPtr bsp = NULL; ForM f; SeqMgrFeatContext fcontext; Uint4 itemID = 0; SeqFeatPtr sfp; SelStructPtr sel; SeqEntryPtr sep; SeqIdPtr sip = NULL; sefp = (SeqEdFormPtr) GetObjectExtra (i); if (sefp == NULL || sefp->bfp->bvd.salp == NULL) return; sep = GetTopSeqEntryForEntityID (sefp->input_entityID); if (sep == NULL) return; if (sefp->bfp->bvd.TargetRow > 0 && sefp->bfp->bvd.TargetRow <= sefp->bfp->bvd.salp->dim) { sip = AlnMgr2GetNthSeqIdPtr(sefp->bfp->bvd.salp, sefp->bfp->bvd.TargetRow); if (sip != NULL) { bsp = BioseqFind (sip); } } if (bsp == NULL) { Message (MSG_OK, "You must target a single sequence in order to propagate"); return; } sfp = GetNextFeatureOnSegOrMaster (bsp, NULL, 0, 0, &fcontext); if (sfp == NULL) { Message (MSG_OK, "The sequence must have features in order to propagate"); return; } sel = ObjMgrGetSelected (); if (sel != NULL && sel->entityID == sefp->input_entityID && sel->next == NULL && sel->itemtype == OBJ_SEQFEAT) { sfp = SeqMgrGetDesiredFeature (sefp->input_entityID, NULL, sel->itemID, 0, NULL, &fcontext); if (sfp != NULL && fcontext.bsp == bsp) { itemID = sel->itemID; } } f = FeaturePropagateForm (bsp, sefp->bfp->bvd.salp, itemID); if (f == NULL) return; Show (f); Select (f); } static SeqLocPtr GetSeqLocForAlignmentEdit (SeqEdFormPtr sefp) { Int4 real_start, real_stop, aln_len; Uint1 strand; SeqLocPtr slp; SeqIdPtr sip; if (sefp == NULL || sefp->bfp->bvd.salp == NULL) { return NULL; } real_start = sefp->edit_pos_start + 1; real_stop = sefp->edit_pos_end; if (real_start < 1) { real_start = 1; } if (real_stop < real_start) { real_stop = real_start; } aln_len = SeqAlignLength (sefp->bfp->bvd.salp); if (real_start == 1 && real_stop == 1) { real_stop = aln_len; } AdjustFromForGap (&real_start, sefp->bfp->bvd.salp, aln_len, sefp->bfp->bvd.TargetRow); AdjustToForGap (&real_stop, sefp->bfp->bvd.salp, sefp->bfp->bvd.TargetRow); strand = AlnMgr2GetNthStrand (sefp->bfp->bvd.salp, sefp->bfp->bvd.TargetRow); real_start --; real_stop --; sip = AlnMgr2GetNthSeqIdPtr(sefp->bfp->bvd.salp, sefp->bfp->bvd.TargetRow); slp = SeqLocIntNew (real_start, real_stop, strand, sip); return slp; } static void AlnEdApplyFeatureToAlignment (IteM i, Int4 feattype) { SeqEdFormPtr sefp; SeqLocPtr slp; sefp = (SeqEdFormPtr) GetObjectExtra (i); if (sefp == NULL || sefp->bfp->bvd.salp == NULL) return; slp = GetSeqLocForAlignmentEdit (sefp); ApplyFeatureToAlignment (sefp->input_entityID, sefp->bfp->bvd.salp, slp, feattype); } static void ApplyCDSToAlignment (IteM i) { AlnEdApplyFeatureToAlignment (i, ADD_CDS); } static void ApplyRRNAToAlignment (IteM i) { AlnEdApplyFeatureToAlignment (i, ADD_RRNA); } static void ApplyOtherFeatureToAlignment (IteM i) { AlnEdApplyFeatureToAlignment (i, ADD_IMP); } static BioseqSetPtr GetTopSetForBioseq (BioseqPtr bsp) { BioseqSetPtr bssp = NULL; SeqEntryPtr sep; Uint2 parenttype; Pointer parentptr; if (bsp == NULL) { return NULL; } sep = GetBestTopParentForData (bsp->idx.entityID, bsp); if (sep == NULL || sep->data.ptrvalue == NULL) { return NULL; } if (IS_Bioseq (sep)) { GetSeqEntryParent (sep, &parentptr, &parenttype); if (parenttype == OBJ_BIOSEQSET) { bssp = (BioseqSetPtr) parentptr; } } else { bssp = (BioseqSetPtr) sep->data.ptrvalue; if (bssp->_class == BioseqseqSet_class_nuc_prot || bssp->_class == BioseqseqSet_class_segset) { GetSeqEntryParent (sep, &parentptr, &parenttype); if (parenttype == OBJ_BIOSEQSET) { bssp = (BioseqSetPtr) parentptr; } } } return bssp; } static Boolean IsAlignmentOnSet (SeqAlignPtr salp) { Int4 n; SeqIdPtr sip; BioseqPtr bsp; BioseqSetPtr bssp; Boolean rval = TRUE; if (salp == NULL) { return FALSE; } for (n = 1; n <= salp->dim && rval; n++) { sip = AlnMgr2GetNthSeqIdPtr(salp, n); bsp = BioseqFind (sip); if (bsp == NULL) { rval = FALSE; } else { bssp = GetTopSetForBioseq (bsp); if (bssp == NULL || !IsPopPhyEtcSet (bssp->_class)) { rval = FALSE; } } } return rval; } static void UpdateTargetMenu (SeqEdFormPtr sefp) { Int4 n; SetAlnTargetPtr satp; IteM localItem; SeqIdPtr sip; BioseqPtr bsp; Char label [128]; if (sefp == NULL) { return; } Reset (sefp->aln_target_menu); for (n = 1; n <= sefp->bfp->bvd.salp->dim; n++) { sip = AlnMgr2GetNthSeqIdPtr(sefp->bfp->bvd.salp, n); bsp = BioseqFind (sip); if (bsp != NULL) { sip = SeqIdFindBestAccession (bsp->id); } SeqIdWrite (sip, label, PRINTID_REPORT, sizeof (label) - 1); localItem = CommandItem (sefp->aln_target_menu, label, SeqAlnSetTarget); satp = (SetAlnTargetPtr) MemNew (sizeof (SetAlnTargetData)); if (satp != NULL) { satp->sefp = sefp; satp->target = n; } SetObjectExtra (localItem, satp, StdCleanupExtraProc); } } static void CreateAlnMenus (WindoW w, Boolean enable_feat_prop, Boolean allow_feat) { MenU edit_menu; IteM localItem; MenU sub; SeqEdFormPtr sefp; Boolean indexerVersion; if (w == NULL) return; sefp = (SeqEdFormPtr) GetObjectExtra (w); if (sefp == NULL) return; indexerVersion = (Boolean) (GetAppProperty ("InternalNcbiSequin") != NULL); /* File Menu */ edit_menu = PulldownMenu (w, "File"); sub = SubMenu (edit_menu, "Export"); localItem = CommandItem (sub, "Interleave", SeqAlnExportInterleave); SetObjectExtra (localItem, sefp, NULL); localItem = CommandItem (sub, "Contiguous", SeqAlnExportContiguous); SetObjectExtra (localItem, sefp, NULL); localItem = CommandItem (sub, "Text Representation", SeqAlnExportText); SetObjectExtra (localItem, sefp, NULL); localItem = CommandItem (edit_menu, "Close", SeqAlnCloseMenuItem); SetObjectExtra (localItem, sefp, NULL); /* Edit Menu */ edit_menu = PulldownMenu (w, "Edit"); if (indexerVersion) { localItem = CommandItem (edit_menu, "Remove Sequences From Alignment", RemoveSequencesFromAlignment); SetObjectExtra (localItem, sefp, NULL); } localItem = CommandItem (edit_menu, "Reverse Sequence Strands In Alignment", ReverseSequenceStrandsInAlignment); SetObjectExtra (localItem, sefp, NULL); localItem = CommandItem (edit_menu, "Validate Alignment", SeqAlnValidateAlignment); SetObjectExtra (localItem, sefp, NULL); localItem = CommandItem (edit_menu, "Propagate Features", SeqAlnFeaturePropagate); SetObjectExtra (localItem, sefp, NULL); if (!enable_feat_prop) { Disable (localItem); } /* View menu */ edit_menu = PulldownMenu (w, "View"); sefp->aln_target_menu = SubMenu (edit_menu, "Target"); UpdateTargetMenu (sefp); localItem = StatusItem (edit_menu, "Show Substitutions", SeqAlnShowSubstitutionsMenuItem); SetObjectExtra (localItem, sefp, NULL); /* Features Menu */ edit_menu = PulldownMenu (w, "Features"); sub = SubMenu (edit_menu, "Apply To Target Sequence"); SeqEdNewFeaturesMenu (sub, TRUE); if (!allow_feat) { Disable (sub); } sub = SubMenu (edit_menu, "Apply To Alignment"); localItem = CommandItem (sub, "CDS", ApplyCDSToAlignment); SetObjectExtra (localItem, sefp, NULL); localItem = CommandItem (sub, "RNA", ApplyRRNAToAlignment); SetObjectExtra (localItem, sefp, NULL); localItem = CommandItem (sub, "Other Feature", ApplyOtherFeatureToAlignment); SetObjectExtra (localItem, sefp, NULL); if (!allow_feat) { Disable (sub); } } extern ForM CreateAlnEditorWindowEx (Int2 left, Int2 top, CharPtr windowname, SeqAlignPtr salp, Uint2 entityID, Nlm_ChangeNotifyProc on_close_func, Pointer on_close_data) { SeqEdFormPtr sefp; WindoW w; GrouP g; Char str [16]; Int2 window_width = 650; Int2 window_hgt = 300, charwidth, lineheight; FonT font; Int4 btns_across; OMUserDataPtr omudp; if (salp == NULL) { return NULL; } sefp = SeqEdFormNew (); if (sefp == NULL) { return NULL; } sefp->on_close_func = on_close_func; sefp->on_close_data = on_close_data; sefp->annot = GetSeqAnnotForAlignment (salp); #ifdef WIN_MAC font = ParseFont ("Monaco, 9"); #endif #ifdef WIN_MSWIN font = ParseFont ("Courier, 9"); #endif #ifdef WIN_MOTIF font = ParseFont ("fixed, 12"); #endif SelectFont (font); charwidth = CharWidth ('0'); lineheight = FontHeight () + SEQ_Y_OFFSET; w = DocumentWindow (left, top, (Int2)(-10), (Int2)(-10), windowname, NULL, ResizeSeqEditorWindow); SetObjectExtra (w, (Pointer) sefp, CleanupSeqEdForm); sefp->form = (ForM) w; sefp->formmessage = SeqEdFormMessage; sefp->input_entityID = entityID; /* initialize view pointer */ sefp->bfp = (BioseqViewFormPtr) MemNew (sizeof (BioseqViewForm)); if (sefp->bfp == NULL) return NULL; sefp->bfp->bvd.seqAlignMode = TRUE; sefp->bfp->bvd.salp = salp; AlnMgr2IndexSeqAlign(sefp->bfp->bvd.salp); /* lock elements of the alignment that could be cached out */ sefp->locked_aln_bioseqs = LockFarAlignmentBioseqs (sefp->bfp->bvd.salp); /* find first viewable target */ sefp->bfp->bvd.TargetRow = 1; sefp->bfp->bvd.bsp = LockNthBioseqInAlignment(sefp->bfp->bvd.salp, sefp->bfp->bvd.TargetRow); while (sefp->bfp->bvd.bsp == NULL && sefp->bfp->bvd.TargetRow < sefp->bfp->bvd.salp->dim) { sefp->bfp->bvd.TargetRow ++; sefp->bfp->bvd.bsp = LockNthBioseqInAlignment(sefp->bfp->bvd.salp, sefp->bfp->bvd.TargetRow); } sefp->bfp->bvd.DrawGrid = FALSE; sefp->bfp->bvd.SeqStartPosX = (FindMaxLabelLen (sefp->bfp->bvd.salp) + 10) * charwidth; sefp->bfp->bvd.CharHeight = FontHeight (); sefp->bfp->bvd.displayFont = font; sefp->bfp->bvd.LineHeight = lineheight; sefp->bfp->bvd.CharWidth = charwidth; sefp->bfp->bvd.seq_entityID = sefp->input_entityID; sefp->bfp->bvd.on_the_fly = FALSE; sefp->bfp->bvd.showAlnSubstitutions = FALSE; CreateAlnMenus (w, IsAlignmentOnSet (sefp->bfp->bvd.salp), (Boolean)(salp->segtype == SAS_DENSEG)); btns_across = 4; sefp->upper_button_group = HiddenGroup (w, -10, -10, NULL); SetGroupSpacing (sefp->upper_button_group, 10, 3); g = HiddenGroup (sefp->upper_button_group, btns_across, 0, NULL); SetGroupSpacing (g, 10, 3); sprintf (str, "%ld", (long) sefp->edit_pos_start); sefp->goto_btn = PushButton (g, "Go to alignment position:", SeqAlnGoToAlnPosBtn); sefp->goto_txt = DialogText (g, str, (Int2)6, NULL); sefp->lookat_btn = PushButton (g, "Go to sequence position:", SeqAlnGoToSeqPosBtn); sefp->lookat_txt = DialogText (g, str, (Int2)6, NULL); /* numbering location and grid controls */ StaticPrompt (g, " Numbering: ", 0, popupMenuHeight, programFont, 'l'); sefp->bfp->bvd.newNumControl = PopupList (g, TRUE, ChangeSeqEditControls); SetObjectExtra (sefp->bfp->bvd.newNumControl, sefp, NULL); PopupItem (sefp->bfp->bvd.newNumControl, "None"); PopupItem (sefp->bfp->bvd.newNumControl, "Side"); PopupItem (sefp->bfp->bvd.newNumControl, "Top"); SetValue (sefp->bfp->bvd.newNumControl, 3); StaticPrompt (g, " Grid: ", 0, popupMenuHeight, programFont, 'l'); sefp->bfp->bvd.newGridControl = PopupList (g, TRUE, ChangeSeqEditControls); SetObjectExtra (sefp->bfp->bvd.newGridControl, sefp, NULL); PopupItem (sefp->bfp->bvd.newGridControl, "On"); PopupItem (sefp->bfp->bvd.newGridControl, "Off"); SetValue (sefp->bfp->bvd.newGridControl, 2); g = HiddenGroup (w, 1, 0, NULL); sefp->position_label = StaticPrompt (g, "", window_width, dialogTextHeight, programFont, 'l'); SeqEdUpdateStatus (sefp); g = HiddenGroup (w, 1, 0, NULL); sefp->bfp->bvd.seqView = AutonomousPanel4 (g, window_width, window_hgt, onDrawSeqPanel, onVScrollBarSeqPanel, NULL, sizeof (BioseqViewPtr), onCloseSeqPanel, NULL); SetObjectExtra (sefp->bfp->bvd.seqView, sefp->bfp, NULL); sefp->lower_button_group = HiddenGroup (w, 6, 0, NULL); SetGroupSpacing (sefp->lower_button_group, 10, 3); StaticPrompt (sefp->lower_button_group, "Features:", 0, dialogTextHeight, programFont, 'l'); sefp->bfp->bvd.newFeatControl = PopupList (sefp->lower_button_group, TRUE, ChangeSeqEditControls); PopupItem (sefp->bfp->bvd.newFeatControl, "Target Sequence"); PopupItem (sefp->bfp->bvd.newFeatControl, "Hidden"); PopupItem (sefp->bfp->bvd.newFeatControl, "All Sequences"); SetValue (sefp->bfp->bvd.newFeatControl, 2); SetObjectExtra (sefp->bfp->bvd.newFeatControl, sefp, NULL); sefp->accept = PushButton (sefp->lower_button_group, "Close", SeqAlnCloseButton); SetObjectExtra (sefp->accept, sefp, NULL); ResizeSeqView (&(sefp->bfp->bvd)); RealizeWindow (w); /* SetSlateChar ((SlatE) sefp->bfp->bvd.seqView, SeqEdOnKey); */ SetSeqAlnPanelClick (sefp); /* register to receive update messages */ sefp->userkey = OMGetNextUserKey (); sefp->procid = 0; sefp->proctype = OMPROC_EDIT; sefp->input_itemtype = OBJ_SEQANNOT; sefp->input_itemID = sefp->annot->idx.itemID; omudp = ObjMgrAddUserData (sefp->input_entityID, sefp->procid, sefp->proctype, sefp->userkey); if (omudp != NULL) { omudp->userdata.ptrvalue = (Pointer) sefp; omudp->messagefunc = SeqEditMsgFunc; } return (ForM) w; } extern ForM CreateAlnEditorWindow (Int2 left, Int2 top, CharPtr windowname, SeqAlignPtr salp, Uint2 entityID) { return CreateAlnEditorWindowEx (left, top, windowname, salp, entityID, NULL, NULL); } BioseqPageData seqpnlPageData = { "Sequence", TRUE, TRUE, TRUE, FALSE, -1, PopulateSeqView, ShowSeqView, SelectSeqView, NULL, NULL, NULL, NULL, ResizeSeqView, NULL }; BioseqPageData seqAlnPnlPageData = { "Alignment", TRUE, TRUE, TRUE, TRUE, -1, PopulateAlnView, ShowSeqView, SelectSeqView, NULL, NULL, NULL, NULL, ResizeSeqView, NULL }; #define SEQ_ED_TRANSLATE_BUFFER_SIZE 32000 NLM_EXTERN SeqEdJournalPtr SeqEdJournalNewTranslate (SeqFeatPtr sfp, BioseqPtr bsp, Uint2 entityID) { SeqEdJournalPtr sejp; BioseqPtr product_bsp; SeqEntryPtr sep; AsnIoMemPtr aimp; if (sfp == NULL) return NULL; sejp = (SeqEdJournalPtr) MemNew (sizeof (SeqEdJournalData)); if (sejp == NULL) return NULL; sejp->action = eSeqEdTranslate; sejp->offset = 0; sejp->spliteditmode = FALSE; sejp->sfp = sfp; sejp->slp = NULL; sejp->bsp = bsp; sejp->moltype = 0; sejp->entityID = entityID; sejp->prev = NULL; sejp->next = NULL; sejp->char_data = MemNew (SEQ_ED_TRANSLATE_BUFFER_SIZE); if (sejp->char_data == NULL) { sejp = MemFree (sejp); return sejp; } sejp->num_chars = 0; product_bsp = BioseqFindFromSeqLoc (sfp->product); if (product_bsp != NULL) { sep = product_bsp->seqentry; aimp = AsnIoMemOpen("wb", (BytePtr)sejp->char_data, SEQ_ED_TRANSLATE_BUFFER_SIZE); /* open to write asn1 to it */ SeqEntryAsnWrite(sep, aimp->aip, NULL); /* write it */ AsnIoFlush(aimp->aip); /* flush it */ sejp->num_chars = aimp->count; /* record how many bytes in it */ AsnIoMemClose(aimp); /* close it */ if (sejp->num_chars == SEQ_ED_TRANSLATE_BUFFER_SIZE) { /* unable to write record */ sejp->char_data = MemFree (sejp->char_data); sejp = MemFree (sejp); } } return sejp; } static Boolean UnplayOneTranslationJournalEntry (SeqEdJournalPtr sejp) { BioseqPtr product_bsp; SeqEntryPtr current_sep = NULL, prev_sep = NULL; SeqEntryPtr top_sep; AsnIoMemPtr aimp; SeqLocPtr product_slp = NULL; if (sejp == NULL || sejp->action != eSeqEdTranslate || sejp->sfp == NULL || sejp->sfp->idx.subtype != FEATDEF_CDS) { return FALSE; } product_bsp = BioseqFindFromSeqLoc (sejp->sfp->product); if (product_bsp != NULL) { current_sep = product_bsp->seqentry; } if (sejp->num_chars > 0) { aimp = AsnIoMemOpen("rb", (BytePtr)sejp->char_data, sejp->num_chars); /* open to read from buffer */ prev_sep = SeqEntryAsnRead(aimp->aip, NULL); /* read it */ AsnIoMemClose(aimp); /* close it */ product_bsp = (BioseqPtr) prev_sep->data.ptrvalue; product_slp = ValNodeNew (NULL); if (product_slp != NULL) { product_slp->choice = SEQLOC_WHOLE; product_slp->data.ptrvalue = SeqIdDup (SeqIdFindBest (product_bsp->id, 0)); } } if (current_sep == NULL) { sejp->num_chars = 0; } else { aimp = AsnIoMemOpen("wb", (BytePtr)sejp->char_data, SEQ_ED_TRANSLATE_BUFFER_SIZE); /* open to write asn1 to it */ SeqEntryAsnWrite(current_sep, aimp->aip, NULL); /* write it */ AsnIoFlush(aimp->aip); /* flush it */ sejp->num_chars = aimp->count; /* record how many bytes in it */ AsnIoMemClose(aimp); /* close it */ } if (current_sep == NULL && prev_sep == NULL) { /* do nothing */ } else if (current_sep == NULL) { /* add product to feature where there wasn't one before */ AddSeqEntryToSeqEntry (sejp->bsp->seqentry, prev_sep, TRUE); } else if (prev_sep == NULL) { /* remove product from feature */ top_sep = GetTopSeqEntryForEntityID (sejp->entityID); RemoveSeqEntryFromSeqEntry (top_sep, current_sep, TRUE); } else { /* replace product sequence */ ReplaceSeqEntryWithSeqEntry (current_sep, prev_sep, TRUE); } sejp->sfp->product = product_slp; return TRUE; } static Boolean PlayOneTranslationJournalEntry (SeqEdJournalPtr sejp) { BioseqPtr product_bsp; SeqEntryPtr current_sep; AsnIoMemPtr aimp; if (sejp == NULL || sejp->action != eSeqEdTranslate || sejp->sfp == NULL || sejp->sfp->idx.subtype != FEATDEF_CDS) { return FALSE; } product_bsp = BioseqFindFromSeqLoc (sejp->sfp->product); if (product_bsp == NULL) { sejp->num_chars = 0; } else { current_sep = product_bsp->seqentry; aimp = AsnIoMemOpen("wb", (BytePtr)sejp->char_data, SEQ_ED_TRANSLATE_BUFFER_SIZE); /* open to write asn1 to it */ SeqEntryAsnWrite(current_sep, aimp->aip, NULL); /* write it */ AsnIoFlush(aimp->aip); /* flush it */ sejp->num_chars = aimp->count; /* record how many bytes in it */ AsnIoMemClose(aimp); /* close it */ } SeqEdTranslateOneCDS (sejp->sfp, sejp->bsp, sejp->entityID, Sequin_GlobalAlign2Seq); return TRUE; } static Boolean PlayOneJournalEntry (SeqEdJournalPtr sejp, BoolPtr pfeats_deleted) { Boolean rval = FALSE; SeqLocPtr slp; SeqPortPtr spp; if (sejp == NULL) return rval; switch (sejp->action) { case eSeqEdInsert: case eSeqEdInsertGap: rval = SeqEdInsert (sejp); break; case eSeqEdDelete: case eSeqEdDeleteGap: slp = SeqLocIntNew (sejp->offset, sejp->offset + sejp->num_chars - 1, Seq_strand_plus, sejp->bsp->id); spp = SeqPortNewByLoc (slp, Seq_code_iupacna); SeqPortRead (spp, (Uint1Ptr)sejp->char_data, sejp->num_chars + 1); SeqPortFree (spp); SeqEdDeleteFromBsp (sejp, pfeats_deleted); SeqLocFree (slp); rval = TRUE; break; case eSeqEdFeatMove: slp = sejp->sfp->location; sejp->sfp->location = sejp->slp; sejp->slp = slp; SeqEdReindexFeature (sejp->sfp, sejp->bsp); rval = TRUE; break; case eSeqEdTranslate: rval = PlayOneTranslationJournalEntry (sejp); break; case eSeqEdJournalEnd: case eSeqEdJournalStart: rval = TRUE; break; } return rval; } static Boolean PlayJournal (SeqEdJournalPtr list, SeqEdJournalPtr PNTR last, Int4 num_steps, BoolPtr pfeats_deleted, SeqEdFormPtr sefp) { Boolean rval = TRUE; Int4 steps_removed = 0; while (list != NULL && list->action != eSeqEdJournalEnd && rval && (num_steps == -1 || steps_removed < num_steps)) { if (list->action != eSeqEdJournalStart) { rval = PlayOneJournalEntry (list, pfeats_deleted); steps_removed ++; } *last = list; list = list->next; } SeqEdReindexGaps (sefp, sefp->bfp->bvd.bsp); return rval; } static Boolean UnplayOneJournalEntry (SeqEdJournalPtr sejp) { Boolean rval = FALSE; SeqLocPtr slp; SeqPortPtr spp; if (sejp == NULL) return FALSE; switch (sejp->action) { case eSeqEdDelete: case eSeqEdDeleteGap: rval = SeqEdInsert (sejp); break; case eSeqEdInsert: case eSeqEdInsertGap: slp = SeqLocIntNew (sejp->offset, sejp->offset + sejp->num_chars - 1, Seq_strand_plus, sejp->bsp->id); spp = SeqPortNewByLoc (slp, Seq_code_iupacna); SeqPortRead (spp, (Uint1Ptr)sejp->char_data, sejp->num_chars); SeqPortFree (spp); SeqEdDeleteFromBsp (sejp, NULL); SeqLocFree (slp); rval = TRUE; break; case eSeqEdFeatMove: slp = sejp->sfp->location; sejp->sfp->location = sejp->slp; sejp->slp = slp; SeqEdReindexFeature (sejp->sfp, sejp->bsp); rval = TRUE; break; case eSeqEdTranslate: rval = UnplayOneTranslationJournalEntry (sejp); break; case eSeqEdJournalEnd: case eSeqEdJournalStart: rval = TRUE; break; } return rval; } static Boolean UnplayJournal (SeqEdJournalPtr PNTR last, Int4 num_steps, SeqEdFormPtr sefp) { Int4 steps_removed = 0; Boolean rval = TRUE; if (last == NULL || *last == NULL) return FALSE; while (*last != NULL && (*last)->action != eSeqEdJournalStart && rval && (num_steps == -1 || steps_removed < num_steps)) { rval = UnplayOneJournalEntry (*last); if (rval) { if ((*last)->action != eSeqEdJournalEnd) { steps_removed ++; } *last = (*last)->prev; } } SeqEdReindexGaps (sefp, sefp->bfp->bvd.bsp); return rval; } static SeqAlignPtr LIBCALLBACK GetSeqAlignEx (BioseqPtr bsp1, BioseqPtr bsp2, Boolean no_extend) { BLAST_SummaryOptions *options = NULL; SeqAlignPtr salp = NULL; if (bsp1 == NULL || bsp2 == NULL) return NULL; BLAST_SummaryOptionsInit(&options); if (bsp1->length > 10000 || bsp2->length > 10000 || no_extend) { options->filter_string = StringSave ("m L"); if (no_extend) { options->word_size = 28; } else { options->word_size = 20; options->cutoff_evalue = act_get_eval (60); } options->hint = eNone; } else { options->filter_string = StringSave ("m F"); } if (ISA_na (bsp1->mol)) { options->program = eBlastn; } else { options->program = eBlastp; } BLAST_TwoSequencesSearch(options, bsp1, bsp2, &salp); BLAST_SummaryOptionsFree(options); return salp; } static SeqAlignPtr LIBCALLBACK GetSeqAlign (BioseqPtr bsp1, BioseqPtr bsp2) { return GetSeqAlignEx (bsp1, bsp2, FALSE); } static SeqAlignPtr LIBCALLBACK GetSeqAlignPiece (SeqLocPtr slp1, SeqLocPtr slp2) { BLAST_SummaryOptions *options = NULL; SBlastSeqalignArray * seqalign_arr=NULL; SeqAlignPtr salp = NULL; BioseqPtr bsp; if (slp1 == NULL || slp2 == NULL) return NULL; bsp = BioseqFindFromSeqLoc (slp1); if (bsp == NULL) { return NULL; } BLAST_SummaryOptionsInit(&options); if (ISA_na (bsp->mol)) { options->program = eBlastn; } else { options->program = eBlastp; } options->gapped_calculation = TRUE; options->cutoff_evalue = 10; options->gap_x_dropoff = 100; options->gap_open = 4; options->gap_extend = 1; options->nucleotide_mismatch = -1; options->word_size = 7; BLAST_TwoSeqLocSets(options, slp1, slp2, NULL, &seqalign_arr, NULL, NULL, NULL); if (seqalign_arr != NULL) { salp = seqalign_arr->array[0]; seqalign_arr->array[0] = NULL; seqalign_arr = SBlastSeqalignArrayFree(seqalign_arr); } BLAST_SummaryOptionsFree(options); return salp; } NLM_EXTERN SeqAlignPtr Sequin_GlobalAlign2Seq (BioseqPtr bsp1, BioseqPtr bsp2, BoolPtr revcomp) { return Sqn_GlobalAlign2SeqEx (bsp1, bsp2, revcomp, GetSeqAlign, GetSeqAlignPiece, TRUE); } /* This function produces a text representation of the alignment salp starting one nucleotide * before the feature and ending one nucleotide after the feature. */ NLM_EXTERN CharPtr FeatureLocationAlignment (SeqFeatPtr sfp, SeqAlignPtr salp, Int4 begin, Int4 fin) { Int4 start, stop, aln_start, aln_stop, orig_aln_len, aln_len, aln_pos, s,e; Uint1Ptr alnbuf, seqbuf; Int4 offset, feat_coord; Uint1 alnstrand, featstrand, effective_strand; if (sfp == NULL || salp == NULL) { return NULL; } start = SeqLocStart (sfp->location); stop = SeqLocStop (sfp->location); aln_start = AlnMgr2MapBioseqToSeqAlign (salp, start, begin); aln_stop = AlnMgr2MapBioseqToSeqAlign (salp, stop, begin); if (aln_start < 0 || aln_stop < 0) { return NULL; } featstrand = SeqLocStrand (sfp->location); alnstrand = AlnMgr2GetNthStrand (salp, begin); effective_strand = Seq_strand_plus; if ((featstrand == Seq_strand_minus && alnstrand != Seq_strand_minus) || (featstrand != Seq_strand_minus && alnstrand == Seq_strand_minus)) { effective_strand = Seq_strand_minus; } s = MIN (aln_start, aln_stop); e = MAX (aln_start, aln_stop); aln_start = s; aln_stop = e; aln_start = MAX (aln_start - 1, 0); aln_stop = aln_stop + 1; orig_aln_len = aln_stop - aln_start + 14; alnbuf = MemNew (orig_aln_len * 3); seqbuf = MemNew (orig_aln_len); aln_len = orig_aln_len; StringCpy ((CharPtr)alnbuf, "Old :"); offset = 8; AlignmentIntervalToString (salp, begin, aln_start, aln_stop, begin, FALSE, seqbuf, alnbuf + offset, &aln_len, TRUE); alnbuf [offset + aln_len] = '\n'; offset += aln_len + 1; aln_len = orig_aln_len; StringCpy ((CharPtr)alnbuf + offset, "New :"); offset += 8; AlignmentIntervalToString (salp, fin, aln_start, aln_stop, begin, FALSE, seqbuf, alnbuf + offset, &aln_len, TRUE); alnbuf [offset + aln_len] = '\n'; offset += aln_len + 1; StringCpy ((CharPtr)alnbuf + offset, "Feature:"); offset += 8; MemSet (alnbuf + offset, ' ', 3 * orig_aln_len - offset - 2); alnbuf [3 * orig_aln_len - 2] = '\n'; alnbuf [3 * orig_aln_len - 1] = 0; /* draw feature here */ for (aln_pos = aln_start; aln_pos <= aln_stop; aln_pos ++) { feat_coord = AlnMgr2MapSeqAlignToBioseq (salp, aln_pos, begin); if (feat_coord >= start && feat_coord <= stop) { alnbuf [offset + aln_pos - aln_start] = effective_strand == Seq_strand_minus ? '<' : '>'; } } return (CharPtr) alnbuf; } NLM_EXTERN Boolean CloseAlignmentEditor(Uint2 entityID, Uint4 itemID) { BaseFormPtr bfp; Uint4 j; Uint4 num; ObjMgrPtr omp; ObjMgrDataPtr PNTR omdpp; OMUserDataPtr omudp; ObjMgrDataPtr tmp; Boolean any = FALSE; ValNodePtr list = NULL, vnp; omp = ObjMgrGet (); if (omp == NULL) return FALSE; num = omp->currobj; for (j = 0, omdpp = omp->datalist; j < num && omdpp != NULL; j++, omdpp++) { tmp = *omdpp; if (tmp->parentptr == NULL && (tmp->EntityID == entityID || entityID == 0)) { for (omudp = tmp->userdata; omudp != NULL; omudp = omudp->next) { if (omudp->proctype == OMPROC_EDIT) { bfp = (BaseFormPtr) omudp->userdata.ptrvalue; if (bfp != NULL) { if ((bfp->input_itemID == itemID || itemID == 0) && bfp->input_itemtype == OBJ_SEQANNOT) { ValNodeAddPointer (&list, 0, bfp); any = TRUE; } } } } } } for (vnp = list; vnp != NULL; vnp = vnp->next) { SeqEdCancel ((SeqEdFormPtr) vnp->data.ptrvalue); } list = ValNodeFree (list); return any; }