diff --git a/bigpicture.c b/bigpicture.c index cda0fad0dff7ae2794d6b5e1b608337e796be023..6437a72c93b354709a769790fd789240f69d5092 100644 --- a/bigpicture.c +++ b/bigpicture.c @@ -90,27 +90,41 @@ gdouble pixelsPerBase(const gint displayWidth, const IntRange const *displayRang } +/* Invert the given coord's position within the given range. Only invert if the bool is true; otherwise + * returns the original coord */ +static int invertCoord(const int coord, const IntRange const *range, const gboolean invert) +{ + int result = invert ? range->max - coord + range->min : coord; + return result; +} + + /* Convert a base index to an x coord within the given rectangle. Returns the number of pixels * from the left edge (including the start of the rectangle) to where the base lies. displayRev * should be passed as true if the display is toggled (i.e. low values on the right and high - * values on the left). */ -gint convertBaseIdxToGridPos(const gint baseIdx, + * values on the left). Clips the result to the rectangle if clip is true */ +gint convertBaseIdxToGridPos(const gint dnaIdx, const GdkRectangle const *rect, - const IntRange const *displayRange) + const IntRange const *dnaDispRange, + const gboolean displayRev, + const gboolean clip) { gint result = UNSET_INT; - gdouble numBasesFromEdge = (gdouble)(baseIdx - displayRange->min); /* 0-based index from edge */ - if (numBasesFromEdge < 0) + int baseIdx = invertCoord(dnaIdx, dnaDispRange, displayRev); + + gdouble numBasesFromEdge = (gdouble)(baseIdx - dnaDispRange->min); /* 0-based index from edge */ + + if (clip && numBasesFromEdge < 0) { numBasesFromEdge = 0; } - gint pixelsFromEdge = (int)(numBasesFromEdge * pixelsPerBase(rect->width, displayRange)); + gint pixelsFromEdge = (int)(numBasesFromEdge * pixelsPerBase(rect->width, dnaDispRange)); result = rect->x + pixelsFromEdge; - if (result > rect->x + rect->width) + if (clip && result > rect->x + rect->width) { result = rect->x + rect->width; } @@ -188,13 +202,16 @@ static void drawVerticalGridLineHeaders(GtkWidget *header, BlxViewContext *bc = bigPictureGetContext(bigPicture); GridHeaderProperties *headerProperties = gridHeaderGetProperties(header); BigPictureProperties *bpProperties = bigPictureGetProperties(bigPicture); + + /* Get the display range in dna coords */ + IntRange dnaDispRange; + convertDisplayRangeToDnaRange(&bpProperties->displayRange, bc->seqType, bc->numFrames, bc->displayRev, &bc->refSeqRange, &dnaDispRange); const int direction = bc->displayRev ? -1 : 1; /* to subtract instead of add when display reversed */ - /* Get the first base index (in terms of the nucleotide coords) and round it to a nice round - * number. We'll offset all of the gridlines by the distance between this and the real start coord. */ - const int realFirstBaseIdx = convertDisplayIdxToDnaIdx(bpProperties->displayRange.min, bc->seqType, 1, 1, bc->numFrames, bc->displayRev, &bc->refSeqRange); - const int firstBaseIdx = roundToValue(realFirstBaseIdx, bpProperties->roundTo); + /* Get the first base index and round it to a nice round number. We'll offset all of the gridlines + * by the distance between this and the real start coord. */ + const int firstBaseIdx = roundToValue(dnaDispRange.min, bpProperties->roundTo); /* Calculate the top and bottom heights for the lines. */ const gint bottomBorder = headerProperties->headerRect.y + headerProperties->headerRect.height; @@ -211,8 +228,7 @@ static void drawVerticalGridLineHeaders(GtkWidget *header, int numBasesFromLeft = bpProperties->basesPerCell * hCell; int baseIdx = firstBaseIdx + (numBasesFromLeft * direction); - const int displayIdx = convertDnaIdxToDisplayIdx(baseIdx, bc->seqType, 1, bc->numFrames, bc->displayRev, &bc->refSeqRange, NULL); - const int x = convertBaseIdxToGridPos(displayIdx, &headerProperties->headerRect, &bpProperties->displayRange); + const int x = convertBaseIdxToGridPos(baseIdx, &headerProperties->headerRect, &dnaDispRange, bc->displayRev, TRUE); if (x > minX && x < maxX) { @@ -667,16 +683,25 @@ static gboolean onExposeGridHeader(GtkWidget *header, GdkEventExpose *event, gpo } -/* Convert an x coord on the given widget to a base index */ -gint convertWidgetPosToBaseIdx(const gint widgetPos, - const GdkRectangle const *displayRect, - const IntRange const *displayRange) +/* Convert an x coord on the given widget to a base index (in nucleotide coords) */ +static gint convertWidgetPosToBaseIdx(const gint widgetPos, + const GdkRectangle const *displayRect, + const IntRange const *dnaDispRange, + const gboolean displayRev) { gint result = UNSET_INT; int distFromEdge = (int)((gdouble)widgetPos - (gdouble)displayRect->x); - int basesFromEdge = distFromEdge / pixelsPerBase(displayRect->width, displayRange); - result = displayRange->min + basesFromEdge; + int basesFromEdge = distFromEdge / pixelsPerBase(displayRect->width, dnaDispRange); + + if (displayRev) + { + result = dnaDispRange->max - basesFromEdge; + } + else + { + result = dnaDispRange->min + basesFromEdge; + } return result; } @@ -687,15 +712,19 @@ gint convertWidgetPosToBaseIdx(const gint widgetPos, * Only does anything if the preview box centre is set. */ void drawPreviewBox(GtkWidget *bigPicture, GdkDrawable *drawable, GdkGC *gc, GdkRectangle *displayRect, GdkRectangle *highlightRect) { - BigPictureProperties *bigPictureProperties = bigPictureGetProperties(bigPicture); + BigPictureProperties *bpProperties = bigPictureGetProperties(bigPicture); + BlxViewContext *bc = bigPictureGetContext(bigPicture); - if (bigPictureProperties->previewBoxCentre == UNSET_INT) + if (bpProperties->previewBoxCentre == UNSET_INT) { return; } - int previewBoxCentre = bigPictureProperties->previewBoxCentre; - const IntRange const *displayRange = &bigPictureProperties->displayRange; + int previewBoxCentre = bpProperties->previewBoxCentre; + + /* Get the display range in dna coords */ + IntRange dnaDispRange; + convertDisplayRangeToDnaRange(&bpProperties->displayRange, bc->seqType, bc->numFrames, bc->displayRev, &bc->refSeqRange, &dnaDispRange); /* Find the x coord for the left edge of the preview box (or the right edge, if * the display is right-to-left). */ @@ -703,15 +732,14 @@ void drawPreviewBox(GtkWidget *bigPicture, GdkDrawable *drawable, GdkGC *gc, Gdk /* Convert it to the base index and back again so that we get it rounded to the position of * the nearest base. */ - int baseIdx = convertWidgetPosToBaseIdx(x, displayRect, displayRange); - int xRounded = convertBaseIdxToGridPos(baseIdx, displayRect, displayRange); + int baseIdx = convertWidgetPosToBaseIdx(x, displayRect, &dnaDispRange, bc->displayRev); + int xRounded = convertBaseIdxToGridPos(baseIdx, displayRect, &dnaDispRange, bc->displayRev, TRUE); /* The other dimensions of the preview box are the same as the current highlight box. */ GdkRectangle previewRect = {xRounded, highlightRect->y, highlightRect->width, highlightRect->height}; - BlxViewContext *bc = bigPictureGetContext(bigPicture); GdkColor *previewBoxColor = getGdkColor(BLXCOLOR_PREVIEW_BOX, bc->defaultColors, FALSE, bc->usePrintColors); - drawHighlightBox(drawable, &previewRect, bigPictureProperties->previewBoxLineWidth, previewBoxColor); + drawHighlightBox(drawable, &previewRect, bpProperties->previewBoxLineWidth, previewBoxColor); } @@ -732,22 +760,28 @@ void showPreviewBox(GtkWidget *bigPicture, const int x) * the preview box. */ void acceptAndClearPreviewBox(GtkWidget *bigPicture, const int xCentre, GdkRectangle *displayRect, GdkRectangle *highlightRect) { - IntRange *displayRange = bigPictureGetDisplayRange(bigPicture); + BlxViewContext *bc = bigPictureGetContext(bigPicture); + BigPictureProperties *bpProperties = bigPictureGetProperties(bigPicture); + + /* Get the display range in dna coords */ + IntRange dnaDispRange; + convertDisplayRangeToDnaRange(&bpProperties->displayRange, bc->seqType, bc->numFrames, bc->displayRev, &bc->refSeqRange, &dnaDispRange); /* Find the base index where the new scroll range will start. This is the leftmost * edge of the preview box if numbers increase in the normal left-to-right direction, * or the rightmost edge if the display is reversed. */ - int x = getLeftCoordFromCentre(xCentre, highlightRect->width, displayRect); - int baseIdx = convertWidgetPosToBaseIdx(x, displayRect, displayRange); + const int x = getLeftCoordFromCentre(xCentre, highlightRect->width, displayRect); + const int baseIdx = convertWidgetPosToBaseIdx(x, displayRect, &dnaDispRange, bc->displayRev); /* Clear the preview box */ bigPictureSetPreviewBoxCentre(bigPicture, UNSET_INT); /* Update the detail view's scroll pos to start at the new base. The base index is in terms of - * the display coords, so the coord's sequence type is whatever the displayed sequence type is */ + * the nucleotide coords so we need to convert to display coords */ + const int displayIdx = convertDnaIdxToDisplayIdx(baseIdx, bc->seqType, 1, bc->numFrames, bc->displayRev, &bc->refSeqRange, NULL); + GtkWidget *detailView = bigPictureGetDetailView(bigPicture); - const BlxSeqType seqType = detailViewGetSeqType(detailView); /* displayed seq type */ - setDetailViewStartIdx(detailView, baseIdx, seqType); + setDetailViewStartIdx(detailView, displayIdx, bc->seqType); gtk_widget_queue_draw(bigPicture); } diff --git a/bigpicture.h b/bigpicture.h index e3ccb5f808394b6e4d7d1097416ffa88883b31eb..45f6dac88d87193a8a4a4358f970ca74a7822a19 100644 --- a/bigpicture.h +++ b/bigpicture.h @@ -97,8 +97,6 @@ void refreshBigPictureDisplayRange(GtkWidget *bigPicture, const gboolean void calculateNumVCells(GtkWidget *bigPicture); void bigPictureRedrawAll(GtkWidget *bigPicture); -gint convertWidgetPosToBaseIdx(const gint widgetPos, const GdkRectangle const *displayRect, const IntRange const *displayRange); - void drawPreviewBox(GtkWidget *bigPicture, GdkDrawable *drawable, GdkGC *gc, GdkRectangle *displayRect, GdkRectangle *highlightRect); void showPreviewBox(GtkWidget *bigPicture, const int x); void acceptAndClearPreviewBox(GtkWidget *bigPicture, const int xCentre, GdkRectangle *displayRect, GdkRectangle *highlightRect); @@ -109,9 +107,11 @@ void zoomWholeBigPicture(GtkWidget *bigPicture); gdouble pixelsPerBase(const gint displayWidth, const IntRange const *displayRange); -gint convertBaseIdxToGridPos(const gint baseIdx, +gint convertBaseIdxToGridPos(const gint dnaIdx, const GdkRectangle const *gridRect, - const IntRange const *displayRange); + const IntRange const *dnaDispRange, + const gboolean displayRev, + const gboolean clip); int getLeftCoordFromCentre(const int centreCoord, const int width, diff --git a/bigpicturegrid.c b/bigpicturegrid.c index 8dc2bc0c0f6268df0c14ba638416fcce7bac0ced..3f1a7c80664bbfebf115686fc64ab381990cc7cc 100644 --- a/bigpicturegrid.c +++ b/bigpicturegrid.c @@ -15,6 +15,7 @@ #include <SeqTools/utilities.h> #include <math.h> #include <string.h> +#include <stdlib.h> #define BIG_PICTURE_MSP_LINE_NAME "BigPictureMspLine" @@ -107,11 +108,15 @@ static void drawVerticalGridLines(GtkWidget *grid, GridProperties *properties = gridGetProperties(grid); BigPictureProperties *bpProperties = bigPictureGetProperties(properties->bigPicture); + /* Get the display range in dna coords */ + IntRange dnaDispRange; + convertDisplayRangeToDnaRange(&bpProperties->displayRange, bc->seqType, bc->numFrames, bc->displayRev, &bc->refSeqRange, &dnaDispRange); + const int direction = bc->displayRev ? -1 : 1; /* to subtract instead of add when display reversed */ /* Get the first base index (in terms of the nucleotide coords) and round it to a nice round * number. We'll offset all of the gridlines by the distance between this and the real start coord. */ - const int realFirstBaseIdx = convertDisplayIdxToDnaIdx(bpProperties->displayRange.min,bc-> seqType, 1, 1, bc->numFrames, bc->displayRev, &bc->refSeqRange); + const int realFirstBaseIdx = convertDisplayIdxToDnaIdx(bpProperties->displayRange.min, bc->seqType, 1, 1, bc->numFrames, bc->displayRev, &bc->refSeqRange); const int firstBaseIdx = roundToValue(realFirstBaseIdx, bpProperties->roundTo); /* Calculate the top and bottom heights for the lines. */ @@ -128,8 +133,7 @@ static void drawVerticalGridLines(GtkWidget *grid, int numBasesFromLeft = bpProperties->basesPerCell * hCell; int baseIdx = firstBaseIdx + (numBasesFromLeft * direction); - const int displayIdx = convertDnaIdxToDisplayIdx(baseIdx, bc->seqType, 1, bc->numFrames, bc->displayRev, &bc->refSeqRange, NULL); - const int x = convertBaseIdxToGridPos(displayIdx, &properties->gridRect, &bpProperties->displayRange); + const int x = convertBaseIdxToGridPos(baseIdx, &properties->gridRect, &dnaDispRange, bc->displayRev, TRUE); if (x > minX && x < maxX) { @@ -200,20 +204,15 @@ void calculateMspLineDimensions(GtkWidget *grid, BlxViewContext *bc = gridGetContext(grid); GridProperties *gridProperties = gridGetProperties(grid); - const IntRange const *displayRange = bigPictureGetDisplayRange(gridProperties->bigPicture); - const int frame = mspGetRefFrame(msp, bc->seqType); + /* Get the display range in dna coords */ + IntRange dnaDispRange; + convertDisplayRangeToDnaRange(gridGetDisplayRange(grid), bc->seqType, bc->numFrames, bc->displayRev, &bc->refSeqRange, &dnaDispRange); - /* Find the coordinates of the start and end base in this match sequence, and convert to display coords */ - const int coord1 = convertDnaIdxToDisplayIdx(msp->qRange.min, bc->seqType, frame, bc->numFrames, bc->displayRev, &bc->refSeqRange, NULL); - const int coord2 = convertDnaIdxToDisplayIdx(msp->qRange.max, bc->seqType, frame, bc->numFrames, bc->displayRev, &bc->refSeqRange, NULL); - - /* Convert the coords to grid positions. The grid positions we use are for the left edge - * of the coord, so to draw the end coord inclusively we need to increase the max coord by 1 */ - const int minCoord = min(coord1, coord2); - const int maxCoord = max(coord1, coord2) + 1; + const int x1 = convertBaseIdxToGridPos(msp->qRange.min, &gridProperties->gridRect, &dnaDispRange, bc->displayRev, TRUE); + const int x2 = convertBaseIdxToGridPos(msp->qRange.max, &gridProperties->gridRect, &dnaDispRange, bc->displayRev, TRUE); - int xMin = convertBaseIdxToGridPos(minCoord, &gridProperties->gridRect, displayRange); - int xMax = convertBaseIdxToGridPos(maxCoord, &gridProperties->gridRect, displayRange); + const int xMin = min(x1, x2); + const int xMax = max(x1, x2); if (x) { @@ -420,14 +419,25 @@ void calculateHighlightBoxBorders(GtkWidget *grid) if (adjustment) { BigPictureProperties *bigPictureProperties = bigPictureGetProperties(properties->bigPicture); + BlxViewContext *bc = gridGetContext(grid); - IntRange *displayRange = gridGetDisplayRange(grid); - int firstBaseIdx = adjustment->value; + /* Get the grid display range in dna coords */ + IntRange gridRange; + convertDisplayRangeToDnaRange(gridGetDisplayRange(grid), bc->seqType, bc->numFrames, bc->displayRev, &bc->refSeqRange, &gridRange); - properties->highlightRect.x = convertBaseIdxToGridPos(firstBaseIdx, &properties->gridRect, displayRange); - properties->highlightRect.y = 0; //properties->gridRect.y - bigPictureProperties->highlightBoxYPad; + /* Get the detail view display range in dna coords */ + GtkWidget *detailView = gridGetDetailView(grid); + IntRange dvRange; + convertDisplayRangeToDnaRange(detailViewGetDisplayRange(detailView), bc->seqType, bc->numFrames, bc->displayRev, &bc->refSeqRange, &dvRange); + + /* Get the x coords for the start and end of the detail view display range */ + const int x1 = convertBaseIdxToGridPos(dvRange.min, &properties->gridRect, &gridRange, bc->displayRev, TRUE); + const int x2 = convertBaseIdxToGridPos(dvRange.max, &properties->gridRect, &gridRange, bc->displayRev, TRUE); + + properties->highlightRect.x = min(x1, x2); + properties->highlightRect.y = 0; - properties->highlightRect.width = roundNearest((gdouble)adjustment->page_size * pixelsPerBase(properties->gridRect.width, displayRange)); + properties->highlightRect.width = abs(x1 - x2); properties->highlightRect.height = properties->gridRect.height + (bigPictureProperties->charHeight / 2) + properties->mspLineHeight + (2 * bigPictureProperties->highlightBoxYPad); } } diff --git a/exonview.c b/exonview.c index d61e301b49ed92af88b46a7e39df3306213a226b..f3b90485999d2737261f6b4b42803fbf661c9c51 100644 --- a/exonview.c +++ b/exonview.c @@ -14,6 +14,7 @@ #include <SeqTools/blxwindow.h> #include <SeqTools/utilities.h> #include <string.h> +#include <stdlib.h> #define DEFAULT_EXON_HEIGHT 10 #define DEFAULT_EXON_HEIGHT_BUMPED 7 @@ -31,6 +32,8 @@ typedef struct _ExonViewProperties GdkRectangle exonViewRect; /* The drawing area for the exon view */ GdkRectangle highlightRect; /* The area that the highlight box will cover (indicating the current detail-view display range) */ + + int exonHeight; /* the height of an individual exon */ } ExonViewProperties; @@ -86,23 +89,36 @@ void callFuncOnAllBigPictureExonViews(GtkWidget *widget, gpointer data) /* Draw an exon */ -static void drawExon(const MSP const *msp, GdkDrawable *drawable, DrawData *data, const BlxSequence *blxSeq, const gboolean isSelected, int x, int y, int width, int height) +static void drawExon(const MSP const *msp, + DrawData *data, + const BlxSequence *blxSeq, + const gboolean isSelected, + const int x, + const int y, + const int width, + const int height) { /* Draw the fill rectangle */ const GdkColor *fillColor = mspGetColor(msp, data->bc->defaultColors, blxSeq, isSelected, data->bc->usePrintColors, TRUE); gdk_gc_set_foreground(data->gc, fillColor); - gdk_draw_rectangle(drawable, data->gc, TRUE, x, y, width, height); + gdk_draw_rectangle(data->drawable, data->gc, TRUE, x, y, width, height); /* Draw outline (exon box outline always the same (unselected) color; only intron lines change when selected) */ const GdkColor *lineColor = mspGetColor(msp, data->bc->defaultColors, blxSeq, isSelected, data->bc->usePrintColors, FALSE); gdk_gc_set_foreground(data->gc, lineColor); - gdk_draw_rectangle(drawable, data->gc, FALSE, x, y, width, height); - + gdk_draw_rectangle(data->drawable, data->gc, FALSE, x, y, width, height); } /* Draw an intron */ -static void drawIntron(const MSP const *msp, GdkDrawable *drawable, DrawData *data, const BlxSequence *blxSeq, const gboolean isSelected, int x, int y, int width, int height) +static void drawIntron(const MSP const *msp, + DrawData *data, + const BlxSequence *blxSeq, + const gboolean isSelected, + const int x, + const int y, + const int width, + const int height) { const GdkColor *lineColor = mspGetColor(msp, data->bc->defaultColors, blxSeq, isSelected, data->bc->usePrintColors, FALSE); gdk_gc_set_foreground(data->gc, lineColor); @@ -110,9 +126,18 @@ static void drawIntron(const MSP const *msp, GdkDrawable *drawable, DrawData *da int xMid = x + roundNearest((double)width / 2.0); int xEnd = x + width; int yMid = y + roundNearest((double)height / 2.0); + + /* Only draw the individual sections if they are in range. For some reason they get drawn in + * the wrong place otherwise. */ + if (xMid >= data->exonViewRect->x && x <= data->exonViewRect->x + data->exonViewRect->width) + { + gdk_draw_line(data->drawable, data->gc, x, yMid, xMid, y); + } - gdk_draw_line(drawable, data->gc, x, yMid, xMid, y); - gdk_draw_line(drawable, data->gc, xMid, y, xEnd, yMid); + if (xEnd >= data->exonViewRect->x && xMid <= data->exonViewRect->x + data->exonViewRect->width) + { + gdk_draw_line(data->drawable, data->gc, xMid, y, xEnd, yMid); + } } @@ -131,26 +156,39 @@ static gboolean drawExonIntron(const MSP *msp, DrawData *data, const gboolean is IntRange mspDisplayRange; intrangeSetValues(&mspDisplayRange, coord1, coord2); /* sorts out which is min and max */ + /* Include an extra coord either side because we draw slightly over the edges */ + --mspDisplayRange.min; + ++mspDisplayRange.max; + if (rangesOverlap(&mspDisplayRange, data->displayRange)) { drawn = TRUE; - /* The grid pos gives the left edge of the coord, so to be inclusive we draw to the max coord + 1 */ - const int xMin = convertBaseIdxToGridPos(mspDisplayRange.min, data->exonViewRect, data->displayRange); - const int xMax = convertBaseIdxToGridPos(mspDisplayRange.max + 1, data->exonViewRect, data->displayRange); + /* Get the display range in dna coords */ + IntRange dnaDispRange; + convertDisplayRangeToDnaRange(data->displayRange, data->bc->seqType, data->bc->numFrames, data->bc->displayRev, &data->bc->refSeqRange, &dnaDispRange); + + /* The grid pos gives the left edge of the coord, so to be inclusive we draw to the end coord + 1 + * (or end - 1 if the end coord is the lower value) */ + const int direction = (mspGetRefStrand(msp) == BLXSTRAND_FORWARD) ? 1 : -1; + const int qStart = mspGetQStart(msp); + const int qEnd = mspGetQEnd(msp) + direction; - int x = xMin; - int width = xMax - xMin; + const int x1 = convertBaseIdxToGridPos(qStart, data->exonViewRect, &dnaDispRange, data->bc->displayRev, FALSE); + const int x2 = convertBaseIdxToGridPos(qEnd, data->exonViewRect, &dnaDispRange, data->bc->displayRev, FALSE); + + int x = min(x1, x2); + int width = abs(x1 - x2); int y = data->y; int height = data->height; if (mspIsExon(msp)) { - drawExon(msp, data->drawable, data, blxSeq, isSelected, x, y, width, height); + drawExon(msp, data, blxSeq, isSelected, x, y, width, height); } else if (mspIsIntron(msp)) { - drawIntron(msp, data->drawable, data, blxSeq, isSelected, x, y, width, height); + drawIntron(msp, data, blxSeq, isSelected, x, y, width, height); } } @@ -225,9 +263,14 @@ static void drawExonView(GtkWidget *exonView, GdkDrawable *drawable) bigPictureProperties->highlightBoxMinWidth, highlightBoxColor); + /* Set a clip rectangle for drawing the exons and introns (because they are drawn "over the + * edges" to make sure intron lines have the correct slope etc.) */ + GdkGC *gc = gdk_gc_new(drawable); + gdk_gc_set_clip_origin(gc, 0, 0); + gdk_gc_set_clip_rectangle(gc, &properties->exonViewRect); + /* Draw the exons and introns. Since we could have a lot of them in the loop, extract all the * info we need now and pass it around so we don't have to look for this stuff each time. */ - GdkGC *gc = gdk_gc_new(drawable); DrawData drawData = { drawable, @@ -245,7 +288,7 @@ static void drawExonView(GtkWidget *exonView, GdkDrawable *drawable) FALSE, properties->yPad, properties->exonViewRect.y, - properties->exonViewRect.height + properties->exonHeight }; /* If the view is compressed (i.e. exons will overlap each other), then @@ -324,32 +367,35 @@ void calculateExonViewHeight(GtkWidget *exonView) } } - const int newHeight = (numExons * (properties->exonViewRect.height + properties->yPad)) + (2 * properties->yPad); + properties->exonViewRect.height = (numExons * (properties->exonHeight + properties->yPad)) + (2 * properties->yPad); - gtk_widget_set_size_request(exonView, -1, newHeight); + gtk_widget_set_size_request(exonView, -1, properties->exonViewRect.height); } void calculateExonViewHighlightBoxBorders(GtkWidget *exonView) { ExonViewProperties *properties = exonViewGetProperties(exonView); + BlxViewContext *bc = bigPictureGetContext(properties->bigPicture); - /* Calculate how many pixels from the left edge of the widget to the first base in the range. Truncating - * the double to an int after the multiplication means we can be up to 1 pixel out, but this should be fine. */ + /* Get the big picture display range in dna coords */ + IntRange bpRange; + convertDisplayRangeToDnaRange(bigPictureGetDisplayRange(properties->bigPicture), bc->seqType, bc->numFrames, bc->displayRev, &bc->refSeqRange, &bpRange); + + /* Get the detail view display range in dna coords */ + IntRange dvRange; GtkWidget *detailView = bigPictureGetDetailView(properties->bigPicture); - GtkAdjustment *adjustment = detailViewGetAdjustment(detailView); + convertDisplayRangeToDnaRange(detailViewGetDisplayRange(detailView), bc->seqType, bc->numFrames, bc->displayRev, &bc->refSeqRange, &dvRange); - if (adjustment) - { - IntRange *displayRange = bigPictureGetDisplayRange(properties->bigPicture); - int firstBaseIdx = adjustment->value; - - properties->highlightRect.x = convertBaseIdxToGridPos(firstBaseIdx, &properties->exonViewRect, displayRange); - properties->highlightRect.y = 0; //properties->exonViewRect.y - bigPictureProperties->highlightBoxYPad; - - properties->highlightRect.width = roundNearest((gdouble)adjustment->page_size * pixelsPerBase(properties->exonViewRect.width, displayRange)); - properties->highlightRect.height = exonView->allocation.height; //properties->exonViewRect.height + (2 * bigPictureProperties->highlightBoxYPad); - } + /* Calculate how many pixels from the left edge of the widget to the first base in the range. */ + const int x1 = convertBaseIdxToGridPos(dvRange.min, &properties->exonViewRect, &bpRange, bc->displayRev, TRUE); + const int x2 = convertBaseIdxToGridPos(dvRange.max, &properties->exonViewRect, &bpRange, bc->displayRev, TRUE); + + properties->highlightRect.x = min(x1, x2); + properties->highlightRect.y = 0; + + properties->highlightRect.width = abs(x1 - x2); + properties->highlightRect.height = exonView->allocation.height; } @@ -404,6 +450,8 @@ static void exonViewCreateProperties(GtkWidget *exonView, properties->exonViewRect.y = DEFAULT_EXON_YPAD; properties->exonViewRect.width = 0; properties->exonViewRect.height = DEFAULT_EXON_HEIGHT; + + properties->exonHeight = DEFAULT_EXON_HEIGHT; gtk_widget_set_size_request(exonView, 0, DEFAULT_EXON_HEIGHT + (2 * DEFAULT_EXON_YPAD)); @@ -439,12 +487,12 @@ void exonViewSetExpanded(GtkWidget *exonView, const gboolean expanded) if (expanded) { properties->yPad = DEFAULT_EXON_YPAD_BUMPED; - properties->exonViewRect.height = DEFAULT_EXON_HEIGHT_BUMPED; + properties->exonHeight = DEFAULT_EXON_HEIGHT_BUMPED; } else { properties->yPad = DEFAULT_EXON_YPAD; - properties->exonViewRect.height = DEFAULT_EXON_HEIGHT; + properties->exonHeight = DEFAULT_EXON_HEIGHT; } calculateExonViewHeight(exonView); diff --git a/utilities.c b/utilities.c index dbf35c41cfbad90773fb7df21dcbe42afa8477d6..cd33c0d56e22225aa58b0a24bb2de2dc190d6ebb 100644 --- a/utilities.c +++ b/utilities.c @@ -741,6 +741,20 @@ char getRefSeqBase(char *refSeq, } +/* Convert the given range of display coords to dna coords */ +void convertDisplayRangeToDnaRange(const IntRange const * displayRange, + const BlxSeqType displaySeqType, + const int numFrames, + const gboolean displayRev, + const IntRange const *refSeqRange, + IntRange *result) +{ + const int q1 = convertDisplayIdxToDnaIdx(displayRange->min, displaySeqType, 1, 1, numFrames, displayRev, refSeqRange); /* 1st base in 1st reading frame */ + const int q2 = convertDisplayIdxToDnaIdx(displayRange->max, displaySeqType, numFrames, numFrames, numFrames, displayRev, refSeqRange); /* last base in last frame */ + intrangeSetValues(result, q1, q2); +} + + /* Given an index into the displayed sequence, a reading frame, and the base number within that * reading frame, return the index into the DNA sequence that will give the equivalent DNA base. * If the display sequence is a peptide sequence, it will convert the coord to a DNA coord. If the diff --git a/utilities.h b/utilities.h index 529af30c0e29832e14af9d4a44070a567a917e54..249eefd38d2dacd14cf90ce9a51fa30170cf910e 100644 --- a/utilities.h +++ b/utilities.h @@ -190,6 +190,13 @@ void boundsLimitValue(int *value, const IntRange const *range); void boundsLimitRange(IntRange *range, const IntRange const *limit, const gboolean maintainLen); char convertBaseToCorrectCase(const char charToConvert, const BlxSeqType seqType); +void convertDisplayRangeToDnaRange(const IntRange const * displayRange, + const BlxSeqType displaySeqType, + const int numFrames, + const gboolean displayRev, + const IntRange const *refSeqRange, + IntRange *result); + int convertDisplayIdxToDnaIdx(const int inputIdx, const BlxSeqType inputIdxType, const int frame,