staden-lg/src/staden/tman_basesDisplay.c

374 lines
9.3 KiB
C

/*
Title: basesDisplay
File: basesDisplay.h
Purpose: Display the bases of a sequence on graphs
Last update: Monday 20 January 1992
*/
/*
`plotEdgeOffset' indicates the pixel position at which point 0
occurs. The characters for bases are printed with their centres
corresponding to their locations on the plot.
A caret is XOR drawn in the editable graph on top of (i.e. after)
all characters have been drawn.
Changes to this module by lfw:
module displayEdBases and displayBases
added int baseNum as a parameter so that
the user could specify a baseNum via the
command line baseNum parameter or via
specifying a string to search for ( if
you specify a string to search for
) and have that be where the caret
is originally positioned. Before this
modification, the caret was always
initially positioned at base 0.
*/
/* ---- Includes ---- */
#include "tman_basesDisplay.h"
#include "tman_display.h"
#include "tman_context.h"
#include "Graph.h"
#include "seq.h" /* IMPORT: Seq, NULLSeq, getNPoints */
#include <ctype.h> /* IMPORT: toupper */
#include <X11/Intrinsic.h>
#include <X11/keysym.h>
#include <X11/StringDefs.h>
#include <X11/Xaw/Command.h>
#include <X11/Xaw/Form.h>
#include <X11/Xaw/Label.h>
#include <X11/Xaw/Viewport.h>
/* ---- Constants ---- */
/* ---- Statics ---- */
/* Current sequence information */
/* Font information */
static Dimension charWidth;
static Dimension halfCharWidth;
static Dimension charVOffset; /* Of char baseline from top of graph=ascent+1 */
static GC Agc, Cgc, Ggc, Tgc;
/* ---- Position translation ---- */
/*
Convert a value from the `point-in-the-sequence' to the
`x-pixel-on-the-graph' scale, and vice-versa, given that
`plotWidth' holds the current pixel width of the graph which
starts `plotEdgeOffset' from either edge of the graph and
`NPoints' gives the current point width.
Fractional results are truncated - for pixelToPoint this may
mean a point one too low is indicated, but a point too high is
never indicated.
*/
static int pointToPixel(DisplayContext *dc, int point)
{ return(((point * dc->plotWidth) / (dc->NPoints-1)) + dc->plotEdgeOffset);
}
int pixelToPoint(DisplayContext *dc, int pixel)
{ return(((pixel-dc->plotEdgeOffset) * (dc->NPoints-1)) / dc->plotWidth);
}
static int leftCutoffPoint(DisplayContext *dc, int baseNum)
/*
Return the point corresponding to a left cutoff at `baseNum'.
*/
{ int pL, pR;
pL = (baseNum == 0) ? 0 : baseNumToPoint(dc->seq, OrigBases, baseNum-1);
pR = (baseNum == 0) ? 0 : baseNumToPoint(dc->seq, OrigBases, baseNum);
return((pR==NULLPoint)?pL:(pL+pR)/2);
}
static int rightCutoffPoint(DisplayContext *dc, int baseNum)
/*
Return the point corresponding to a right cutoff at `baseNum'.
*/
{ int NorigBases = getNBases(dc->seq, OrigBases);
int pL, pR;
pL = (baseNum == 0)
? dc->NPoints-1
: baseNumToPoint(dc->seq, OrigBases, NorigBases-baseNum);
pR = (baseNum == 0)
? dc->NPoints-1
: baseNumToPoint(dc->seq, OrigBases, NorigBases-baseNum-1);
return((pL+pR)/2);
}
/* ---- Internal routines ---- */
static void writeBase(DisplayContext *dc, Widget wid, int baseNum)
{
char base = getBase(dc->seq, OrigBases, baseNum);
int point = baseNumToPoint(dc->seq, OrigBases, baseNum);
GC gc;
/* Get the correct GC */
switch (base)
{ case 'A': gc=Agc; break;
case 'C': gc=Cgc; break;
case 'G': gc=Ggc; break;
case 'T': gc=Tgc; break;
default: gc=Ggc; break;
}
XDrawImageString(XtDisplay(wid),
XtWindow(wid),
gc,
pointToPixel(dc,point)-halfCharWidth, charVOffset,
&base, 1);
}
/* ---- Callbacks ---- */
static void exposeCallback(Widget wid,
XtPointer client_data, XtPointer call_data)
{ Region region = (Region) call_data;
XRectangle rect;
int x0, xN; /* Affected region: pixels */
int p0, pN; /* Affected region: points */
int b, b0, bN; /* Affected region: bases */
int leftCutoffP, rightCutoffP;
int NBases;
int whichBases;
DisplayContext *dc = widgetToDisplayContext(XtParent(XtParent(XtParent(wid))));
if (dc->seq == NULLSeq) return;
leftCutoffP = leftCutoffPoint(dc,dc->leftCutoff);
rightCutoffP = rightCutoffPoint(dc,dc->rightCutoff);
NBases = dc->seq->NorigBases;
whichBases = OrigBases;
/*
`region' gives us the exposed graph region.
XClipBox will return a bounding rectangle, in pixels.
*/
XClipBox(region, &rect);
x0 = rect.x;
xN = rect.x+rect.width;
/* Convert to affected points after trimming to the plot proper */
p0=pixelToPoint(dc,(x0<dc->plotEdgeOffset) ?dc->plotEdgeOffset :x0);
pN=pixelToPoint(dc,(xN>dc->plotWidth+dc->plotEdgeOffset)?dc->plotWidth+dc->plotEdgeOffset:xN);
if (pN<dc->NPoints-1) pN++;
/*
Now draw the affected bases.
*/
/* The first base is to the left of the exposed region */
b0 = pointToBaseNum(dc->seq, whichBases, p0);
b0 = (b0 == NULLBaseNum) ? NBases-1
: (b0>0) ? b0-1
: 0;
/* The last base is to the right of the exposed region */
bN = pointToBaseNum(dc->seq, whichBases, pN);
bN = (bN == NULLBaseNum) ? NBases-1 : bN;
if (b0<dc->leftCutoff)
/*
Some of the bases are in the left cutoff area.
Draw them, the edited ones with the dim background.
*/
{
for (b=b0; b<=dc->leftCutoff-1; b++) writeBase(dc,wid, b);
}
if (bN>=dc->leftCutoff && b0-dc->seq->NorigBases-1<dc->rightCutoff)
/*
Some of the exposed region is in the middle area.
Draw the bases.
*/
{ int firstBase = (b0<dc->leftCutoff) ? dc->leftCutoff : b0;
int lastBase = (bN>dc->seq->NorigBases-1-dc->rightCutoff)
? dc->seq->NorigBases-1-dc->rightCutoff
: bN;
for (b=firstBase; b<=lastBase; b++) writeBase(dc, wid, b);
}
if (bN>dc->seq->NorigBases-1-dc->rightCutoff)
/*
Some of the exposed region is in the right cutoff area.
Repaint it with dimmed background.
*/
{
/* Plot the affected bases */
for (b=dc->seq->NorigBases-dc->rightCutoff; b<=bN; b++) writeBase(dc, wid, b);
}
}
/* ---- Exports ---- */
Widget createBasesDisplay(DisplayContext *dc, Widget parentWid, Widget fromVertWid,
Dimension width)
/*
Create the bases display within the Form widget `parent',
with the XtNfromVert constraint `fromVertWid'. The initial
width is `width'. Return the (lower) widget constructed.
No bases are initially displayed.
*/
{ Arg args[10];
int nargs;
dc->seq = NULLSeq;
dc->graphWidth = width;
nargs = 0;
XtSetArg(args[nargs], XtNfromVert, fromVertWid); nargs++;
XtSetArg(args[nargs], XtNwidth, dc->graphWidth); nargs++;
dc->origSeqWid = XtCreateManagedWidget("origSeq", graphWidgetClass,
parentWid, args, nargs);
XtAddCallback(dc->origSeqWid, XtNexposeCallback, exposeCallback, NULL);
/*
Get font information.
The text graphs are set to be two pixels higher than
(ascent+descent). Characters are then plotted with
a vertical offset one more than the ascent.
*/
{ XFontStruct *fontStruct;
nargs = 0;
XtSetArg(args[nargs], XtNfont, &fontStruct); nargs++;
XtGetValues(dc->origSeqWid, args, nargs);
charWidth = fontStruct->max_bounds.width;
halfCharWidth = fontStruct->max_bounds.width/2;
charVOffset = fontStruct->ascent+1;
dc->plotEdgeOffset = halfCharWidth+2;
dc->plotWidth = dc->graphWidth-(2*dc->plotEdgeOffset);
dc->graphHeight = fontStruct->ascent + fontStruct->descent + 2;
/* Make this graph tall enough to hold it */
nargs = 0;
XtSetArg(args[nargs], XtNheight, dc->graphHeight); nargs++;
XtSetValues(dc->origSeqWid, args, nargs);
}
/*
Get the GCs
*/
Agc = GraphGC1(dc->origSeqWid);
Cgc = GraphGC2(dc->origSeqWid);
Ggc = GraphGC3(dc->origSeqWid);
Tgc = GraphGC4(dc->origSeqWid);
return dc->origSeqWid;
}
void getBasesFontInfo(DisplayContext *dc,Dimension *offset, Dimension *chWidth)
/*
In `offset' return the offset which the bases are drawn
from the left and right hand edges. The width of the characters
used is returned in `chWidth'.
*/
{ *offset = dc->plotEdgeOffset;
*chWidth = charWidth;
}
void initBaseDisplay(Seq seq, int baseNum)
/*
Initialise the base display of sequence `seq'.
*/
{
DisplayContext *dc = seqToDisplayContext(seq);
if (seq == NULLSeq) return;
dc->seq = seq;
/*
Get static information about the current sequence.
*/
dc->NPoints = getNPoints(dc->seq);
getCutoffs(dc->seq, &dc->leftCutoff, &dc->rightCutoff);
}
void setBasesWidth(DisplayContext *dc, Dimension width)
/*
Set the width of the current sequence bases display.
*/
{ Arg args[10];
int nargs;
nargs = 0;
XtSetArg(args[nargs], XtNwidth, width); nargs++;
XtSetValues(dc->origSeqWid, args, nargs);
dc->graphWidth = width;
dc->plotWidth = dc->graphWidth-(2*dc->plotEdgeOffset);
/*
Clear the graphs.
*/
if (XtIsRealized(dc->origSeqWid))
XClearWindow(XtDisplay(dc->origSeqWid), XtWindow(dc->origSeqWid));
}