/* Title: display File: display.c Purpose: Sequence display and editing Last update: Friday 15 May 1992 */ /* The display is created by a call to CreateDisplay. It principally consists of two components: the first, created by a call to createBasesDisplay displays the original and edited bases, the second, created by a call to createTracesDisplay, displays the traces. Editing is done by stream: as the client presses keys and buttons these must be interpreted as editing keystrokes. The viewport widget does not itself hand out resize events, so we create a dummy (graph) widget in the same patch, connected in the same way to the walls of the form, to collect resize events and allow us to adjust scalings for the graphs within the viewport. This is slightly dodgy and should be redone some other way. Changes to this program by lfw: module displaySeq Added the parameter mag to the parameters passed to the subroutine Changed to default magnification to 30% by changing the call to setGraphWidth to be 30 rather than -1. And by allowing the call to setGraphWidth to be specified by the user which comes from the main calling program via the mag parameter Changes made by sd: Added scaleUp and scaleDown buttons + callbacks SD 15-May-1992 editSeqEvents(): DEC Xlib function XlookupString didn't always work with a buffer of length of 1, even when only one character returned. Made buffer larger - now eight characters (doesn't work with <=four) */ /* ---- Includes ---- */ #include "display.h" #include "traceDisplay.h" /* IMPORT: createTraceDisplay, displayTrace, unDisplayTrace, setTraceWidth */ #include "basesDisplay.h" /* IMPORT: createBasesDisplay, displayBases, unDisplayBases, setBasesWidth */ #include "Graph.h" #include "seq.h" /* IMPORT: Seq, NULLSeq, getNPoints */ #include /* IMPORT: isgraph */ #include #include #include #include #include #include #include #include #include /* ---- Constants ---- */ #define MaxDimension 32767 /* By definition, 2^16-1 */ #define MaxMagCharSpace 5 /* At maximum magnification, the distance in characters between each base */ #define ViewportFudge 10 /* A guess of the space required within the viewport for the graph to fit */ /* the following allows us to get the default magnification from the app_defaults file, Xted */ typedef struct { int magnif; String enz; } AppData, *AppDataPtr; #define XtNmagnif "magnif" #define XtCMagnif "Magnif" #define XtNenz "enz" #define XtCEnz "Enz" static XtResource resources[] = { { XtNmagnif, XtCMagnif, XtRInt, sizeof(int), XtOffset(AppDataPtr, magnif), XtRImmediate, NULL }, { XtNenz, XtCEnz, XtRString, sizeof(String), XtOffset(AppDataPtr, enz), XtRImmediate, NULL } }; /* ---- Statics ---- */ /* Current sequence information */ static Seq currSeq = NULLSeq; static int NPoints; static int NedBases; /* Viewport widget */ static Widget viewportWid; static Widget vpFormWid; static Widget dummyWid; static Dimension charWidth; /* As used by basesDisplay */ static Dimension minGraphWidth; /* All characters displayed (depends on width of parent viewport) */ static Dimension maxGraphWidth; /* Bases spaced out with `MaxMagCharSpace' blanks (depends on char size and NorigBases) */ static Dimension graphWidth; /* Current width of the graph */ static Dimension plotEdgeOffset; /* Editing state toggles */ static Widget togWid; /* The group of toggles */ /* Magnification widget */ static Widget magWid; /* ---- Internal routines ---- */ static void setGraphWidth(int percent) /* Set the widths of the graphs to be `percent' between the minimum and maximum widths. The current ``centre of interest'' is maintained. */ { int nargs; Arg args[10]; float centre, topOfThumb, shown; Widget hScrollWid = XtNameToWidget(viewportWid, "horizontal"); /* The ``centre of interest'' is the middle of the displayed graph. Percentagewise, this is given by `topOfThumb+show/2'. */ nargs=0; XtSetArg(args[nargs], XtNtopOfThumb, &topOfThumb); nargs++; XtSetArg(args[nargs], XtNshown, &shown); nargs++; XtGetValues(hScrollWid, args, nargs); centre = topOfThumb+shown/2; /* Set the displays to the required width */ graphWidth = ((maxGraphWidth-minGraphWidth) * percent)/100 + minGraphWidth; XawFormDoLayout(vpFormWid, False); nargs = 0; XtSetArg(args[nargs], XtNwidth, graphWidth); nargs++; setBasesWidth(graphWidth); setTraceWidth(graphWidth); XawFormDoLayout(vpFormWid, True); /* We have changed the size of the form widget within the viewport widget. The viewport does not define where exactly the form will now sit, so we manually reset the ``centre of interest'', keeping `shown' at its (new) value. */ nargs=0; XtSetArg(args[nargs], XtNtopOfThumb, &topOfThumb); nargs++; XtSetArg(args[nargs], XtNshown, &shown); nargs++; XtGetValues(hScrollWid, args, nargs); topOfThumb = centre-shown/2; XawScrollbarSetThumb(hScrollWid, topOfThumb, shown); XtCallCallbacks(hScrollWid, XtNjumpProc, &topOfThumb); } static void editSeqEvent(XEvent *eventP) /* `eventP' (a button or key press) is interpreted as a sequence editing command. */ { char buffer[8]; KeySym keySym; int charCount; XComposeStatus compose; switch (eventP->type) { case KeyPress: charCount = XLookupString((XKeyEvent *)eventP, buffer, 8, &keySym, &compose); switch (keySym) { case XK_Right: moveCaretRight(); break; case XK_Left: moveCaretLeft(); break; case XK_Delete: /* Delete the base to the left of the caret */ if (deleteBase(currSeq, getCaret())) { baseDeleted(); NedBases--; } else XBell(XtDisplay(viewportWid), 100); break; default: if (charCount==1 && isgraph(buffer[0])) { /* Insert the base to the right of the caret */ if (insertBase(currSeq, buffer[0], getCaret())) { baseInserted(); NedBases++; } else XBell(XtDisplay(viewportWid), 100); } break; } break; case ButtonPress: { /* Move the caret to where the pointer is */ int point = pixelToPoint(eventP->xbutton.x); if (point<0) moveCaretTo(-1); else if (point>NPoints-1) moveCaretTo(NedBases-1); else { int b = pointToBaseNum(currSeq, EdBases, point); moveCaretTo((b == NULLBaseNum) ? NedBases-1 : b-1); } break; } } } static void adjustLEvent(XEvent *eventP) /* `eventP' (a button or key press) is interpreted as a command to adjust the left cutoff. */ { char buffer[1]; KeySym keySym; int charCount; XComposeStatus compose; int leftCutoff, rightCutoff; switch (eventP->type) { case KeyPress: charCount = XLookupString((XKeyEvent *)eventP, buffer, 1, &keySym, &compose); switch (keySym) { case XK_Right: /* Move the cutoff right one */ getCutoffs(currSeq, &leftCutoff, &rightCutoff); if (leftCutoff0) leftCutoff--; (void) setCutoffs(currSeq, leftCutoff, rightCutoff); basesCutoffChange(); traceCutoffChange(); break; } break; case ButtonPress: { int point, baseNum; /* Move the cutoff to where the pointer is */ point = pixelToPoint(eventP->xbutton.x); if (point<0) baseNum = 0; else if (point>NPoints-1) baseNum = NedBases; else { baseNum = pointToBaseNum(currSeq, EdBases, point); baseNum = (baseNum == NULLBaseNum) ? NedBases : baseNum; } getCutoffs(currSeq, &leftCutoff, &rightCutoff); setCutoffs(currSeq, baseNum, rightCutoff); basesCutoffChange(); traceCutoffChange(); break; } } } static void adjustREvent(XEvent *eventP) /* `eventP' (a button or key press) is interpreted as a command to adjust the right cutoff. */ { char buffer[1]; KeySym keySym; int charCount; XComposeStatus compose; int leftCutoff, rightCutoff; switch (eventP->type) { case KeyPress: charCount = XLookupString((XKeyEvent *)eventP, buffer, 1, &keySym, &compose); switch (keySym) { case XK_Right: /* Move the cutoff right one */ getCutoffs(currSeq, &leftCutoff, &rightCutoff); if (rightCutoff>0) rightCutoff--; (void) setCutoffs(currSeq, leftCutoff, rightCutoff); basesCutoffChange(); traceCutoffChange(); break; case XK_Left: /* Move the cutoff left one */ getCutoffs(currSeq, &leftCutoff, &rightCutoff); if (rightCutoffxbutton.x); if (point<0) baseNum = 0; else if (point>NPoints-1) baseNum = NedBases; else { baseNum = pointToBaseNum(currSeq, EdBases, point); baseNum = (baseNum == NULLBaseNum) ? NedBases : baseNum; } getCutoffs(currSeq, &leftCutoff, &rightCutoff); setCutoffs(currSeq, leftCutoff, NedBases-baseNum); basesCutoffChange(); traceCutoffChange(); break; } } } /* ---- Callbacks ---- */ static void resizeCallback(Widget wid, XtPointer client_data, XtPointer call_data) { Dimension width; int mag; Arg args[10]; int nargs; nargs = 0; XtSetArg(args[nargs], XtNwidth, &width); nargs++; XtGetValues(viewportWid, args, nargs); /* Back calculate what the current magnification is */ mag = ((graphWidth-minGraphWidth)*100) / (maxGraphWidth-minGraphWidth); /* Adjust the minimum magnification */ minGraphWidth = width-ViewportFudge; graphWidth = minGraphWidth; /* Set us to the old magnification, but with the new dimensions */ setGraphWidth(mag); } static void magJumpCallback(Widget wid, XtPointer client_data, XtPointer call_data) { float percent = *((float *) call_data); setGraphWidth((int) (percent*100)); } static void magScrollCallback(Widget wid, XtPointer client_data, XtPointer call_data) { int position = (int) call_data; float topOfThumb; int nargs; Arg args[10]; nargs=0; XtSetArg(args[nargs], XtNtopOfThumb, &topOfThumb); nargs++; XtGetValues(wid, args, nargs); /* Move the thumb by 1% in the appropriate direction */ if (position>0) { topOfThumb += .01; if (topOfThumb > 1.0) topOfThumb = 1.0; } else { topOfThumb -= .01; if (topOfThumb < 0.0) topOfThumb = 0.0; } XawScrollbarSetThumb(wid, topOfThumb, -1.0); setGraphWidth((int) (topOfThumb*100)); } static void scaleUpCallback(Widget wid, XtPointer client_data, XtPointer call_data) { incScaleFactor(); } static void scaleDownCallback(Widget wid, XtPointer client_data, XtPointer call_data) { decScaleFactor(); } static void complementCallback(Widget wid, XtPointer client_data, XtPointer call_data) { complement_seq(currSeq); /* force redisplay of everything in viewport widget */ redisplayTraces(); redisplayBases(); /* shift caret */ moveCaretTo(currSeq->NedBases - getCaret() - 2); { /* set viewport position */ Cardinal nargs; float topOfThumb, shown; Arg args[2]; Widget hScrollWid = XtNameToWidget(viewportWid, "horizontal"); nargs=0; XtSetArg(args[nargs], XtNtopOfThumb, &topOfThumb); nargs++; XtSetArg(args[nargs], XtNshown, &shown); nargs++; XtGetValues(hScrollWid, args, nargs); topOfThumb = 1.0 - shown - topOfThumb; XawScrollbarSetThumb(hScrollWid, topOfThumb, shown); XtCallCallbacks(hScrollWid, XtNjumpProc, &topOfThumb); } /* set strand widget */ { Widget strandWid; strandWid = XtNameToWidget(XtParent(wid), "strand"); set_strand_label(strandWid,currSeq); } } /* ---- Exports ---- */ void createDisplay(Widget parentWid, Widget fromVertWid) /* Create the display within the Form widget `parentWid' with the XtNfromVert constraint `fromVertWid'. No sequence is initally displayed. */ { Widget labelWid, basesWid; Widget scaleUpWid, scaleDownWid; Widget compWid; Arg args[10]; int nargs; /* The magnification slider */ nargs = 0; XtSetArg(args[nargs], XtNfromVert, fromVertWid); nargs++; labelWid = XtCreateManagedWidget("maglab", labelWidgetClass, parentWid, args, nargs); nargs = 0; XtSetArg(args[nargs], XtNfromVert, fromVertWid); nargs++; XtSetArg(args[nargs], XtNfromHoriz, labelWid); nargs++; magWid = XtCreateManagedWidget("magscr", scrollbarWidgetClass, parentWid, args, nargs); XtAddCallback(magWid, XtNjumpProc, magJumpCallback, NULL); XtAddCallback(magWid, XtNscrollProc, magScrollCallback, NULL); /* The editing mode toggles */ nargs = 0; XtSetArg(args[nargs], XtNfromVert, fromVertWid); nargs++; XtSetArg(args[nargs], XtNfromHoriz, magWid); nargs++; labelWid = XtCreateManagedWidget("edmodelab", labelWidgetClass, parentWid, args, nargs); nargs = 0; XtSetArg(args[nargs], XtNfromVert, fromVertWid); nargs++; XtSetArg(args[nargs], XtNfromHoriz, labelWid); nargs++; togWid = XtCreateManagedWidget("adjustL", toggleWidgetClass, parentWid, args, nargs); nargs = 0; XtSetArg(args[nargs], XtNfromVert, fromVertWid); nargs++; XtSetArg(args[nargs], XtNfromHoriz, togWid); nargs++; XtSetArg(args[nargs], XtNradioGroup, togWid); nargs++; togWid = XtCreateManagedWidget("edSeq", toggleWidgetClass, parentWid, args, nargs); nargs = 0; XtSetArg(args[nargs], XtNfromVert, fromVertWid); nargs++; XtSetArg(args[nargs], XtNfromHoriz, togWid); nargs++; XtSetArg(args[nargs], XtNradioGroup, togWid); nargs++; togWid = XtCreateManagedWidget("adjustR", toggleWidgetClass, parentWid, args, nargs); /* for vertical scaling */ nargs = 0; XtSetArg(args[nargs], XtNfromVert, fromVertWid); nargs++; XtSetArg(args[nargs], XtNfromHoriz, togWid); nargs++; scaleDownWid = XtCreateManagedWidget("scaleDown", commandWidgetClass, parentWid, args, nargs); XtAddCallback(scaleDownWid, XtNcallback, scaleDownCallback, NULL); nargs = 0; XtSetArg(args[nargs], XtNfromVert, fromVertWid); nargs++; XtSetArg(args[nargs], XtNfromHoriz, scaleDownWid); nargs++; scaleUpWid = XtCreateManagedWidget("scaleUp", commandWidgetClass, parentWid, args, nargs); XtAddCallback(scaleUpWid, XtNcallback, scaleUpCallback, NULL); nargs = 0; XtSetArg(args[nargs], XtNfromVert, fromVertWid); nargs++; XtSetArg(args[nargs], XtNfromHoriz, scaleUpWid); nargs++; compWid = XtCreateManagedWidget("switch", commandWidgetClass, parentWid, args, nargs); XtAddCallback(compWid, XtNcallback, complementCallback, NULL); /* The main display */ nargs = 0; XtSetArg(args[nargs], XtNfromVert, labelWid); nargs++; XtSetArg(args[nargs], XtNforceBars, True); nargs++; viewportWid = XtCreateManagedWidget("viewport", viewportWidgetClass, parentWid, args, nargs); /* The minimum graph width is the viewport width minus a random amount to allow for spacing between the viewport and the graph, borders etc. The initial graph width is this minimum width. */ { Dimension vpWidth; nargs = 0; XtSetArg(args[nargs], XtNwidth, &vpWidth); nargs++; XtGetValues(viewportWid, args, nargs); minGraphWidth = vpWidth-ViewportFudge; graphWidth = minGraphWidth; } nargs = 0; vpFormWid = XtCreateManagedWidget("vpForm", formWidgetClass, viewportWid, args, nargs); basesWid = createBasesDisplay(vpFormWid, NULL, graphWidth); getBasesFontInfo(&plotEdgeOffset, &charWidth); createTraceDisplay(vpFormWid,basesWid,graphWidth, plotEdgeOffset); nargs = 0; XtSetArg(args[nargs], XtNfromVert, magWid); nargs++; dummyWid = XtCreateManagedWidget("dummy", graphWidgetClass, parentWid, args, nargs); XtAddCallback(dummyWid, XtNresizeCallback, resizeCallback, NULL); } void displaySeq(Seq seq, int baseNum, int mag) /* Display the sequence `seq' for editing. If baseNum is not equal to NULLBaseNum, display at 30% (or mag) magnification centered on baseNum. */ { AppData app_data; XtGetApplicationResources(magWid, (XtPointer) &app_data, resources, XtNumber(resources), NULL, 0); if (seq == NULLSeq) return; currSeq = seq; displayBases(seq,baseNum); displayTrace(seq); /* The maximum graph width is such to allow for a `MaxMagCharSpace' spacing between bases. There is a limit on Dimension sizes, noting that the graph we generate has to fit into a Viewport. */ { Dimension maxWidth; int NorigBases; NorigBases = getNBases(currSeq, OrigBases); maxWidth = ((NorigBases-1) * charWidth * MaxMagCharSpace) + (2 * plotEdgeOffset); maxGraphWidth = (maxWidth>MaxDimension-ViewportFudge) ? MaxDimension-ViewportFudge : (maxWidth 100) { setGraphWidth(0); XawScrollbarSetThumb(magWid, 0.3, -1.0); } else { setGraphWidth(mag); XawScrollbarSetThumb(magWid, (float)mag/100.0, -1.0); } } else { /* Centred on baseNum, half magnification */ Widget hScrollWid = XtNameToWidget(viewportWid, "horizontal"); float topOfThumb; /* Set the `centre of interest' on baseNum. Zero `shown'. */ /* topOfThumb = (float)baseNum / (float)(NedBases-1); */ topOfThumb = (float) baseNumToPoint(seq, OrigBases,baseNum) / (float) NPoints; XawScrollbarSetThumb(hScrollWid, topOfThumb, 0.0); /* Set the actual magnification */ /* the original program automatically set the magnification to 30% if the user specified a baseNum other than NULL, this section was added by LaDeana Hillier, 9/27/90, to allow the user to set their own magnification when calling up ted. */ if (mag==-5) /* back calculate it */ mag = ((graphWidth-minGraphWidth)*100) / (maxGraphWidth-minGraphWidth); if (app_data.magnif==0) app_data.magnif = 30; if (mag <= 0 || mag > 100) { setGraphWidth(app_data.magnif); /* Set the magnification scrollbar */ XawScrollbarSetThumb(magWid, (float)(app_data.magnif)/100.0, -1.0); } else { setGraphWidth(mag); XawScrollbarSetThumb(magWid, (float)mag/100.0, -1.0); } } } void unDisplaySeq() /* Cease displaying the current sequence (if any). */ { currSeq = NULLSeq; /* Reset the magnification to minimum. The thumb is left its default size. */ XawScrollbarSetThumb(magWid, 0.0, -1.0); unDisplayBases(); unDisplayTrace(); /* The initial width is the minimum, so everything is visible. This also clears the graphs. */ setGraphWidth(0); } Seq displayedSeq() /* Return the currently displayed sequence, or NULL if none is being displayed. */ { return(currSeq); } void userEvent(XEvent *eventP) { String currTog; if (currSeq == NULLSeq) return; /* Find which of the toggles is currently set */ currTog = (String) XawToggleGetCurrent(togWid); if (strcmp(currTog, "adjustL") == 0) { /* Adjust the left cutoff */ adjustLEvent(eventP); } else if (strcmp(currTog, "adjustR") == 0) { /* Adjust the right cutoff */ adjustREvent(eventP); } else { /* Edit the sequence itself */ editSeqEvent(eventP); } }