in layer3/Seeker.cpp [1186:2171]
void SeekerUpdate(PyMOLGlobals * G)
{
/* CObject *o = NULL;
int s; */
void *hidden = NULL;
AtomInfoType *ai;
ObjectMolecule *obj;
int nRow = 0;
int label_mode = 0;
int codes = 0;
int max_row = 50;
int default_color = 0;
int align_sele = -1; /* alignment selection */
const int MAXCONSECUTIVEGAPS = 10;
CSeqRow *row_vla, *row, *lab = NULL;
row_vla = VLACalloc(CSeqRow, 10);
/* FIRST PASS: get all the residues represented properly */
label_mode = SettingGetGlobal_i(G, cSetting_seq_view_label_mode);
align_sele = ExecutiveGetActiveAlignmentSele(G);
while(ExecutiveIterateObjectMolecule(G, &obj, &hidden)) {
if(obj->Obj.Enabled && (SettingGet_b(G, obj->Obj.Setting, NULL, cSetting_seq_view)) &&
(obj->Obj.Name[0] != '_')) {
int a;
AtomInfoType *last = NULL, *last_segi = NULL, *last_chain = NULL;
CoordSet *last_disc = NULL;
int last_state;
int last_abbr = true;
int last_spacer = false;
int nCol = 0;
int nListEntries = 1; /* first list starts at 1 always... */
int est_col = obj->NAtom / 5 + 1;
int est_char = obj->NAtom * 4;
int first_atom_in_label;
int missing_color = SettingGet_i(G, obj->Obj.Setting, NULL, cSetting_seq_view_fill_color);
CoordSet *cs = obj->DiscreteFlag ? NULL : ObjectMoleculeGetCoordSet(obj, std::max(0, obj->getState()));
bool atom_in_state;
int gapMode = SettingGet_i(G, obj->Obj.Setting, nullptr, cSetting_seq_view_gap_mode);
int min_pad = -1;
CSeqCol *r1 = NULL, *l1 = NULL; /* *col */
if(nRow >= max_row)
break;
codes = SettingGet_i(G, obj->Obj.Setting, NULL, cSetting_seq_view_format);
if(obj->DiscreteFlag && SettingGet_b(G,
obj->Obj.Setting,
NULL, cSetting_seq_view_discrete_by_state))
codes = 4;
default_color = SettingGet_i(G, obj->Obj.Setting, NULL, cSetting_seq_view_color);
/* allocate a row for labels, if present
the text for the labels and the residues will line up exactly
*/
VLACheck(row_vla, CSeqRow, nRow);
if((label_mode == 2) || ((label_mode == 1) && (!nRow))) {
lab = row_vla + nRow++;
lab->txt = VLAlloc(char, est_char);
lab->col = VLACalloc(CSeqCol, est_col);
lab->label_flag = true;
} else {
lab = NULL;
}
VLACheck(row_vla, CSeqRow, nRow);
row = row_vla + nRow;
if(lab)
lab = row - 1; /* critical! */
row->txt = VLAlloc(char, est_char);
row->col = VLACalloc(CSeqCol, est_col);
row->fill = VLACalloc(CSeqCol, est_col / 8);
row->atom_lists = VLACalloc(int, obj->NAtom + est_col + 1);
row->atom_lists[0] = -1; /* terminate the blank listQ (IMPORTANT!) */
row->char2col = VLACalloc(int, est_char);
row->obj = obj;
strcpy(row->name, obj->Obj.Name);
row->color = obj->Obj.Color;
ai = obj->AtomInfo;
/* copy object name onto label row */
if(lab) {
int st_len;
/* copy label text */
VLACheck(lab->col, CSeqCol, nCol);
l1 = lab->col + nCol;
l1->start = lab->len;
UtilConcatVLA(&lab->txt, &lab->len, "/");
UtilConcatVLA(&lab->txt, &lab->len, obj->Obj.Name);
l1->stop = lab->len;
st_len = l1->stop - l1->start;
if(label_mode == 2) {
/* blank equivalent text for sequence row below the fixed label */
VLACheck(row->col, CSeqCol, nCol);
r1 = row->col + nCol;
r1->start = row->len;
UtilFillVLA(&row->txt, &row->len, ' ', st_len);
r1->stop = row->len;
r1->spacer = true;
nCol++;
}
}
if(label_mode < 2) { /* no label rows, so put object name into left-hand column */
/* copy label text */
VLACheck(row->col, CSeqCol, nCol);
r1 = row->col + nCol;
r1->start = row->len;
UtilConcatVLA(&row->txt, &row->len, "/");
UtilConcatVLA(&row->txt, &row->len, obj->Obj.Name);
r1->stop = row->len;
r1->spacer = true;
row->column_label_flag = true;
row->title_width = row->len;
nCol++;
} else if(label_mode == 3) { /* otherwise just insert a blank zero-length column */
VLACheck(row->col, CSeqCol, nCol);
r1 = row->col + nCol;
r1->start = row->len;
UtilConcatVLA(&row->txt, &row->len, "");
r1->stop = row->len;
r1->spacer = true;
nCol++;
}
if(lab) {
int st_len;
/* copy label text */
VLACheck(lab->col, CSeqCol, nCol);
l1 = lab->col + nCol;
l1->start = lab->len;
if(obj->NAtom) {
UtilConcatVLA(&lab->txt, &lab->len, "/");
UtilConcatVLA(&lab->txt, &lab->len, LexStr(G, ai->segi));
UtilConcatVLA(&lab->txt, &lab->len, "/");
UtilConcatVLA(&lab->txt, &lab->len, LexStr(G, ai->chain));
UtilConcatVLA(&lab->txt, &lab->len, "/");
} else {
UtilConcatVLA(&lab->txt, &lab->len, "///");
}
l1->stop = lab->len;
st_len = l1->stop - l1->start;
last_segi = ai;
last_chain = ai;
/* blank equivalent text for sequence row below the fixed label */
VLACheck(row->col, CSeqCol, nCol);
r1 = row->col + nCol;
r1->start = row->len;
UtilFillVLA(&row->txt, &row->len, ' ', st_len);
r1->stop = row->len;
r1->spacer = true;
nCol++;
} else { /* if no labels, just insert a space in row below */
VLACheck(row->col, CSeqCol, nCol);
r1 = row->col + nCol;
r1->start = row->len;
UtilConcatVLA(&row->txt, &row->len, " ");
r1->stop = row->len;
r1->spacer = true;
nCol++;
}
last_state = -1;
for(a = 0; a < obj->NAtom; a++) {
first_atom_in_label = false;
if(lab && !AtomInfoSameSegmentP(G, last_segi, ai)) {
int st_len;
if(row->len < min_pad) {
row->len = min_pad;
}
min_pad = -1;
/* copy label text */
VLACheck(lab->col, CSeqCol, nCol);
l1 = lab->col + nCol;
l1->start = lab->len;
UtilConcatVLA(&lab->txt, &lab->len, "/");
UtilConcatVLA(&lab->txt, &lab->len, LexStr(G, ai->segi));
UtilConcatVLA(&lab->txt, &lab->len, "/");
UtilConcatVLA(&lab->txt, &lab->len, LexStr(G, ai->chain));
UtilConcatVLA(&lab->txt, &lab->len, "/");
l1->stop = lab->len;
st_len = l1->stop - l1->start;
/* blank equivalent text for sequence row */
VLACheck(row->col, CSeqCol, nCol);
r1 = row->col + nCol;
r1->start = row->len;
UtilFillVLA(&row->txt, &row->len, ' ', st_len);
r1->stop = row->len;
r1->spacer = true;
nCol++;
last_abbr = false;
last_spacer = true;
last_segi = ai;
last_chain = ai;
} else if(lab && !AtomInfoSameChainP(G, last_chain, ai)) {
int st_len;
if(row->len < min_pad) {
row->len = min_pad;
}
min_pad = -1;
/* copy label text */
VLACheck(lab->col, CSeqCol, nCol);
l1 = lab->col + nCol;
l1->start = lab->len;
UtilConcatVLA(&lab->txt, &lab->len, "/");
UtilConcatVLA(&lab->txt, &lab->len, LexStr(G, ai->chain));
UtilConcatVLA(&lab->txt, &lab->len, "/");
l1->stop = lab->len;
st_len = l1->stop - l1->start;
/* blank equivalent text for sequence row */
VLACheck(row->col, CSeqCol, nCol);
r1 = row->col + nCol;
r1->start = row->len;
UtilFillVLA(&row->txt, &row->len, ' ', st_len);
r1->stop = row->len;
r1->spacer = true;
nCol++;
last_abbr = false;
last_spacer = true;
last_chain = ai;
}
if(min_pad < 0)
{
min_pad = row->len + 1; // + strlen(resi)
for (int v = ai->resv; v; v /= 10) {
min_pad++;
}
if (ai->inscode) {
min_pad++;
}
}
atom_in_state = (cs && a < cs->NAtIndex && cs->AtmToIdx[a] >= 0);
int gapsNeeded{0};
if(gapMode != GapMode::NONE
&& AtomInfoSameChainP(G, ai, last)
&& (ai->flags & last->flags & cAtomFlag_polymer)
&& align_sele < 0){
gapsNeeded = ai->resv - last->resv - 1;
if(gapsNeeded > 1 && gapMode == GapMode::SINGLE){
gapsNeeded = 1;
}
}
auto push_gap = [&](const std::string& str)
{
UtilConcatVLA(&row->txt, &row->len, str.c_str());
VLACheck(row->col, CSeqCol, nCol + str.size());
r1 = row->col + nCol;
for(int i = 0; i < str.size(); i++){
r1->color = missing_color;
r1->spacer = true;
r1->stop = r1->start + 1;
auto lastStop = r1->stop;
nCol++;
r1 = row->col + nCol;
r1->start = lastStop;
}
};
switch (codes) {
case 0: /* one letter residue codes */
if(!AtomInfoSameResidueP(G, last, ai)) {
char abbr[2] = "1";
last = ai;
VLACheck(row->col, CSeqCol, nCol);
r1 = row->col + nCol;
r1->start = row->len;
//Only include non-consecutive gaps when not doing alignment
if(gapsNeeded > 0 && gapsNeeded <= MAXCONSECUTIVEGAPS){
for(int g = 0; g < gapsNeeded; ++g){
push_gap("-");
}
}
else if(gapsNeeded > MAXCONSECUTIVEGAPS){
push_gap("---...---");
}
if(obj->DiscreteFlag)
r1->state = ai->discrete_state;
first_atom_in_label = true;
// single letter codes for polymer/solvent
if (!(ai->flags & (cAtomFlag_organic | cAtomFlag_inorganic))) {
abbr[0] = SeekerGetAbbr(G, LexStr(G, ai->resn), 'O', 0);
} else {
abbr[0] = 0;
}
r1->hint_no_space = last_abbr || last_spacer;
if(!abbr[0]) {
if(last_abbr) {
UtilConcatVLA(&row->txt, &row->len, " ");
r1->start = row->len;
}
if(ai->resn)
UtilConcatVLA(&row->txt, &row->len, LexStr(G, ai->resn));
else
UtilConcatVLA(&row->txt, &row->len, "''");
r1->stop = row->len;
UtilConcatVLA(&row->txt, &row->len, " ");
} else {
UtilConcatVLA(&row->txt, &row->len, abbr);
r1->is_abbr = true;
r1->stop = row->len;
}
if(!atom_in_state)
r1->color = missing_color;
else if(default_color < 0)
r1->color = SeekerFindColor(G, ai, obj->NAtom - a);
else
r1->color = default_color;
if(align_sele >= 0) {
r1->tag = SeekerFindTag(G, ai, align_sele, codes, obj->NAtom - a);
} else {
r1->tag = 0;
}
nCol++;
last_abbr = abbr[0];
}
break;
case 1: /* explicit residue codes */
if(!AtomInfoSameResidueP(G, last, ai)) {
last = ai;
VLACheck(row->col, CSeqCol, nCol);
r1 = row->col + nCol;
r1->start = row->len;
if(obj->DiscreteFlag)
r1->state = ai->discrete_state;
first_atom_in_label = true;
//Only include non-consecutive gaps when not doing alignment
if(gapsNeeded > 0 && gapsNeeded <= MAXCONSECUTIVEGAPS){
for(int g = 0; g < gapsNeeded; ++g){
push_gap("--- ");
}
}
else if(gapsNeeded > MAXCONSECUTIVEGAPS){
push_gap("---...--- ");
}
if(ai->resn)
UtilConcatVLA(&row->txt, &row->len, LexStr(G, ai->resn));
else
UtilConcatVLA(&row->txt, &row->len, "''");
r1->stop = row->len;
if(!atom_in_state)
r1->color = missing_color;
else if(default_color < 0)
r1->color = SeekerFindColor(G, ai, obj->NAtom - a);
else
r1->color = default_color;
if(align_sele >= 0) {
r1->tag = SeekerFindTag(G, ai, align_sele, codes, obj->NAtom - a);
} else {
r1->tag = 0;
}
UtilConcatVLA(&row->txt, &row->len, " ");
nCol++;
}
break;
case 2: /* atom names */
VLACheck(row->col, CSeqCol, nCol);
r1 = row->col + nCol;
r1->start = row->len;
first_atom_in_label = true;
if(ai->name)
UtilConcatVLA(&row->txt, &row->len, LexStr(G, ai->name));
else
UtilConcatVLA(&row->txt, &row->len, "''");
r1->stop = row->len;
if(!atom_in_state)
r1->color = missing_color;
else if(default_color < 0)
r1->color = ai->color;
else
r1->color = default_color;
if(align_sele >= 0) {
r1->tag = SeekerFindTag(G, ai, align_sele, codes, obj->NAtom - a);
} else {
r1->tag = 0;
}
UtilConcatVLA(&row->txt, &row->len, " ");
nCol++;
break;
case 3: /* chains */
if(!AtomInfoSameChainP(G, last, ai)) {
last = ai;
VLACheck(row->col, CSeqCol, nCol);
r1 = row->col + nCol;
r1->start = row->len;
first_atom_in_label = true;
if(ai->chain)
UtilConcatVLA(&row->txt, &row->len, LexStr(G, ai->chain));
else
UtilConcatVLA(&row->txt, &row->len, "''");
r1->stop = row->len;
if(default_color < 0)
r1->color = SeekerFindColor(G, ai, obj->NAtom - a);
else
r1->color = default_color;
if(align_sele >= 0) {
r1->tag = SeekerFindTag(G, ai, align_sele, codes, obj->NAtom - a);
} else {
r1->tag = 0;
}
UtilConcatVLA(&row->txt, &row->len, " ");
nCol++;
}
break;
case 4: /* state names */
if(obj->DiscreteFlag) {
CoordSet *cs;
WordType buf1;
if((cs = obj->DiscreteCSet[a]) != last_disc) {
last_disc = cs;
if(cs) {
default_color = SettingGet_i(G, cs->Setting, obj->Obj.Setting,
cSetting_seq_view_color);
VLACheck(row->col, CSeqCol, nCol);
r1 = row->col + nCol;
r1->start = row->len;
r1->color = default_color;
first_atom_in_label = true;
if(cs->Name[0])
UtilConcatVLA(&row->txt, &row->len, cs->Name);
else {
sprintf(buf1, "%d", ai->discrete_state);
UtilConcatVLA(&row->txt, &row->len, buf1);
}
r1->stop = row->len;
r1->state = ai->discrete_state;
UtilConcatVLA(&row->txt, &row->len, " ");
nCol++;
}
}
} else {
/* non-discrete objects simply get their states enumerated
without selections */
if(last_state < 0) {
int b;
CoordSet *cs;
WordType buf1;
last_state = 1;
first_atom_in_label = true;
for(b = 0; b < obj->NCSet; b++) {
cs = obj->CSet[b];
if(cs) {
default_color = SettingGet_i(G, cs->Setting, obj->Obj.Setting,
cSetting_seq_view_color);
VLACheck(row->col, CSeqCol, nCol);
r1 = row->col + nCol;
r1->state = b + 1;
r1->start = row->len;
r1->atom_at = nListEntries + 1; /* tricky & dangerous */
r1->color = default_color;
if(cs->Name[0])
UtilConcatVLA(&row->txt, &row->len, cs->Name);
else {
sprintf(buf1, "%d", b + 1);
UtilConcatVLA(&row->txt, &row->len, buf1);
}
r1->stop = row->len;
UtilConcatVLA(&row->txt, &row->len, " ");
nCol++;
}
}
}
}
break;
case 5: /* movie frames */
break;
}
if(first_atom_in_label) {
if(nCol > 1) { /* terminate current list, if any */
VLACheck(row->atom_lists, int, nListEntries);
row->atom_lists[nListEntries] = -1;
nListEntries++;
}
if(r1) {
r1->atom_at = nListEntries;
}
}
VLACheck(row->atom_lists, int, nListEntries);
row->atom_lists[nListEntries] = a;
nListEntries++;
ai++;
}
if(lab) {
/* if(lab->len<row->len) {
lab->len = row->len;
} */
VLASize(lab->txt, char, lab->len + 1);
lab->txt[lab->len] = 0;
VLACheck(lab->col, CSeqCol, nCol); /* make sure we've got column records for labels too */
lab->nCol = nCol;
/*if(row->len<lab->len) {
row->len = lab->len;
} */
}
VLASize(row->txt, char, row->len + 1);
row->txt[row->len] = 0;
row->nCol = nCol;
/* terminate last atom list */
VLACheck(row->atom_lists, int, nListEntries);
row->atom_lists[nListEntries] = -1;
nListEntries++;
nRow++;
}
}
/* SECOND PASS: align columns to reflect current alignment and fixed labels */
if(nRow) {
int a, b;
int nCol;
int maxCol = 0;
int done_flag = false;
/* find out the maximum number of columns */
for(a = 0; a < nRow; a++) {
row = row_vla + a;
nCol = row->nCol;
row->accum = 0; /* initialize the accumulators */
row->current = 0;
if(maxCol < nCol)
maxCol = nCol;
}
if(align_sele < 0) {
/* in the simplest mode, just start each sequence in the same column */
b = 0;
while(!done_flag) {
int max_offset = 0;
done_flag = true;
for(a = 0; a < nRow; a++) {
row = row_vla + a;
if(!row->label_flag) {
if(b < row->nCol) {
CSeqCol *r1 = row->col + b;
done_flag = false;
r1->offset = r1->start + row->accum;
if(max_offset < r1->offset)
max_offset = r1->offset;
}
}
}
for(a = 0; a < nRow; a++) {
row = row_vla + a;
if(!row->label_flag) {
if(b < row->nCol) {
CSeqCol *r1 = row->col + b;
if(b < 3) {
if(r1->offset < max_offset) {
row->accum += max_offset - r1->offset;
}
}
r1->offset = r1->start + row->accum;
}
}
}
b++;
}
} else {
/* in alignment mode, line up the tags */
int stagger = false;
/* intialize current columns and get the starting character */
int current = 0;
int first = true;
switch (SettingGetGlobal_i(G, cSetting_seq_view_unaligned_mode)) {
case 0:
case 1:
case 2:
stagger = false;
break;
default:
stagger = true;
break;
}
for(a = 0; a < nRow; a++) {
row = row_vla + a;
row->cCol = 0;
if((!row->label_flag) && ((row->cCol < row->nCol))) {
if(current < row->accum)
current = row->accum;
}
}
done_flag = false;
while(!done_flag) {
int hint_tagged_no_space = true;
done_flag = true;
{
{
/* insert untagged entries into their own columns */
int untagged_flag = true;
int saw_untagged_no_abbr = false;
int hint_untagged_space = false;
while(untagged_flag) {
int space_added = false;
int max_width = 0;
untagged_flag = false;
/* first get the spaces in... */
for(a = 0; a < nRow; a++) {
row = row_vla + a;
if((!row->label_flag) && (row->cCol < row->nCol)) {
CSeqCol *r1 = row->col + row->cCol;
if(!r1->tag) { /* not aligned */
int text_len = (r1->stop - r1->start);
if((!first) && (!space_added) && (row->cCol > 2) &&
(codes || (((!r1->is_abbr) && (!r1->spacer))) ||
hint_untagged_space || (r1->is_abbr && (!r1->hint_no_space)))) {
/* insert space */
current++;
space_added = true;
}
if(max_width < text_len)
max_width = text_len;
}
}
}
/* then do the rest */
for(a = 0; a < nRow; a++) {
row = row_vla + a;
if((!row->label_flag) && (row->cCol < row->nCol)) {
CSeqCol *r1 = row->col + row->cCol;
if(!r1->tag) { /* not aligned */
int text_len = (r1->stop - r1->start);
untagged_flag = true;
done_flag = false;
saw_untagged_no_abbr |= (!r1->is_abbr) && (!r1->spacer);
first = false;
r1->offset = current;
r1->unaligned = true;
if(!r1->spacer) {
int aa;
for(aa = 0; aa < nRow; aa++) { /* infill populate other rows with dashes */
if(aa != a) {
CSeqRow *row2 = row_vla + aa;
if(!row2->label_flag) {
if(row2->cCol < row2->nCol) {
CSeqCol *r2 = row2->col + row2->cCol;
if(stagger || r2->tag || r2->spacer) {
VLACheck(row2->fill, CSeqCol, row2->nFill);
r2 = row2->fill + row2->nFill;
r2->stop = text_len;
r2->offset = current;
row2->nFill++;
}
} else {
CSeqCol *r2 = row2->col + row2->cCol;
VLACheck(row2->fill, CSeqCol, row2->nFill);
r2 = row2->fill + row2->nFill;
r2->stop = text_len;
r2->offset = current;
row2->nFill++;
}
}
}
}
}
if(stagger)
current += text_len;
else if(max_width < text_len)
max_width = text_len;
}
}
}
if(!stagger)
current += max_width;
if(saw_untagged_no_abbr) {
hint_untagged_space = true;
hint_tagged_no_space = false;
} else {
hint_untagged_space = false;
hint_tagged_no_space = true;
}
saw_untagged_no_abbr = false;
for(a = 0; a < nRow; a++) {
row = row_vla + a;
if((!row->label_flag) && (row->cCol < row->nCol)) {
CSeqCol *r1 = row->col + row->cCol;
if(!r1->tag) {
row->cCol++;
}
}
}
}
}
}
{
/* next insert match-tagged entries into the same column */
int min_tag = 0;
for(a = 0; a < nRow; a++) {
row = row_vla + a;
if((!row->label_flag) && (row->cCol < row->nCol)) {
CSeqCol *r1 = row->col + row->cCol;
if(r1->tag && ((min_tag > r1->tag) || (!min_tag))) {
min_tag = r1->tag;
}
}
}
if(min_tag) {
int width, max_width = 0;
int space_added = false;
int rep;
for(rep = 0; rep < 2; rep++)
for(a = 0; a < nRow; a++) {
row = row_vla + a;
if((!row->label_flag) && (row->cCol < row->nCol)) {
CSeqCol *r1 = row->col + row->cCol;
if(r1->tag == min_tag) {
if((!first) && (!space_added) &&
(codes || (((!r1->is_abbr) && (!r1->spacer))) ||
(r1->is_abbr
&& (!(r1->hint_no_space || hint_tagged_no_space))))) {
/* insert space */
current++;
space_added = true;
}
done_flag = false;
first = false;
r1->offset = current;
width = (r1->stop - r1->start);
if(max_width < width)
max_width = width;
/* row->cCol++; */
}
}
}
{
int aa;
for(aa = 0; aa < nRow; aa++) { /* infill populate other rows with dashes */
CSeqRow *row2 = row_vla + aa;
if(!row2->label_flag) {
if(row2->cCol < row2->nCol) {
CSeqCol *r1 = row2->col + row2->cCol;
if(r1->tag != min_tag) {
CSeqCol *r2;
VLACheck(row2->fill, CSeqCol, row2->nFill);
r2 = row2->fill + row2->nFill;
r2->stop = max_width;
r2->offset = current;
row2->nFill++;
}
} else {
CSeqCol *r2;
VLACheck(row2->fill, CSeqCol, row2->nFill);
r2 = row2->fill + row2->nFill;
r2->stop = max_width;
r2->offset = current;
row2->nFill++;
}
}
}
}
for(a = 0; a < nRow; a++) {
row = row_vla + a;
if((!row->label_flag) && (row->cCol < row->nCol)) {
CSeqCol *r1 = row->col + row->cCol;
if(r1->tag == min_tag) {
row->cCol++;
}
}
}
current += max_width;
}
}
}
}
for(a = 0; a < nRow; a++) {
row = row_vla + a;
nCol = row->nCol;
if(row->label_flag)
lab = row;
else {
for(b = 0; b < nCol; b++) {
CSeqCol *r1 = row->col + b, *l1 = NULL;
if(lab) {
l1 = lab->col + b; /* if a fixed label is present,
get the final offset from the residue line */
if(l1->stop)
l1->offset = r1->offset;
}
}
lab = NULL;
}
}
}
/* THIRD PASS: fill in labels, based on actual residue spacing */
if(nRow && (codes != 4)) {
int a, b, c;
int nCol;
for(a = 0; a < nRow; a++) {
lab = row_vla + a;
if(lab->label_flag) {
int next_open = 0;
int *atom_list;
int st_len;
int div, sub;
int draw_it;
int n_skipped = 0;
int last_resv = -1;
AtomInfoType *last_ai = NULL;
ObjectMolecule *obj;
AtomInfoType *ai;
row = lab + 1;
nCol = row->nCol;
obj = row->obj;
div = SettingGet_i(G, obj->Obj.Setting, NULL, cSetting_seq_view_label_spacing);
sub = SettingGet_i(G, obj->Obj.Setting, NULL, cSetting_seq_view_label_start);
for(b = 0; b < nCol; b++) {
CSeqCol *r1 = row->col + b;
CSeqCol *l1 = lab->col + b;
ai = NULL;
if(r1->atom_at) {
atom_list = row->atom_lists + r1->atom_at;
if(*atom_list >= 0)
ai = obj->AtomInfo + (*atom_list); /* get first atom in list */
}
if(l1->stop) { /* if label is already present, just line it up */
l1->offset = r1->offset;
} else if((r1->offset >= next_open) && ai) {
if((div > 1) && (codes != 2)) {
if(!((ai->resv - sub) % div))
draw_it = true;
else
draw_it = false;
} else {
draw_it = true;
}
if(ai->resv != (last_resv + 1)) /* gap in sequence? then draw label ASAP */
draw_it = true;
if(n_skipped >= (div + div)) /* don't skip too many without a label! */
draw_it = true;
if(AtomInfoSameResidueP(G, last_ai, ai)) /* don't ever draw a residue label twice */
draw_it = false;
if(draw_it) {
n_skipped = 0;
last_ai = ai;
l1->start = lab->len;
if(codes == 2) {
UtilConcatVLA(&lab->txt, &lab->len, LexStr(G, ai->resn));
UtilConcatVLA(&lab->txt, &lab->len, "`");
}
{
char resi[8];
AtomResiFromResv(resi, sizeof(resi), ai);
UtilConcatVLA(&lab->txt, &lab->len, resi);
}
l1->stop = lab->len;
st_len = l1->stop - l1->start + 1;
l1->offset = r1->offset;
next_open = r1->offset + st_len;
/* make sure this label doesn't conflict with a fixed label */
for(c = b + 1; c < nCol; c++) {
CSeqCol *l2 = lab->col + c;
if(l2->offset && (l2->offset < next_open)) {
l1->start = 0;
l1->stop = 0;
break;
}
if((c - b) > st_len) /* only search as many columns as characters */
break;
}
} else
n_skipped++;
}
if(ai)
last_resv = ai->resv;
}
}
}
}
/* FOURTH PASS: simply fill in character offsets */
if(nRow) {
int a, b;
int nCol;
int start, stop;
for(a = 0; a < nRow; a++) {
row = row_vla + a;
row->ext_len = 0;
if(!row->label_flag) {
nCol = row->nCol;
for(b = 0; b < nCol; b++) {
CSeqCol *r1 = row->col + b;
stop = r1->offset + (r1->stop - r1->start);
if(row->ext_len < stop)
row->ext_len = stop;
}
VLACheck(row->char2col, int, row->ext_len);
UtilZeroMem(row->char2col, row->ext_len);
for(b = 0; b < nCol; b++) {
CSeqCol *r1 = row->col + b;
int c;
start = r1->offset;
stop = r1->offset + (r1->stop - r1->start);
for(c = start; c < stop; c++)
row->char2col[c] = b + 1;
}
}
}
}
G->Seeker->handler.fClick = SeekerClick;
G->Seeker->handler.fRelease = SeekerRelease;
G->Seeker->handler.fDrag = SeekerDrag;
G->Seeker->handler.fRefresh = SeekerRefresh;
SeqSetRowVLA(G, row_vla, nRow);
SeqSetHandler(G, &G->Seeker->handler);
}