/*****************************************************************************
#   Copyright (C) 1994-2008 by David Gordon.
#   All rights reserved.                           
#                                                                           
#   This software is part of a beta-test version of the Consed/Autofinish
#   package.  It should not be redistributed or
#   used for any commercial purpose, including commercially funded
#   sequencing, without written permission from the author and the
#   University of Washington.
#   
#   This software is provided ``AS IS'' and any express or implied
#   warranties, including, but not limited to, the implied warranties of
#   merchantability and fitness for a particular purpose, are disclaimed.
#   In no event shall the authors or the University of Washington be
#   liable for any direct, indirect, incidental, special, exemplary, or
#   consequential damages (including, but not limited to, procurement of
#   substitute goods or services; loss of use, data, or profits; or
#   business interruption) however caused and on any theory of liability,
#   whether in contract, strict liability, or tort (including negligence
#   or otherwise) arising in any way out of the use of this software, even
#   if advised of the possibility of such damage.
#
#   Building Consed from source is error prone and not simple which is
#   why I provide executables.  Due to time limitations I cannot
#   provide any assistance in building Consed.  Even if you do not
#   modify the source, you may introduce errors due to using a
#   different version of the compiler, a different version of motif,
#   different versions of other libraries than I used, etc.  For this
#   reason, if you discover Consed bugs, I can only offer help with
#   those bugs if you first reproduce those bugs with an executable
#   provided by me--not an executable you have built.
# 
#   Modifying Consed is also difficult.  Although Consed is modular,
#   some modules are used by many other modules.  Thus making a change
#   in one place can have unforeseen effects on many other features.
#   It may takes months for you to notice these other side-effects
#   which may not seen connected at all.  It is not feasable for me to
#   provide help with modifying Consed sources because of the
#   potentially huge amount of time involved.
#
#*****************************************************************************/
#include    <Xm/Form.h>
#include    <Xm/DrawingA.h>
#include    <Xm/ScrollBar.h>
#include    <Xm/PushB.h>
#include    <Xm/RowColumn.h>
#include    <Xm/Label.h>
#include    <Xm/ToggleB.h>
#include    "guiDisplayDigest.h"
#include    "guiFindRestrictionEnzymeSites.h"
#include    <Xm/ScrolledW.h>
#include    <Xm/Text.h>
#include    "guicolortext.h"
#include    "hp_exception_kludge.h"
#include    "waitUntilDialogIsVisible.h"
#include    "handleWindowManagerDelete2.h"
#include    "digestForOneEnzyme.h"
#include    <Xm/List.h>
#include    <Xm/SelectioB.h>
#include    "contigEnd.h"
#include    "consed.h"
#include    "contigwin.h"
#include    "popupErrorMessage2.h"
#include    <Xm/TextF.h>
#include    "consedParameters.h"
#include    "guicolortext.h"
#include    "colorDefaults.h"
#include    "visibleLineForRestrictionFragments.h"
#include    "popupErrorMessage.h"
#include    "guiDigestProblemNavigator.h"
#include    "clScaffold.h"
#include    "textbox.h"
#include    <Xm/MainW.h>
#include    <Xm/CascadeB.h>
#include    "assemblyView.h"




const int nGelScrollBarIncrementInPixels = 20;
const int nHalfHeightOfCursorIndicator = 6;


static char szNumber[100];

const int nHugeRestrictionFragment = 100000000;


static void cbGuiShowDocumentationForRestrictionDigest( Widget wid,
                                                        XtPointer pClientData,
                                                        XtPointer pCallData ) {

   guiDisplayDigest* pDisplayDigest = (guiDisplayDigest*) pClientData;  
   TRY_CATCH_WRAPPER( pDisplayDigest->showDocumentationForRestrictionDigest() );

}



static void cbUserPushedShowProblems( Widget wid,
                                      XtPointer pClientData,
                                      XtPointer pCallData ) {

   guiDisplayDigest* pDisplayDigest = (guiDisplayDigest*) pClientData;

   TRY_CATCH_WRAPPER( pDisplayDigest->userPushedShowProblems() );
}


static void cbComplVector( Widget wid,
                           XtPointer pClientData,
                           XtPointer pCallData ) {

   guiDisplayDigest* pDisplayDigest = (guiDisplayDigest*) pClientData;

   TRY_CATCH_WRAPPER( pDisplayDigest->userPushedComplVector() );
}
   



static void cbInput( Widget wid,
                     XtPointer pClientData,
                     XtPointer pCallData ) {

   guiDisplayDigest* pDisplayDigest = (guiDisplayDigest*) pClientData;
   
   TRY_CATCH_WRAPPER( pDisplayDigest->userClicked( pCallData ) );
}




static void pointerMotionEventHandler( Widget wid,
                                  XtPointer pClientData,
                                  XEvent* pEvent,
                                  Boolean* ) {
   
   int nPixelX = pEvent->xmotion.x;
   int nPixelY = pEvent->xmotion.y;
   
   guiDisplayDigest* pDisplayDigest = (guiDisplayDigest*) pClientData;
   
   TRY_CATCH_WRAPPER( pDisplayDigest->pointerMoved( nPixelX, nPixelY ) );
}


static void cbUserPushedZoomInOrOut(
      Widget wid,
      XtPointer pClientData,
      XtPointer pCallData ) {

   guiDisplayDigest* pDisplayRes = (guiDisplayDigest*) pClientData;
   TRY_CATCH_WRAPPER( pDisplayRes->userPushedZoomInOrOut( wid ) );

}


static void cbUserPushedShowTextOutput(
      Widget wid,
      XtPointer pClientData,
      XtPointer pCallData ) {

   guiDisplayDigest* pDisplayRes = (guiDisplayDigest*) pClientData;
   TRY_CATCH_WRAPPER( pDisplayRes->showTextOutput() );
}


static void cbUserChangedEnzyme(
      Widget wid,
      XtPointer pClientData,
      XtPointer pCallData ) {

   guiDisplayDigest* pDisplayRes = (guiDisplayDigest*) pClientData;
   TRY_CATCH_WRAPPER( pDisplayRes->userChangedEnzyme( wid ) );

}


static void cbUserPushedGotoRightEnd( 
      Widget wid,
      XtPointer pClientData,
      XtPointer pCallData ) {

   guiDisplayDigest* pDisplayRes = 
      ( guiDisplayDigest* ) pClientData;

   TRY_CATCH_WRAPPER( pDisplayRes->gotoEnd( nRightGap ) );

}


static void cbUserPushedGotoLeftEnd( 
      Widget wid,
      XtPointer pClientData,
      XtPointer pCallData ) {

   guiDisplayDigest* pDisplayRes = 
      ( guiDisplayDigest* ) pClientData;

   TRY_CATCH_WRAPPER( pDisplayRes->gotoEnd( nLeftGap ) );

}


static void cbGelScrollBar(
      Widget wid,
      XtPointer pClientData,
      XtPointer pCallData ) {

   guiDisplayDigest* pDisplayRes = 
      ( guiDisplayDigest* ) pClientData;

   XmScrollBarCallbackStruct* pCbStruct = 
      (XmScrollBarCallbackStruct*) pCallData;

   TRY_CATCH_WRAPPER( pDisplayRes->gelScrollBarMoved( pCbStruct->value ) );
}


static void cbGelWindowExpose(
      Widget wid,
      XtPointer pClientData,
      XtPointer pCallData ) {
   
   guiDisplayDigest* pDisplay = 
      ( guiDisplayDigest* ) pClientData;

   TRY_CATCH_WRAPPER( pDisplay->displayGelWindow(); );

}


static void cbUserPushedDismiss( 
      Widget wid,
      XtPointer pClientData,
      XtPointer pCallData ) {

   guiDisplayDigest* pDisplay = 
      ( guiDisplayDigest* ) pClientData;

   TRY_CATCH_WRAPPER( delete pDisplay );
   

}


static void cbSortChanged(
      Widget wid,
      XtPointer pClientData,
      XtPointer pCallData ) {

   guiDisplayDigest* pDisplay = 
      ( guiDisplayDigest* ) pClientData;

   TRY_CATCH_WRAPPER( pDisplay->sortChanged() );

}




const int nGelWindowPosition = 50;


guiDisplayDigest :: guiDisplayDigest() :

   fPixelsPerGelUnit_( 0.3 ),
   nGelPositionAtTopOfGelWindow_( 0 ),
   bWindowVisible_( false ),
   pTempMarkedActualRestrictionFragment_( NULL ),
   pTempMarkedPredictedRestrictionFragment_( NULL ),
   pPermMarkedActualRestrictionFragment_( NULL ),
   pPermMarkedPredictedRestrictionFragment_( NULL ),
   bFlipVectorFromTheDefault_( false )
{
   

   aVisibleLinesForPredictedFragments_.soName_ = 
      "guiDisplayDigest::aVisibleLinesForPredictedFragments_";

   aVisibleLinesForActualFragments_.soName_ = 
      "guiDisplayDigest::aVisibleLinesForActualFragments_";

   aDigests_.soName_ = "guiDisplayDigest::aDigest_";

}


// why didn't I use the array aDigests_ which contains the 
// enzyme name and bases instead of passing aSelectedEnzymeNames and
// aSelectedEnzymeBases and then later having to search to find
// the corresponding element of aDigests_ ?

void guiDisplayDigest :: createWindow(
                     const RWTValOrderedVector<RWCString>& 
                             aSelectedEnzymeNames,
                     const RWTValOrderedVector<RWCString>& 
                             aSelectedEnzymeBases,
                     const bool bUseUserDefinedContigMap,
                     const RWCString soUserEnteredContigMap,
                     const int nStartUnpaddedConsPos,
                     const int nEndUnpaddedConsPos ) {

   aSelectedEnzymeNames_ = aSelectedEnzymeNames;
   aSelectedEnzymeBases_ = aSelectedEnzymeBases;

   bUseUserDefinedContigMap_ = bUseUserDefinedContigMap;
   soUserEnteredContigMap_ = soUserEnteredContigMap;
   nStartUnpaddedConsPos_ = nStartUnpaddedConsPos;
   nEndUnpaddedConsPos_ = nEndUnpaddedConsPos;


   setMinGelPosition();

   widPopupShell_ = XtVaCreatePopupShell( 
      "guiDisplayDigest",
      topLevelShellWidgetClass,
      GuiApp::pGetGuiApp()->widGetTopLevel(),
      XmNtitle, "Display Digests",
      XmNtransient, False,
      XmNdeleteResponse, XmDO_NOTHING,
      NULL );


   handleWindowManagerDelete2( widPopupShell_, cbUserPushedDismiss, this );


   // the immediate child of the application shell is a main window (so
   // there can be a menu bar)

   Widget widMainWin = XtVaCreateManagedWidget( "mainwin",
                                                xmMainWindowWidgetClass,
                                                widPopupShell_,
                                                XmNancestorSensitive, True,
                                                NULL );

   // put menu bar on the main window

   int nArgs = 0;
   Arg aArg[30];
   Widget widMenuBar = XmCreateMenuBar( widMainWin, "menubar", aArg, nArgs );
   XtManageChild( widMenuBar );

   // create help menu button

   nArgs = 0;
   Widget widHelpMenu = XmCreatePulldownMenu( widMenuBar,
                                              "Help",
                                              aArg,
                                              nArgs );

   nArgs = 0;
   XtSetArg( aArg[ nArgs ],
             XmNsubMenuId,
             widHelpMenu ); ++nArgs;

   Widget widHelpCascade = XmCreateCascadeButton( widMenuBar,
                                                  "Help",
                                                  aArg,
                                                  nArgs );

   XtManageChild( widHelpCascade );

   XtVaSetValues( widMenuBar,
                  XmNmenuHelpWidget, widHelpCascade,
                  NULL );

   // now add help menu item

   Widget widShowDocumentation =
      XtVaCreateManagedWidget( "Show Documentation for Restriction Digest",
                               xmPushButtonWidgetClass,
                               widHelpMenu,
                               NULL );

   XtAddCallback( widShowDocumentation,
                  XmNactivateCallback,
                  cbGuiShowDocumentationForRestrictionDigest,
                  this );
   
   widForm_ = XtVaCreateManagedWidget( 
      "form",
      xmFormWidgetClass,
      widMainWin,
      XmNancestorSensitive, True,
      NULL );

   // build from bottom up

   widDismiss_ = XtVaCreateManagedWidget(
      "Dismiss",
      xmPushButtonWidgetClass,
      widForm_,
      XmNbottomAttachment, XmATTACH_FORM,
      XmNbottomOffset, 10,
      XmNleftAttachment, XmATTACH_POSITION,
      XmNleftPosition, 45,
      XmNrightAttachment, XmATTACH_POSITION,
      XmNrightPosition, 55,
      NULL );

   XtAddCallback( widDismiss_,
                  XmNactivateCallback,
                  (XtCallbackProc ) cbUserPushedDismiss,
                  this );


   Widget widAttachWidgetAboveToThis = widDismiss_;


   // create the options menu.  This is done by creating
   // a pulldown menu, adding push buttons (menu items) to it,
   // and finally creating an options menu and linking it to
   // the pulldown menu.

   Widget widPullDownMenu = XmCreatePulldownMenu( 
      widForm_,
      "option_pulldown",
      NULL,
      0 );

   for( int nEnzyme = 0; nEnzyme < aSelectedEnzymeNames_.length(); 
        ++nEnzyme ) {

      Widget widPushButton = XtVaCreateManagedWidget(
         aSelectedEnzymeNames_[ nEnzyme ].data(), 
         xmPushButtonWidgetClass,
         widPullDownMenu,
         NULL );

      aEnzymeWidgets_.insert( widPushButton );
      
      XtAddCallback( widPushButton,
                     XmNactivateCallback,
                     (XtCallbackProc ) cbUserChangedEnzyme,
                     this );
   }


   XmString xms = XmStringCreateLocalized( "Select Enzyme:" );


   XtSetArg( aArg[ nArgs ], XmNlabelString, xms ); ++nArgs;
   XtSetArg( aArg[ nArgs ], XmNsubMenuId, widPullDownMenu ); ++nArgs;
   XtSetArg( aArg[ nArgs ], XmNleftAttachment, XmATTACH_FORM ); ++nArgs;
   XtSetArg( aArg[ nArgs ], XmNbottomAttachment, XmATTACH_WIDGET ); ++nArgs;
   XtSetArg( aArg[ nArgs ], XmNbottomWidget, widAttachWidgetAboveToThis ); ++nArgs;


   widEnzymeOptionsMenu_ = XmCreateOptionMenu( widForm_, "Select Enzyme:",
      aArg, nArgs );


   XtManageChild( widEnzymeOptionsMenu_ );




   widCurrentlyDisplayedEnzymeBases_ = XtVaCreateManagedWidget(
       "enzyme bases",
       xmTextFieldWidgetClass,
       widForm_,
       XmNtraversalOn, False,
       XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET,
       XmNbottomWidget, widEnzymeOptionsMenu_,
       XmNleftAttachment, XmATTACH_WIDGET,
       XmNleftWidget, widEnzymeOptionsMenu_,
       XmNleftOffset, 10,
       XmNcolumns, 8,
       XmNcursorPositionVisible, False,
       XmNeditable, False,
       NULL );


   widAttachWidgetAboveToThis = widEnzymeOptionsMenu_;


   Widget widContigMapLabel = XtVaCreateManagedWidget(
       "Contig Map:",
       xmLabelWidgetClass,
       widForm_,
       XmNleftAttachment, XmATTACH_WIDGET,
       XmNleftWidget, widCurrentlyDisplayedEnzymeBases_,
       XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET,
       XmNbottomWidget, widEnzymeOptionsMenu_,
       XmNleftOffset, 20,
       NULL );

   widContigMap_ = XtVaCreateManagedWidget(
       "contig map",
       xmTextFieldWidgetClass,
       widForm_,
       XmNtraversalOn, False,
       XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET,
       XmNbottomWidget, widEnzymeOptionsMenu_,
       XmNleftAttachment, XmATTACH_WIDGET,
       XmNleftWidget, widContigMapLabel,
       XmNleftOffset, 10,
       XmNrightAttachment, XmATTACH_FORM,
       XmNrightOffset, 10,
       XmNcursorPositionVisible, False,
       XmNeditable, False,
       XmNvalue, ConsEd::pGetAssembly()->soGetContigMap().data(),
       NULL );


   Widget widLabel1 = XtVaCreateManagedWidget( 
       "Go to:",
       xmLabelWidgetClass,
       widForm_, 
       XmNleftAttachment, XmATTACH_FORM,
       XmNbottomAttachment, XmATTACH_WIDGET,
       XmNbottomWidget, widAttachWidgetAboveToThis,
       NULL );


   widGotoLeft_ = XtVaCreateManagedWidget(
       "Left End",
       xmPushButtonWidgetClass,
       widForm_,
       XmNleftAttachment, XmATTACH_WIDGET,
       XmNleftWidget, widLabel1,
       XmNbottomAttachment, XmATTACH_WIDGET,
       XmNbottomWidget, widAttachWidgetAboveToThis,
       NULL );
   
   XtAddCallback( widGotoLeft_,
                  XmNactivateCallback,
                  cbUserPushedGotoLeftEnd,
                  this );

   widGotoRight_ = XtVaCreateManagedWidget(
       "Right End",
       xmPushButtonWidgetClass,
       widForm_,
       XmNleftAttachment, XmATTACH_WIDGET,
       XmNleftWidget, widGotoLeft_,
       XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET,
       XmNbottomWidget, widGotoLeft_,
       XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET,
       XmNtopWidget, widGotoLeft_,
       NULL );

   XtAddCallback( widGotoRight_,
                  XmNactivateCallback,
                  cbUserPushedGotoRightEnd,
                  this );

   widShowTextOutput_ = XtVaCreateManagedWidget( 
       "Text Output",
       xmPushButtonWidgetClass,
       widForm_,
       XmNleftAttachment, XmATTACH_WIDGET,
       XmNleftWidget, widGotoRight_,
       XmNleftOffset, 20,
       XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET,
       XmNbottomWidget, widGotoRight_,
       XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET,
       XmNtopWidget, widGotoRight_,
       NULL );

   XtAddCallback( widShowTextOutput_,
                  XmNactivateCallback,
                  cbUserPushedShowTextOutput,
                  this );



   widComplVector_ = XtVaCreateManagedWidget( 
       "compl vector",
       xmPushButtonWidgetClass,
       widForm_,
       XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET,
       XmNtopWidget, widShowTextOutput_,
       XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET,
       XmNbottomWidget, widShowTextOutput_,
       XmNleftAttachment, XmATTACH_WIDGET,
       XmNleftWidget, widShowTextOutput_,
       XmNleftOffset, 20,
       XmNtraversalOn, False,
       NULL );


   XtAddCallback( widComplVector_,
                  XmNactivateCallback,
                  cbComplVector,
                  this );








   widZoomIn_ = XtVaCreateManagedWidget(
       "Zoom In",
       xmPushButtonWidgetClass,
       widForm_,
       XmNleftAttachment, XmATTACH_WIDGET,
       XmNleftWidget, widComplVector_,
       XmNleftOffset, 20,
       XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET,
       XmNbottomWidget, widGotoLeft_,
       XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET,
       XmNtopWidget, widGotoLeft_,
       NULL );

   XtAddCallback( widZoomIn_,
                  XmNactivateCallback,
                  cbUserPushedZoomInOrOut,
                  this );

   widZoomOut_ = XtVaCreateManagedWidget(
       "Zoom Out",
       xmPushButtonWidgetClass,
       widForm_,
       XmNleftAttachment, XmATTACH_WIDGET,
       XmNleftWidget, widZoomIn_,
       XmNleftOffset, 10,
       XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET,
       XmNbottomWidget, widZoomIn_,
       XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET,
       XmNtopWidget, widZoomIn_,
       NULL );

   XtAddCallback( widZoomOut_,
                  XmNactivateCallback,
                  cbUserPushedZoomInOrOut,
                  this );



   widZoomOriginal_ = XtVaCreateManagedWidget(
       "Zoom Orig",
       xmPushButtonWidgetClass,
       widForm_,
       XmNleftAttachment, XmATTACH_WIDGET,
       XmNleftWidget, widZoomOut_,
       XmNleftOffset, 10,
       XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET,
       XmNbottomWidget, widZoomOut_,
       XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET,
       XmNtopWidget, widZoomOut_,
       NULL );

   XtAddCallback( widZoomOriginal_,
                  XmNactivateCallback,
                  cbUserPushedZoomInOrOut,
                  this );

   
   widShowProblems_ = XtVaCreateManagedWidget(
        "Show Problems",
        xmPushButtonWidgetClass,
        widForm_,
        XmNleftAttachment, XmATTACH_WIDGET,
        XmNleftWidget, widZoomOriginal_,
        XmNleftOffset, 10,
        XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET,
        XmNbottomWidget, widZoomOriginal_,
        XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET,
        XmNtopWidget, widZoomOriginal_,
        NULL );

   XtAddCallback( widShowProblems_,
                  XmNactivateCallback,
                  cbUserPushedShowProblems,
                  this );


   widAttachWidgetAboveToThis = widGotoLeft_;



   // Radio box


   Widget widLabel2 = XtVaCreateManagedWidget(
       "Sort by:",
       xmLabelWidgetClass,
       widForm_,
       XmNleftAttachment, XmATTACH_FORM,
       XmNbottomAttachment, XmATTACH_WIDGET,
       XmNbottomWidget, widAttachWidgetAboveToThis,
       NULL );


   Dimension dimWidth;
   XtVaGetValues( widLabel2, XmNwidth, &dimWidth, NULL );
   Dimension dimSpacing;
   XtVaGetValues( widForm_, XmNhorizontalSpacing, &dimSpacing, NULL );



   Widget widSortByRadioBox = XmCreateRadioBox(
       widForm_,
       "sortByRadio",
       NULL,
       0 );

   XtVaSetValues( widSortByRadioBox,
                  XmNtraversalOn, True,
                  XmNbottomAttachment, XmATTACH_WIDGET,
                  XmNbottomWidget, widAttachWidgetAboveToThis,
                  XmNleftAttachment, XmATTACH_FORM,
                  XmNleftOffset, dimWidth + dimSpacing,
                  XmNorientation, XmHORIZONTAL,
                  NULL );
                  
   Widget widSortBySize = XtVaCreateManagedWidget(
       "size",
       xmToggleButtonWidgetClass,
       widSortByRadioBox,
       XmNset, True, // default
       NULL );

   widSortByPosition_ = XtVaCreateManagedWidget(
       "position",
       xmToggleButtonWidgetClass,
       widSortByRadioBox,
       XmNset, False,
       NULL );


   XtAddCallback( widSortByPosition_,
                  XmNvalueChangedCallback,
                  cbSortChanged,
                  this );

   XtManageChild( widSortByRadioBox );


   XtVaSetValues( widLabel2, 
                  XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET,
                  XmNtopWidget, widSortByRadioBox,
                  XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET,
                  XmNbottomWidget, widSortByRadioBox,
                  NULL );
   

   widAttachWidgetAboveToThis = widSortByRadioBox;



   // end Radio Box


   

   nArgs = 0;
   XtSetArg( aArg[nArgs], XmNtopAttachment, XmATTACH_FORM ); nArgs++;
   XtSetArg( aArg[nArgs], XmNleftAttachment, XmATTACH_FORM ); nArgs++;
   XtSetArg( aArg[nArgs], XmNbottomAttachment, XmATTACH_WIDGET ); nArgs++;
   XtSetArg( aArg[nArgs], XmNbottomWidget, widAttachWidgetAboveToThis ); ++nArgs;
   XtSetArg( aArg[nArgs], XmNbottomOffset, 20 ); ++nArgs;
   XtSetArg( aArg[nArgs], XmNrightAttachment, XmATTACH_POSITION ); nArgs++;
   XtSetArg( aArg[nArgs], XmNrightPosition, nGelWindowPosition ); nArgs++;
   XtSetArg(aArg[nArgs], XmNscrollBarDisplayPolicy, XmAS_NEEDED); nArgs++;
   //   XtSetArg(aArg[nArgs], XmNscrollingPolicy, XmAUTOMATIC); nArgs++;
   XtSetArg(aArg[nArgs], XmNlistVisibleItemCount, 20 ); nArgs++;
   XtSetArg(aArg[nArgs], XmNcolumns, 100 ); nArgs++;
   XtSetArg(aArg[nArgs], XmNtraversalOn, False); nArgs++;
   XtSetArg(aArg[nArgs], XmNselectionPolicy, XmSINGLE_SELECT ); ++nArgs;
   XtSetArg(aArg[nArgs], XmNmarginHeight, 0 ); ++nArgs;
   XtSetArg(aArg[nArgs], XmNmarginWidth, 0 ); ++nArgs;
   //   XtSetArg(aArg[nArgs], XmNtextColumns, (short) 20 ); ++nArgs;
   XtSetArg( aArg[ nArgs ], XmNlistVisibleItemCount, pCP->nRestrictionDigestInitialWindowSizeInTextRows_ ); ++nArgs;



   widTextSelectionBox_ = XmCreateSelectionBox( widForm_,
                                            "text",
                                            aArg,
                                            nArgs );

   XtManageChild( widTextSelectionBox_ );

   XtUnmanageChild( XmSelectionBoxGetChild( widTextSelectionBox_, XmDIALOG_TEXT ));
   XtUnmanageChild( XmSelectionBoxGetChild( widTextSelectionBox_, XmDIALOG_SELECTION_LABEL));
   XtUnmanageChild( XmSelectionBoxGetChild( widTextSelectionBox_, XmDIALOG_OK_BUTTON ));
   XtUnmanageChild( XmSelectionBoxGetChild( widTextSelectionBox_, XmDIALOG_CANCEL_BUTTON ));
   XtUnmanageChild( XmSelectionBoxGetChild( widTextSelectionBox_, XmDIALOG_HELP_BUTTON ));
   // commented out because it was already null
   //   XtUnmanageChild( XmSelectionBoxGetChild( widTextSelectionBox_, XmDIALOG_WORK_AREA ));
   XtUnmanageChild( XmSelectionBoxGetChild( widTextSelectionBox_, XmDIALOG_SEPARATOR ));
   XtUnmanageChild( XmSelectionBoxGetChild( widTextSelectionBox_, XmDIALOG_LIST_LABEL ));
                    
   widTextList_ = XmSelectionBoxGetChild( widTextSelectionBox_, 
                                          XmDIALOG_LIST );


   nArgs = 0;
   XtSetArg( aArg[nArgs], XmNtopAttachment, XmATTACH_FORM ); nArgs++;
   XtSetArg( aArg[nArgs], XmNrightAttachment, XmATTACH_FORM ); nArgs++;
   XtSetArg( aArg[nArgs], XmNbottomAttachment, XmATTACH_WIDGET ); nArgs++;
   XtSetArg( aArg[nArgs], XmNbottomWidget, widAttachWidgetAboveToThis ); ++nArgs;
   XtSetArg( aArg[nArgs], XmNbottomOffset, 20 ); ++nArgs;
   XtSetArg( aArg[nArgs], XmNleftAttachment, XmATTACH_POSITION ); nArgs++;
   XtSetArg( aArg[nArgs], XmNleftPosition, nGelWindowPosition ); nArgs++;
   widGelScrollingWindow_ = XmCreateScrolledWindow( widForm_,
                                            "text",
                                            aArg,
                                            nArgs );

   XtManageChild( widGelScrollingWindow_ );
   
   nArgs = 0;
   XtSetArg( aArg[nArgs], XmNorientation, XmVERTICAL ); nArgs++;
   widGelScrollBar_ = XmCreateScrollBar( widGelScrollingWindow_,
                                         "scrollbar",
                                         aArg,
                                         nArgs );

   XtManageChild( widGelScrollBar_ );



   XtAddCallback( widGelScrollBar_,
                  XmNvalueChangedCallback,
                  cbGelScrollBar,
                  this );

   XtAddCallback( widGelScrollBar_,
                  XmNdragCallback,
                  cbGelScrollBar,
                  this );


   const int nNumbersInScale = 6;
   
   nArgs = 0;
   XtSetArg( aArg[nArgs], XmNwidth, 
             nGetLeftEndScaleNumber2() + 
             nNumbersInScale * GuiApp::nGetFontWidth() ); nArgs++;

   widGelWindow_ = XmCreateDrawingArea( widGelScrollingWindow_,
                                        "gel",
                                        aArg,
                                        nArgs );
   XtManageChild( widGelWindow_ );

   XtAddCallback( widGelWindow_,
                  XmNexposeCallback,
                  cbGelWindowExpose,
                  this );

   XtAddEventHandler( widGelWindow_,
                      PointerMotionMask,
                      False,
                      (XtEventHandler) pointerMotionEventHandler,
                      this );

   XtAddCallback( widGelWindow_,
                  XmNinputCallback,
                  (XtCallbackProc ) cbInput,
                  this );
             
   XtPopup( widPopupShell_, XtGrabNone );

   bWindowVisible_ = true;

   // cannot update displays since pCurrentlyDisplayedDigest_ // has
   // not yet been set.  In fact, none of the digestForOneEnzyme are
   // as yet created.
}





void guiDisplayDigest :: updateDisplays() {
   waitUntilDialogIsVisible( widPopupShell_ );
   updateTextDisplay();
}


void guiDisplayDigest :: updateTextDisplay() {

   arrayOfRestrictionFragments* pPredictedFragmentsArray =
      pGetPredictedFragmentsArray();


   
   XmStringTable ppXtString = (XmStringTable) XtMalloc( 
      pPredictedFragmentsArray->length() * sizeof( XmString ) );

   int nPredictedFragment;
   for( nPredictedFragment = 0; nPredictedFragment < 
        pPredictedFragmentsArray->length();
        ++nPredictedFragment ) {

      restrictionFragment* pResFrag = 
         (*pPredictedFragmentsArray)[ nPredictedFragment ];

      RWCString soStringToDisplay( (size_t) 200 );
      // types of predicted fragments:
      //    entirely within contig
      //    entirely within vector
      //    partly within contig and unknown other end
      //    partly within vector and unknown other end
      //    partly within contig and partly within vector

      pResFrag->getDescriptionLine( soStringToDisplay );
      

      ppXtString[ nPredictedFragment ] = XmStringCreateLocalized(
          soStringToDisplay.data() );                            
   } //  for( int nPredictedFragment = 0; nPredictedFragment < ...

   XtVaSetValues( widTextList_, 
                  XmNitems, ppXtString,
                  XmNitemCount, pPredictedFragmentsArray->length(),
                  NULL );

   for( nPredictedFragment = 0; 
        nPredictedFragment < pPredictedFragmentsArray->length();
        ++nPredictedFragment ) {
      XmStringFree( ppXtString[ nPredictedFragment ] );
   }

   XtFree( (char*) ppXtString );

}

const int nNumberOfVectorPoints = 3;
XPoint xp[ nNumberOfVectorPoints ];

const int nVectorVHalfWidth = 3;
const int nVectorVHeight = 4;

const char szG[] = "g";



void guiDisplayDigest :: drawLineForPredictedFragment(
                           visibleLineForRestrictionFragments* pVis ) {
   

   XDrawLine( XtDisplay( widGelWindow_ ),
              XtWindow( widGelWindow_ ),
              pVis->pGetGuiColorText()->gcGet(),
              nGetPredictedFragmentLeftEndOnGel(),
              pVis->nMiddlePixel_,
              nGetPredictedFragmentRightEndOnGel(),
              pVis->nMiddlePixel_ );


   if ( pVis->bAllFragmentsAreVector() ) {
      
      int nMiddle = ( nGetPredictedFragmentLeftEndOnGel() +
                      nGetPredictedFragmentRightEndOnGel() ) / 2;


      xp[0].x = nMiddle - nVectorVHalfWidth;
      xp[0].y = pVis->nMiddlePixel_ - nVectorVHeight;
      xp[1].x = nMiddle;
      xp[1].y = pVis->nMiddlePixel_;
      xp[2].x = nMiddle + nVectorVHalfWidth;
      xp[2].y = pVis->nMiddlePixel_ - nVectorVHeight;


      XDrawLines( XtDisplay( widGelWindow_ ),
                  XtWindow( widGelWindow_ ),
                  pVis->pGetGuiColorText()->gcGet(),
                  xp,
                  nNumberOfVectorPoints,
                  CoordModeOrigin );
   }

   if ( pVis->bSomeFragmentIsGapSpanning() ) {
      
      // I'm putting the char a little to the left of middle
      // so it won't overlap the v for vector fragments

      int nMiddleLeft = nGetPredictedFragmentLeftEndOnGel() +
         0.33333 * ( nGetPredictedFragmentRightEndOnGel() -
                     nGetPredictedFragmentLeftEndOnGel() );

      XDrawString(
               XtDisplay( widGelWindow_ ),
               XtWindow( widGelWindow_ ),
               pVis->pGetGuiColorText()->gcGet(),
               nMiddleLeft,
               pVis->nMiddlePixel_,
               szG,
               1 );
   }



}



void guiDisplayDigest :: drawLineForActualFragment(
                           visibleLineForRestrictionFragments* pVis ) {


   XDrawLine( XtDisplay( widGelWindow_ ),
              XtWindow( widGelWindow_ ),
              pVis->pGetGuiColorText()->gcGet(),
              nGetActualFragmentLeftEndOnGel(),
              pVis->nMiddlePixel_,
              nGetActualFragmentRightEndOnGel(),
              pVis->nMiddlePixel_ );

}
  



   
void guiDisplayDigest :: gelScrollBarMoved( const int nNewScrollBarPosition ) {

   nGelPositionAtTopOfGelWindow_ = nNewScrollBarPosition;

   displayGelWindow();
}


void guiDisplayDigest :: clearGelWindow() {

   XClearArea( 
              XtDisplay( widGelWindow_ ), 
              XtWindow( widGelWindow_ ),
              0, 
              0, 
              0,
              0,
              false
              );

}


guiDisplayDigest :: ~guiDisplayDigest() {

   if ( bWindowVisible_ ) {
      XtRemoveCallback( widGelWindow_,
                        XmNexposeCallback,
                        cbGelWindowExpose,
                        this );

      XtRemoveEventHandler( widGelWindow_,
                            PointerMotionMask,
                            False,
                            (XtEventHandler) pointerMotionEventHandler,
                            this );

      XtPopdown( widPopupShell_ );
      XtDestroyWidget( widPopupShell_ );
   }

   aDigests_.clearAndDestroy();

   int nIndex;
   if ( ( nIndex = ConsEd::pGetConsEd()->aGuiDisplayDigest_.index( this ) )
        != RW_NPOS ) {
      ConsEd::pGetConsEd()->aGuiDisplayDigest_.removeAt( nIndex );
   }
}


void guiDisplayDigest :: changeCurrentlyDisplayedDigest( 
                                digestForOneEnzyme* pNewDigest ) {

   pCurrentlyDisplayedDigest_ = pNewDigest;

   // nothing should be marked any longer 
   pTempMarkedActualRestrictionFragment_ = NULL;
   pTempMarkedPredictedRestrictionFragment_ = NULL;
   pPermMarkedActualRestrictionFragment_ = NULL;
   pPermMarkedPredictedRestrictionFragment_ = NULL;

   XtVaSetValues( widCurrentlyDisplayedEnzymeBases_,
                  XmNvalue,
                  pCurrentlyDisplayedDigest_->soEnzymeBases_.data(),
                  NULL );

   calculateInitialZoomFactor();
   
   setScrollBar();

   nGelPositionAtTopOfGelWindow_ = nGetMinGelPosition();
   XtVaSetValues( widGelScrollBar_, 
                  XmNvalue, nGelPositionAtTopOfGelWindow_,
                  NULL );

   updateTextDisplay();
   displayGelWindow();
   tellAssemblyView();
}


void guiDisplayDigest :: setScrollBar() {

   int nIncrementInGelUnits = 
      nGelScrollBarIncrementInPixels / fPixelsPerGelUnit_;

   
   int nGelUnitsDisplayedAtOnce = nGetGelWindowPixelHeight() / 
      fPixelsPerGelUnit_;

   XtVaSetValues( widGelScrollBar_, 
                  XmNmaximum, nGetMaxGelPosition(),
                  XmNminimum, nGetMinGelPosition(),
                  XmNincrement, nIncrementInGelUnits,
                  XmNsliderSize, nGelUnitsDisplayedAtOnce - 1,
                  XmNpageIncrement, nGelUnitsDisplayedAtOnce,
                  NULL );
}


int guiDisplayDigest :: nGetGelWindowPixelHeight() {

   Dimension nHeight;
   XtVaGetValues( widGelWindow_,
                  XmNheight, &nHeight,
                  NULL );

   return( nHeight );
}



void guiDisplayDigest :: gotoEnd( const int nWhichEnd ) {
   
   // first get which item in the list the user selected

   int nRestrictionFragmentIndex;
   int* pPositionList;
   int nNumberOfSelectedItems;
   if ( XmListGetSelectedPos( widTextList_, 
                              &pPositionList,
                              &nNumberOfSelectedItems ) ) {
      assert( nNumberOfSelectedItems == 1 );
      nRestrictionFragmentIndex = pPositionList[0] - 1; // motif index 
      // starts at 1
   }
   else {
      popupErrorMessage2( widPopupShell_, "you must first select a fragment" );
      return;
   }


   arrayOfRestrictionFragments* pPredictedFragmentArray =
      pGetPredictedFragmentsArray();


   restrictionFragment* pResFrag = 
      (*pPredictedFragmentArray)[ nRestrictionFragmentIndex ];

   Contig* pContig;
   int nUnpadded;
   

   if ( nWhichEnd == nLeftGap ) {
      if ( pResFrag->fragLeft_ != restrictionFragment::IN_CONTIG ) {
         popupErrorMessage2( widPopupShell_, "The left end of the selected fragment is not in a contig.\nYou can only select go to a contig position." );
         return;
      }

      pContig = pResFrag->pLeftContig_;
      nUnpadded = pResFrag->nUnpaddedLeft_;
   }
   else if ( nWhichEnd == nRightGap ) {
      if ( pResFrag->fragRight_ != restrictionFragment::IN_CONTIG ) {
         popupErrorMessage2( widPopupShell_, "The right end of the selected fragment is not in a contig.\nYou can only select go to a contig position." );
         return;
      }

      pContig = pResFrag->pRightContig_;
      nUnpadded = pResFrag->nUnpaddedRight_;
   }
   else 
      assert( false );


   int nConsPos = pContig->nPaddedIndexFast( nUnpadded );

   ContigWin* pContigWin = 
      ConsEd::pGetConsEd()->pScrollExistingContigWinOrMakeNewContigWin( 
                                pContig,
                                nConsPos );

   pContigWin->moveCursorToConsPos( nConsPos );

   // raise the window
   pContigWin->raiseWindow();
}




   
const int nAsciiSize = 256;


void guiDisplayDigest :: doSearch() {


   for( int nEnzyme = 0; nEnzyme < aSelectedEnzymeBases_.length(); 
        ++nEnzyme ) {

      // find corresponding digestforOneEnzyme

      digestForOneEnzyme* pDigest = NULL;
      for( int nDigest = 0; nDigest < aDigests_.length(); ++nDigest ) {
         if ( aDigests_[ nDigest ]->soEnzymeName_ == 
              aSelectedEnzymeNames_[ nEnzyme ] ) {
            pDigest = aDigests_[ nDigest ];
            break;
         }
      }
      
      assert( pDigest );
      assert( pDigest->soEnzymeBases_ == aSelectedEnzymeBases_[ nEnzyme ] );

      // work out a match table that includes any ambiguity codes

      RWTPtrOrderedVector<unsigned char> aIndexedByEnzymeBases(
                                           pDigest->soEnzymeBases_.length() );

      aIndexedByEnzymeBases.soName_ = "aIndexedByEnzymeBases";
      aIndexedByEnzymeBases.soName_ += " ";
      aIndexedByEnzymeBases.soName_ += aSelectedEnzymeNames_[ nEnzyme ];

      for( int nEnzymeBase = 0; nEnzymeBase < pDigest->soEnzymeBases_.length();
           ++nEnzymeBase ) {

         char cBase = pDigest->soEnzymeBases_[ nEnzymeBase ];
         
         // a 256-byte lookup table that translates ambiguity codes
         // to yes/no depending a match to acgt
         unsigned char* pUC = (unsigned char*) malloc( sizeof(unsigned char) *
                                                       nAsciiSize );

         unsigned char ucDefaultValue;
         if ( cBase == 'n' ) {
            ucDefaultValue = 1;
            for( int n = 0; n < nAsciiSize; ++n )
               pUC[n] = 1;
         }
         else {


            for( int n = 0; n < nAsciiSize; ++n )
               pUC[n] = 0;
   
            if ( cBase == 'a' || cBase == 'c' || cBase == 'g' || cBase == 't' )
               pUC[ cBase ] = 1;
            else if ( cBase == 'r' ) {
               pUC[ 'a' ] = 1;
               pUC[ 'g' ] = 1;
            }
            else if ( cBase == 'y' ) {
               pUC[ 'c' ] = 1;
               pUC[ 't' ] = 1;
            }
            else if ( cBase == 'm' ) {
               pUC[ 'a' ] = 1;
               pUC[ 'c' ] = 1;
            }
            else if ( cBase == 'k' ) {
               pUC[ 'g' ] = 1;
               pUC[ 't' ] = 1;
            }
            else if ( cBase == 's' ) {
               pUC[ 'c' ] = 1;
               pUC[ 'g' ] = 1;
            }
            else if ( cBase == 'w' ) {
               pUC[ 'a' ] = 1;
               pUC[ 't' ] = 1;
            }
            else if ( cBase == 'd' ) {
               pUC[ 'a' ] = 1;
               pUC[ 'g' ] = 1;
               pUC[ 't' ] = 1;
            }
            else if ( cBase == 'h' ) {
               pUC[ 'a' ] = 1;
               pUC[ 'c' ] = 1;
               pUC[ 't' ] = 1;
            }
            else if ( cBase == 'b' ) {
               pUC[ 'c' ] = 1;
               pUC[ 'g' ] = 1;
               pUC[ 't' ] = 1;
            }
            else if ( cBase == 'v' ) {
               pUC[ 'a' ] = 1;
               pUC[ 'c' ] = 1;
               pUC[ 'g' ] = 1;
            }
         }
            
         aIndexedByEnzymeBases.insert( pUC );
      } //   for( int nEnzymeBase = 0; ...



      pDigest->aPredictedResFragsBySize_.clear();


      int nPositionOrderOfFragment = 0;

      if ( bUseUserDefinedContigMap_ ) {

         RWTPtrOrderedVector<clScaffold> aScaffoldArray;
         RWCString soErrorMessage;

         ConsEd::pGetAssembly()->createScaffoldsFromUserContigMap( 
             soUserEnteredContigMap_,
             nStartUnpaddedConsPos_,
             nEndUnpaddedConsPos_,
             &aScaffoldArray,
             soErrorMessage );


         for( int nScaffold = 0; nScaffold < aScaffoldArray.length();
              ++nScaffold ) {

            clScaffold* pScaffold = aScaffoldArray[ nScaffold ];

            ConsEd::pGetAssembly()->getRestrictionFragmentsForOneScaffold(
                       aIndexedByEnzymeBases,
                       pDigest->aPredictedRestrictionFragmentsNotEndingAtVectorInsertJunction_,
                       pDigest->aPredictedInsertRestrictionFragmentsEndingAtVectorInsertJunction_,
                       pScaffold,
                       nPositionOrderOfFragment );

            cerr << "# of predicted fragments = " <<
               pDigest->aPredictedRestrictionFragmentsNotEndingAtVectorInsertJunction_.length() <<
               " and " << 
               pDigest->aPredictedInsertRestrictionFragmentsEndingAtVectorInsertJunction_.length() << endl;
         }

         aScaffoldArray.clearAndDestroy();
      } //       if ( bJustPartNotWholeCloneDigest_ ) {
      else {

         for( int nScaffold = 0; 
           nScaffold < ConsEd::pGetAssembly()->aHeadsOfScaffoldsOfContigs_.length(); 
           ++nScaffold ) {

            clScaffold* pScaffold = ConsEd::pGetAssembly()->pCreateScaffold( nScaffold );

            ConsEd::pGetAssembly()->getRestrictionFragmentsForOneScaffold( 
                       aIndexedByEnzymeBases, 
                       pDigest->aPredictedRestrictionFragmentsNotEndingAtVectorInsertJunction_,
                       pDigest->aPredictedInsertRestrictionFragmentsEndingAtVectorInsertJunction_,
                       pScaffold, 
                       nPositionOrderOfFragment );

            delete pScaffold;
         }
      }

      getVectorFragments( 
         aIndexedByEnzymeBases,
         pDigest->aPredictedRestrictionFragmentsNotEndingAtVectorInsertJunction_,
         pDigest->aPredictedVectorRestrictionFragmentsEndingAtVectorInsertJunction_,
         nPositionOrderOfFragment,
         pDigest->bNoCutSitesInVector_ );

      if ( pDigest->bNoCutSitesInVector_ ) {
         cerr << "enzyme " << pDigest->soEnzymeName_ << 
            " does not cut vector" << endl;
      }


//       for( int nFrag = 0; 
//            nFrag < pDigest->aPredictedVectorRestrictionFragmentsEndingAtVectorInsertJunction_.length(); 
//            ++nFrag ) {
//          restrictionFragment* pRes = 
//             pDigest->aPredictedVectorRestrictionFragmentsEndingAtVectorInsertJunction_[ nFrag ];

//          RWCString soMessage;
//          pRes->getDescriptionLine( soMessage );
//          cerr << "partial vector fragment: " << soMessage <<  " for enzyme: "
//               << pDigest->soEnzymeName_ << endl;
//       }




      // now we need to put together the restriction fragments that end
      // at the vector-insert junction

      pDigest->processingAfterFindingAllPartialFragments( 
                          bFlipVectorFromTheDefault_ );

   } // for( int nEnzyme = 0 ...

   // I put this here instead of in createWindow since there is no
   // point in assemblyView trying to display anything until here.
   // This needs to come before changeCurrentlyDisplayedDigest since
   // the latter calls tellAssemblyView which calls drawEverything
   // which will only draw cut sites if
   // ConsEd::pGetConsEd()->pGuiDisplayDigest_ is set.

   ConsEd::pGetConsEd()->aGuiDisplayDigest_.insert( this );

   // start display with the 0th enzyme

   changeCurrentlyDisplayedDigest( aDigests_[0] );


   //    updateDisplays(); don't think I need this here...
}
   


void guiDisplayDigest :: getVectorFragments( 
        RWTPtrOrderedVector<unsigned char>& aIndexedByEnzymeBases,
        RWTPtrOrderedVector<restrictionFragment>& aRestrictionFragments,
        RWTPtrOrderedVector<restrictionFragment>& 
            aRestrictionFragmentsEndingAtAVectorInsertJunction,
        int& nPositionOrderOfFragment,
        bool& bNoCutSitesInVector ) {

   
   
   RWTValOrderedVector<int> aCutSites;

   for( int nVectorBase = 0; nVectorBase < 
           ( (int) soVectorSequence_.length() -
             (int) aIndexedByEnzymeBases.length() + 1 );
        ++nVectorBase ) {
      
      bool bMatch = true;
      for( int nEnzymeBase = 0; nEnzymeBase < aIndexedByEnzymeBases.length();
           ++nEnzymeBase ) {

         char cVectorBase = soVectorSequence_[ nVectorBase + nEnzymeBase ];

         if ( ! ( aIndexedByEnzymeBases[ nEnzymeBase ] )[ cVectorBase ] ) {
            bMatch = false;
            break;
         }
      }

      if ( bMatch ) {
         // found a perfect match

         aCutSites.insert( nVectorBase );
      }
   }

   if ( aCutSites.length() == 0 )
      bNoCutSitesInVector = true;
   else
      bNoCutSitesInVector = false;


   for( int nCutSite = 0; nCutSite < aCutSites.length(); ++nCutSite ) {

      restrictionFragment* pRes = new restrictionFragment( 
          restrictionFragment::PREDICTED_FRAGMENT );

      pRes->bVectorFragment_ = true;

      pRes->nPositionOrder_ = nPositionOrderOfFragment;
      ++nPositionOrderOfFragment;
      
      if ( nCutSite == 0 ) {
         pRes->fragLeft_ = restrictionFragment::AT_VECTOR_INSERT_JUNCTION;
         pRes->nUnpaddedLeft_ = 1;
         pRes->nSize_ = aCutSites[ nCutSite ];
         aRestrictionFragmentsEndingAtAVectorInsertJunction.insert( pRes );

      }
      else {
         pRes->fragLeft_ = restrictionFragment::IN_VECTOR;
         pRes->nUnpaddedLeft_ = aCutSites[ nCutSite - 1];
         pRes->nSize_ = aCutSites[ nCutSite ] - aCutSites[ nCutSite - 1];
         aRestrictionFragments.insert( pRes );
      }

      pRes->fragRight_ = restrictionFragment::IN_VECTOR;
      pRes->nUnpaddedRight_ = aCutSites[ nCutSite ];
   }

   // deal with last fragment, keeping in mind that there may be no
   // cut sites at all in the vector

   restrictionFragment* pRes = new restrictionFragment( 
                      restrictionFragment::PREDICTED_FRAGMENT );
   pRes->bVectorFragment_ = true;
   aRestrictionFragmentsEndingAtAVectorInsertJunction.insert( pRes );

   pRes->nPositionOrder_ = nPositionOrderOfFragment;
   ++nPositionOrderOfFragment;

   if ( aCutSites.length() == 0 ) {
      pRes->fragLeft_ = restrictionFragment::AT_VECTOR_INSERT_JUNCTION;
      pRes->nUnpaddedLeft_ = 1;
      pRes->nSize_ = soVectorSequence_.length();
   }
   else {
      pRes->fragLeft_ = restrictionFragment::IN_VECTOR;
      pRes->nUnpaddedLeft_ = aCutSites[ aCutSites.length() - 1 ];
      pRes->nSize_ = soVectorSequence_.length() -
         aCutSites[ aCutSites.length() - 1 ];
   }

   
   pRes->fragRight_ = restrictionFragment::AT_VECTOR_INSERT_JUNCTION;
   pRes->nUnpaddedRight_ = soVectorSequence_.length() - 1;

}


void guiDisplayDigest :: userChangedEnzyme( Widget wid ) {

   // find which enzyme the user changed to:

   int nIndex = aEnzymeWidgets_.index( wid );

   assert( nIndex != RW_NPOS );

   changeCurrentlyDisplayedDigest( aDigests_[ nIndex ] );
}



void guiDisplayDigest :: displayGelWindow() {

   // handle case in which the window just came up and the fragments
   // have not yet been created

   if ( !pCurrentlyDisplayedDigest_ ) return;

   clearGelWindow();
   drawTitles();
   
   // store target positions for determining where the cursor is
   aVisibleLinesForPredictedFragments_.clear();

   int nMinGelPosition = nGetGelPositionAtTopOfGelWindow();
   int nMaxGelPosition = nGetGelPositionAtBottomOfGelWindow();
   int nLastPixelY = -666;

   for( int nPredicted = 0; 
        nPredicted < 
        pCurrentlyDisplayedDigest_->aPredictedResFragsBySize_.length();
        ++nPredicted ) {
      restrictionFragment* pFrag = 
         pCurrentlyDisplayedDigest_->aPredictedResFragsBySize_[ nPredicted ];

      if ( pFrag->fPositionOnGel_ < nMinGelPosition )
         continue;

      if ( pFrag->fPositionOnGel_ > nMaxGelPosition )
         break;

      // store target positions for determining where the cursor is
      int nPixelY = nGetPixelYFromGelPosition( pFrag->fPositionOnGel_ );
      if ( nLastPixelY != nPixelY ) {
         nLastPixelY = nPixelY;
         aVisibleLinesForPredictedFragments_.insert( 
               visibleLineForRestrictionFragments( nPixelY,
                                                   pFrag,
                                                   restrictionFragment::PREDICTED_FRAGMENT )
                                                    );
      }
      else {
         visibleLineForRestrictionFragments& vis =
            aVisibleLinesForPredictedFragments_[ 
               aVisibleLinesForPredictedFragments_.length() - 1 ];
         vis.aFragmentsAtSamePixel_.insert( pFrag );
      }
   }



   // store target positions for determining where the cursor is
   aVisibleLinesForActualFragments_.clear();
   nLastPixelY = -666;

   for( int nActual = 0;
        nActual < 
        pCurrentlyDisplayedDigest_-> aActualRestrictionFragments_.length();
        ++nActual ) {
      restrictionFragment* pActualFrag =
         pCurrentlyDisplayedDigest_->aActualRestrictionFragments_[ nActual ];


      if ( pActualFrag->fPositionOnGel_ < nMinGelPosition )
         continue;

      if ( pActualFrag->fPositionOnGel_ > nMaxGelPosition )
         break;

      // store targets positions for determining where the cursor is
      int nPixelY = nGetPixelYFromGelPosition( pActualFrag->fPositionOnGel_ );
      if ( nLastPixelY != nPixelY ) {
         nLastPixelY = nPixelY;
         aVisibleLinesForActualFragments_.insert(
               visibleLineForRestrictionFragments( nPixelY,
                                                   pActualFrag,
                                                   restrictionFragment::ACTUAL_FRAGMENT )
                                                    );
      }
      else {
         visibleLineForRestrictionFragments& vis =
            aVisibleLinesForActualFragments_[
               aVisibleLinesForActualFragments_.length() - 1 ];
         
         vis.aFragmentsAtSamePixel_.insert( pActualFrag );
      }
   }


   expandVisibleLines();



   int nVisible;
   for( nVisible = 0; 
        nVisible < aVisibleLinesForPredictedFragments_.length();
        ++nVisible ) {

      drawLineForPredictedFragment( &( aVisibleLinesForPredictedFragments_[ nVisible ] ) );
   }


   for( nVisible = 0;
        nVisible < aVisibleLinesForActualFragments_.length();
        ++nVisible ) {
      
      drawLineForActualFragment( &( aVisibleLinesForActualFragments_[ nVisible ] ) );
   }



   drawGelWindowScale();

   drawTempVisibleLines();
   drawPermVisibleLines();

}


void guiDisplayDigest :: userPushedZoomInOrOut( Widget wid ) {



   if ( wid == widZoomIn_ ) {
      // if zooming in, try to keep whatever is in the middle, still in
      // the middle


      int nGelPositionInMiddle = ( nGelPositionAtTopOfGelWindow_ +
                                nGetGelPositionAtBottomOfGelWindow() ) / 2;

      fPixelsPerGelUnit_ *= pCP->dRestrictionDigestZoomFactor_;

      int nPixelOfMiddle = nGetGelWindowPixelHeight() / 2;

      nGelPositionAtTopOfGelWindow_ = nGelPositionInMiddle -
         nPixelOfMiddle / fPixelsPerGelUnit_;

      if ( nGelPositionAtTopOfGelWindow_ < 0 ) {
         RWCString soError = "nGelPositionAtTopOfGelWindow_ = " +
            RWCString( (long) nGelPositionAtTopOfGelWindow_ ) +
               " nGelPositionInMiddle = " + 
            RWCString( (long) nGelPositionInMiddle );
         THROW_ERROR2( soError );
      }

      // if nGelPositionAtTopOfGelWindow_ is changed, then
      // XmNvalue of the scrollbar must be changed also.  Otherwise,
      // the next time the user moves the scrollbar, it will move
      // from its previous position and give a value that is 
      // way off from what is currently being displayed.

      XtVaSetValues( widGelScrollBar_, 
                     XmNvalue, nGelPositionAtTopOfGelWindow_,
                     NULL );



   }    
   else if ( wid == widZoomOut_ ) {
      fPixelsPerGelUnit_ /= pCP->dRestrictionDigestZoomFactor_;
   }
   else if ( wid == widZoomOriginal_ ) {
      calculateInitialZoomFactor();
   }
   else
      assert( false );

   adjustScrollBarWhenZoom();

   displayGelWindow();
}

void guiDisplayDigest :: adjustScrollBarWhenZoom() {

   int nGelUnitsPerScrollBarClick = (float) nGelScrollBarIncrementInPixels /
      fPixelsPerGelUnit_;

   int nGelUnitsDisplayedAtOnce = nGetGelWindowPixelHeight() /
      fPixelsPerGelUnit_;

   
   XtVaSetValues( widGelScrollBar_, 
                  XmNincrement, nGelUnitsPerScrollBarClick,
                  XmNsliderSize, nGelUnitsDisplayedAtOnce - 1,
                  XmNpageIncrement, nGelUnitsDisplayedAtOnce,
                  NULL );
}




void guiDisplayDigest :: drawGelWindowScale() {

   drawScaleLine();


   // now draw the scale ticks for sizes
   
   int nMinFragSizeInWindow;
   if ( ! ConsEd::bCouldGetFragmentSizeFromGelPosition( 
                                nGetGelPositionAtBottomOfGelWindow(),
                                nMinFragSizeInWindow ) )
      return;

   // find bases of bottom-most tick.  Do this by "rounding"
   // nMinFragSizeInWindow up to the nearest multiple of a power of
   // ten.   
   // bottom of window
   //       bottom tick mark
   // 151   200? 1000? 10000? 100000?
   // 251   300? 1000? 10000? 100000?
   // 351   400? 1000? 10000? 100000?
   // 451   500? 1000? 10000? 100000?
   // 551   600? 1000? 10000? 100000?
   // 661   700? 1000? 10000? 100000?
   // 991   1000? 10000? 100000?
   // 1000  1000? 10000? 100000?
   // 1001  2000? 10000? 100000?

   int nPowerOfTen;
   int nMultipleOfPowerOfTen;
   int nPixelOfScaleTick;

   if ( !bCouldGetBottomScaleTickFragmentSize( nPowerOfTen,
                                               nMultipleOfPowerOfTen,
                                               nPixelOfScaleTick ) )
      return;

   if ( nPixelOfScaleTick < 0 ) return;

   int nFragmentSize = nPowerOfTen * nMultipleOfPowerOfTen;

   drawScaleTickForFragmentSize( nFragmentSize );

   while( bCouldGetNextFragmentSizeScaleTick( nPowerOfTen,
                                              nMultipleOfPowerOfTen,
                                              nPixelOfScaleTick ) ) {

      if ( nPixelOfScaleTick < 0 ) return;

      drawScaleTickForFragmentSize( nPowerOfTen * nMultipleOfPowerOfTen );
   }

}



void guiDisplayDigest :: drawScaleLine() {

   XDrawLine( XtDisplay( widGelWindow_ ),
              XtWindow( widGelWindow_ ),
               GuiApp::pGetGuiApp()->pColorOfRestrictionDigestScale_->gcGet(),
              nGetGelScaleCenter(),
              0,
              nGetGelScaleCenter(),
              nGetGelWindowPixelHeight() );

}




void guiDisplayDigest :: drawScaleTickForFragmentSize( const int nBases ) {

   int nGelPosition = 
      ConsEd::fGetPositionOnGelFromRestrictionFragmentSize( nBases );

   int nPixelY = nGetPixelYFromGelPosition( nGelPosition );

   XDrawLine( XtDisplay( widGelWindow_ ),
              XtWindow( widGelWindow_ ),
              GuiApp::pGetGuiApp()->pColorOfRestrictionDigestScale_->gcGet(),
              nGetGelScaleCenter(),
              nPixelY,
              nGetRightEndGelScaleTick(),
              nPixelY );


   int nLength = sprintf( szNumber, "%d", nBases );

   nPixelY += (GuiApp::nGetFontAscent() / 2 );

   XDrawString( XtDisplay( widGelWindow_ ),
                XtWindow( widGelWindow_ ),
                GuiApp::pGetGuiApp()->pColorOfRestrictionDigestScale_->gcGet(),
                nGetLeftEndScaleNumber2(),
                nPixelY,
                szNumber,
                nLength );

}





int guiDisplayDigest :: nGetGelPositionAtBottomOfGelWindow() {

   int nPixelAtBottom = nGetGelWindowPixelHeight();

   int nWindowHeightInGelUnits = nGetGelWindowPixelHeight() /
      fPixelsPerGelUnit_;

   return( nWindowHeightInGelUnits + nGelPositionAtTopOfGelWindow_ );
}




         
   
bool guiDisplayDigest :: bCouldGetBottomScaleTickFragmentSize( 
                                int& nPowerOfTen,
                                int& nMultipleOfPowerOfTen,
                                int& nPixelOfBottomScaleTick ) {

   // Near the bottom of the screen, see what nGetFontAscent in pixels 
   // translates to in bases.  Use this (rounded to a power of 10) as the
   // initial scale increment size.
   
   int nMinFragSizeInWindow;
   if ( ! ConsEd::bCouldGetFragmentSizeFromGelPosition( 
                                nGetGelPositionAtBottomOfGelWindow(),
                                nMinFragSizeInWindow ) )
      return( false );

   
   int nNextClosestFragSizeInWindow;
   if ( ! bCouldGetFragmentSizeFromPixelY(
                                nGetGelWindowPixelHeight() -
                                GuiApp::nGetFontAscent(),
                                nNextClosestFragSizeInWindow ) )
      return( false );

   int nMinFragSizeDifference = nNextClosestFragSizeInWindow - 
      nMinFragSizeInWindow;

   // pathological case
   if ( nMinFragSizeDifference <= 1 ) {
      nPowerOfTen = 1;
   }
   else {
      // normal case


      nPowerOfTen = 1;
      while( nPowerOfTen < nMinFragSizeDifference ) {
         nPowerOfTen *= 10;
      }
   
      assert( nPowerOfTen >= nMinFragSizeDifference ); 
      assert( nPowerOfTen/10 < nMinFragSizeDifference );
   }

   // round up
   nMultipleOfPowerOfTen = ( nMinFragSizeInWindow + nPowerOfTen - 1 ) /
      nPowerOfTen;


   nPixelOfBottomScaleTick = 
      nGetPixelYFromRestrictionFragmentSize( nPowerOfTen * 
                                             nMultipleOfPowerOfTen );
   return( true );
}


bool guiDisplayDigest :: bCouldGetNextFragmentSizeScaleTick( 
                                int& nPowerOfTenOfPreviousScaleTick,
                                int& nMultipleOfPowerOfTen,
                                int& nPixelOfPreviousScaleTick ) {
   
   // let's try the obvious--just increment the nMultipleOfPowerOfTen

   int nFragmentSizeOfNextScaleTick = ( nMultipleOfPowerOfTen + 1 ) *
      nPowerOfTenOfPreviousScaleTick;

   int nPixelOfNextScaleTick = 
      nGetPixelYFromRestrictionFragmentSize( nFragmentSizeOfNextScaleTick );

   if ( nPixelOfNextScaleTick < 0 )
      return( false );
   
   if ( ABS( nPixelOfPreviousScaleTick - nPixelOfNextScaleTick ) >=
        GuiApp::nGetFontAscent() ) {
      nPixelOfPreviousScaleTick = nPixelOfNextScaleTick;
      nMultipleOfPowerOfTen += 1;
      return( true );
   }

   // try jumping to the next power of ten

   while( nPowerOfTenOfPreviousScaleTick < nHugeRestrictionFragment ) {
      nPowerOfTenOfPreviousScaleTick *= 10;

      // we must have a nMultipleOfPowerOfTen that is large
      // enough so that the next tick is at least nFragmentSizeOfNextScaleTick

      nMultipleOfPowerOfTen = 
         ( nFragmentSizeOfNextScaleTick + nPowerOfTenOfPreviousScaleTick - 1 ) /
         nPowerOfTenOfPreviousScaleTick;


      nPixelOfNextScaleTick = 
         nGetPixelYFromRestrictionFragmentSize( 
                                      nPowerOfTenOfPreviousScaleTick *
                                      nMultipleOfPowerOfTen );


      if ( nPixelOfNextScaleTick < 0 )
         return( false );

      if (  ABS( nPixelOfPreviousScaleTick - nPixelOfNextScaleTick ) >=
            GuiApp::nGetFontAscent() ) {
         nPixelOfPreviousScaleTick = nPixelOfNextScaleTick;
         return( true );
      }
   }

   return( false );

}


         
      


bool guiDisplayDigest :: bCouldGetFragmentSizeFromPixelY( const int nPixelY,
                                                          int& nFragSize ) {

   float fGelPosition = fGetGelPositionFromPixelY( nPixelY );

   if ( ConsEd::bCouldGetFragmentSizeFromGelPosition( fGelPosition,
                                                      nFragSize ) )
      return( true );
   else
      return( false );
}


void guiDisplayDigest :: calculateInitialZoomFactor() {

   // figure out the 10th percentile fragment size

   int n10PercentilePosition = 
      pCurrentlyDisplayedDigest_->aActualRestrictionFragments_.length() * 
      0.9;

   if ( n10PercentilePosition >= 
        pCurrentlyDisplayedDigest_->aActualRestrictionFragments_.length() ) 
      return;

   int n10PercentileFragSize = 
      pCurrentlyDisplayedDigest_->aActualRestrictionFragments_[ n10PercentilePosition ]->nSize_;

   float fGelPositionOfTenthPercentileFragment = 
      ConsEd::fGetPositionOnGelFromRestrictionFragmentSize( 
                                        n10PercentileFragSize );

   // So make sure that this gel position will be located near the bottom
   // of the screen.

   fPixelsPerGelUnit_ = 
      ( (float) ( nGetGelWindowPixelHeight() - GuiApp::nGetFontAscent() ) ) /
      ( fGelPositionOfTenthPercentileFragment - (float) nGetMinGelPosition() );


}


const int nHalfVisibleLineTargetHeight = 16;

void guiDisplayDigest :: expandVisibleLines() {
   expandVisibleLines2( &aVisibleLinesForPredictedFragments_ );
   expandVisibleLines2( &aVisibleLinesForActualFragments_ );
}



void guiDisplayDigest :: expandVisibleLines2( 
   RWTValOrderedVector<visibleLineForRestrictionFragments>* pVisibleLineArray ) {

   for( int nLine = 1; nLine < pVisibleLineArray->length();
        ++nLine ) {
      visibleLineForRestrictionFragments& vis1 = 
         (*pVisibleLineArray)[ nLine - 1];

      visibleLineForRestrictionFragments& vis2 = 
         (*pVisibleLineArray)[ nLine ];

      int nMidPixel = ( vis1.nBottomPixel_ + vis2.nTopPixel_ ) / 2;

      // if vis1.nBottomPixel_ and vis2.nTopPixel_ are only 1 pixel
      // apart, nMidPixel will be which one?  It will be the top (smaller)
      // one.  That is the reason (below) that the top vis gets 
      // nMidPixel and the bottom vis gets the nMidPixel + 1

      vis1.nBottomPixel_ = MIN( nMidPixel,
                                vis1.nBottomPixel_ +
                                nHalfVisibleLineTargetHeight );

      vis2.nTopPixel_ = MAX( nMidPixel + 1,
                             vis2.nTopPixel_ -
                             nHalfVisibleLineTargetHeight );

   }


   // still need to handle the top of the top and the bottom of the bottom

   if ( pVisibleLineArray->length() > 0 ) {
      (*pVisibleLineArray)[0].nTopPixel_ -= 
         nHalfVisibleLineTargetHeight;

      (*pVisibleLineArray)[ 
         pVisibleLineArray->length() - 1
                           ].nBottomPixel_ 
         += nHalfVisibleLineTargetHeight;

   }


}


void guiDisplayDigest :: pointerMoved( const int nPixelX, 
                                       const int nPixelY ) {

   restrictionFragment* pNewActualResFrag;
   restrictionFragment* pNewPredictedResFrag;

   getFragmentsAtPosition( nPixelX,
                           nPixelY,
                           pNewActualResFrag,
                           pNewPredictedResFrag );
   
   // if pointer hasn't moved much, no need to redraw
   if ( pNewActualResFrag == pTempMarkedActualRestrictionFragment_
        &&
        pNewPredictedResFrag == 
        pTempMarkedPredictedRestrictionFragment_ )
      return;
   
   clearTempVisibleLines();
   drawPermVisibleLines();

   pTempMarkedActualRestrictionFragment_ = pNewActualResFrag;
   pTempMarkedPredictedRestrictionFragment_ = pNewPredictedResFrag;
   
   drawTempVisibleLines();
}



void guiDisplayDigest :: clearTempVisibleLines() {
   clearLineIndicator( restrictionFragment::ACTUAL_FRAGMENT, false );
   clearLineIndicator( restrictionFragment::PREDICTED_FRAGMENT, false );
}
   
void guiDisplayDigest :: clearPermVisibleLines() {
   clearLineIndicator( restrictionFragment::ACTUAL_FRAGMENT, true );
   clearLineIndicator( restrictionFragment::PREDICTED_FRAGMENT, true );
}


void guiDisplayDigest :: clearLineIndicator( 
                      const unsigned char cActualOrPredicted,
                      const bool bPermNotTemp ) {

   restrictionFragment* pRes;
   if ( cActualOrPredicted == restrictionFragment::ACTUAL_FRAGMENT ) {
      if ( bPermNotTemp ) {
         pRes = pPermMarkedActualRestrictionFragment_;
         pPermMarkedActualRestrictionFragment_ = NULL;
      }
      else {
         pRes = pTempMarkedActualRestrictionFragment_;
         pTempMarkedActualRestrictionFragment_ = NULL;
      }
   }
   else {
      if ( bPermNotTemp ) {
         pRes = pPermMarkedPredictedRestrictionFragment_;
         pPermMarkedPredictedRestrictionFragment_ = NULL;
      }
      else {
         pRes = pTempMarkedPredictedRestrictionFragment_;
         pTempMarkedPredictedRestrictionFragment_ = NULL;
      }
   }


   if ( !pRes ) return;

   int nPixelYOfLine = nGetPixelYFromGelPosition( pRes->fPositionOnGel_ );

   clearLineIndicator2( cActualOrPredicted, nPixelYOfLine );
}



void guiDisplayDigest :: clearLineIndicator2( unsigned char cActualOrPredicted,
                                              const int nPixelYOfLine ) {

   // erase arrow
   int nX;
   if ( cActualOrPredicted == restrictionFragment::ACTUAL_FRAGMENT ) {
      nX = nGetLeftEndOfLeftArrowForActualFragment();
   }
   else {
      nX = nGetLeftEndOfRightArrowForPredictedFragment();
   }


   XClearArea( XtDisplay( widGelWindow_ ),
               XtWindow( widGelWindow_ ),
               nX,
               nPixelYOfLine - nHalfHeightOfCursorIndicator,
               nArrowWidth,
               2*nHalfHeightOfCursorIndicator,
               False );

   // erase numbers

   int nWidth = nMaxDigitsFragmentSize * GuiApp::nGetFontWidth();
   
   int nY = nPixelYOfLine - GuiApp::nGetFontAscent() / 2;
   
   if ( cActualOrPredicted == restrictionFragment::ACTUAL_FRAGMENT ) {
      nX = nGetLeftEndOfActualFragmentSizeOnGel();
   }
   else {
      nX = nGetLeftEndOfPredictedFragmentSizeOnGel();
   }

   XClearArea( XtDisplay( widGelWindow_ ),
               XtWindow( widGelWindow_ ),
               nX,
               nY,
               nWidth,
               GuiApp::nGetFontAscent(), 
               False );
}


void guiDisplayDigest :: drawTempVisibleLines() {
   drawVisibleLine( restrictionFragment::ACTUAL_FRAGMENT, false );
   drawVisibleLine( restrictionFragment::PREDICTED_FRAGMENT, false );

}

void guiDisplayDigest :: drawPermVisibleLines() {
   drawVisibleLine( restrictionFragment::ACTUAL_FRAGMENT, true );
   drawVisibleLine( restrictionFragment::PREDICTED_FRAGMENT, true );
}





void guiDisplayDigest :: drawVisibleLine(
                      const unsigned char cActualOrPredicted,
                      const bool bPermNotTemp ) {

   restrictionFragment* pResFrag;
   if ( cActualOrPredicted == restrictionFragment::ACTUAL_FRAGMENT ) {
      if ( bPermNotTemp )
         pResFrag = pPermMarkedActualRestrictionFragment_;
      else
         pResFrag = pTempMarkedActualRestrictionFragment_;
   }
   else {
      if ( bPermNotTemp ) 
         pResFrag = pPermMarkedPredictedRestrictionFragment_;
      else
         pResFrag = pTempMarkedPredictedRestrictionFragment_;
   }


   if ( !pResFrag ) return;

   visibleLineForRestrictionFragments* pVis =
      pGetVisibleLineFromRestrictionFragment( pResFrag );
   

   // case in which the marked restriction fragment is off the screen
   if ( !pVis ) return;


   int nPixelYOfLine = pVis->nMiddlePixel_;

   // clear the area we are going to draw to

   clearLineIndicator2( cActualOrPredicted, nPixelYOfLine );

   int nNumberOfPoints;
   XPoint aPoint[ 6 ];
   if ( bPermNotTemp ) {
      
      nNumberOfPoints = 5;

      if ( cActualOrPredicted == restrictionFragment::ACTUAL_FRAGMENT ) {

         //             point 0,4
         //     point1           point 3
         //             point 2

         aPoint[0].x = nGetLeftEndOfLeftArrowForActualFragment() +
            nArrowWidth / 2;
         aPoint[0].y = nPixelYOfLine - nHalfHeightOfCursorIndicator;

         aPoint[1].x = nGetLeftEndOfLeftArrowForActualFragment();
         aPoint[1].y = nPixelYOfLine;

         aPoint[2].x = aPoint[0].x;
         aPoint[2].y = nPixelYOfLine + nHalfHeightOfCursorIndicator;
         
         aPoint[3].x = nGetRightEndOfLeftArrowForActualFragment();
         aPoint[3].y = aPoint[1].y;
         
         aPoint[4] = aPoint[0];
      }
      else {
         //            point 0,4
         //  point 3            point 1
         //            point 2   


         aPoint[0].x = nGetRightEndOfRightArrowForPredictedFragment() -
            nArrowWidth / 2;
         aPoint[0].y = nPixelYOfLine - nHalfHeightOfCursorIndicator;
   
         aPoint[1].x = nGetRightEndOfRightArrowForPredictedFragment();
         aPoint[1].y = nPixelYOfLine;

         aPoint[2].x = aPoint[0].x;
         aPoint[2].y = nPixelYOfLine + nHalfHeightOfCursorIndicator;

         aPoint[3].x = nGetLeftEndOfRightArrowForPredictedFragment();
         aPoint[3].y = nPixelYOfLine;
         
         aPoint[4] = aPoint[0];
      }
   }
   else {
      nNumberOfPoints = 4;

      if ( cActualOrPredicted == restrictionFragment::ACTUAL_FRAGMENT ) {

         aPoint[0].x = nGetLeftEndOfLeftArrowForActualFragment();
         aPoint[0].y = nPixelYOfLine - nHalfHeightOfCursorIndicator;
         aPoint[1].x = aPoint[0].x;
         aPoint[1].y = aPoint[0].y + 2 * nHalfHeightOfCursorIndicator;
         
         aPoint[2].x = nGetRightEndOfLeftArrowForActualFragment();
         aPoint[2].y = aPoint[0].y + nHalfHeightOfCursorIndicator;
   
         aPoint[3] = aPoint[0];
      }
      else {
         aPoint[0].x = nGetRightEndOfRightArrowForPredictedFragment();
         aPoint[0].y = nPixelYOfLine - nHalfHeightOfCursorIndicator;
   
         aPoint[1].x = aPoint[0].x;
         aPoint[1].y = aPoint[0].y + 2 * nHalfHeightOfCursorIndicator;
   
         aPoint[2].x = nGetLeftEndOfRightArrowForPredictedFragment();
         aPoint[2].y = aPoint[0].y + nHalfHeightOfCursorIndicator;
      
         aPoint[3] = aPoint[0];
      }
   }

   XFillPolygon( 
                XtDisplay( widGelWindow_ ),
                XtWindow( widGelWindow_ ),
                pVis->pGetGuiColorText()->gcGet(),
                aPoint,
                nNumberOfPoints,
                Convex,
                CoordModeOrigin );


   // now draw the fragment size, using the first 
   // fragment's size


   int nLength;
   if ( pVis->aFragmentsAtSamePixel_.length() == 1 )
      nLength = sprintf( szNumber, "%d", pResFrag->nSize_ );
   else {
      if ( cActualOrPredicted == restrictionFragment::ACTUAL_FRAGMENT )
         nLength = sprintf( szNumber, "(%d) %d", 
                            pVis->aFragmentsAtSamePixel_.length(),
                            pResFrag->nSize_ );
      else
         nLength = sprintf( szNumber, "%d (%d)", 
                            pResFrag->nSize_,
                            pVis->aFragmentsAtSamePixel_.length() );
   }

   int nX;
   if ( cActualOrPredicted == restrictionFragment::ACTUAL_FRAGMENT )
      nX = nGetRightEndOfActualFragmentSizeOnGel()
         - nLength * GuiApp::nGetFontWidth();
   else
      nX = nGetLeftEndOfPredictedFragmentSizeOnGel();

   int nY = nPixelYOfLine + GuiApp::nGetFontAscent() / 2;

   XDrawString(
               XtDisplay( widGelWindow_ ),
               XtWindow( widGelWindow_ ),
               pVis->pGetGuiColorText()->gcGet(),
               nX,
               nY,
               szNumber,
               nLength );

}
   



visibleLineForRestrictionFragments* guiDisplayDigest :: pGetVisibleLineFromRestrictionFragment( 
    restrictionFragment* pResFrag ) {

   visibleLineForRestrictionFragments* pVis;
   if ( pResFrag->cActualOrPredictedFragment_ == 
        restrictionFragment::ACTUAL_FRAGMENT ) {

      pVis = pGetVisibleLineForActualRestrictionFragments(
               nGetPixelYFromGelPosition( pResFrag->fPositionOnGel_ ) );

   }
   else {
      pVis = pGetVisibleLineForPredictedRestrictionFragments(
                  nGetPixelYFromGelPosition( pResFrag->fPositionOnGel_ ) );
   }

   return( pVis );
}



void guiDisplayDigest :: getFragmentsAtPosition( 
     const int nPointerPixelX,
     const int nPointerPixelY,
     restrictionFragment*& pNewActualRestrictionFragment,
     restrictionFragment*& pNewPredictedRestrictionFragment ) {

   visibleLineForRestrictionFragments* pNewActualVisibleLine = 
      pGetVisibleLineForActualRestrictionFragments( nPointerPixelY );

   if ( pNewActualVisibleLine )
      pNewActualRestrictionFragment = 
         pNewActualVisibleLine->aFragmentsAtSamePixel_[0];
   else
      pNewActualRestrictionFragment = NULL;

   visibleLineForRestrictionFragments* pNewPredictedVisibleLine = 
      pGetVisibleLineForPredictedRestrictionFragments( nPointerPixelY );

   if ( pNewPredictedVisibleLine )
      pNewPredictedRestrictionFragment =
         pNewPredictedVisibleLine->aFragmentsAtSamePixel_[0];
   else
      pNewPredictedRestrictionFragment = NULL;
}




visibleLineForRestrictionFragments* guiDisplayDigest :: pGetVisibleLineForPredictedRestrictionFragments(
     const int nPointerPixelY ) {

   return( pGetVisibleLineForRestrictionFragments2( nPointerPixelY,
                                                    &aVisibleLinesForPredictedFragments_ ) );
}



visibleLineForRestrictionFragments* guiDisplayDigest :: pGetVisibleLineForActualRestrictionFragments(
                                                                                                     const int nPointerPixelY ) {
   return( pGetVisibleLineForRestrictionFragments2( nPointerPixelY,
                                                    &aVisibleLinesForActualFragments_ ) );
}


visibleLineForRestrictionFragments* guiDisplayDigest :: pGetVisibleLineForRestrictionFragments2( 
     const int nPointerPixelY,
     RWTValOrderedVector<visibleLineForRestrictionFragments>* 
        pVisibleLineArray ) {


   if ( pVisibleLineArray->length() == 0 )
      return( NULL );

   int nTooSmallIndex = 0;
   int nMaxIndex = pVisibleLineArray->length() - 1;

   // region A
   // ------------ nTooSmallIndex top
   // B
   // ------------ nTooSmallIndex bottom
   // C
   //
   // ------------ nMaxIndex top
   // D
   // ------------ nMaxIndex bottom
   // E
   //
   // The loop assumes that the nPointerPixelY lies within either C or D.
   // Thus we need to first handle the other cases:

   // case of region E:

   if ( (*pVisibleLineArray)[ nMaxIndex ].nBottomPixel_ <
        nPointerPixelY )
      return( NULL );

   
   // case of regions A and B:

   if ( nPointerPixelY <= 
        (*pVisibleLineArray)[ nTooSmallIndex ].nBottomPixel_ ) {
      
      // case of region A
      if ( nPointerPixelY <
           (*pVisibleLineArray)[ nTooSmallIndex ].nTopPixel_ )
         return( NULL );
      else {
         // case of region B
         return( &( (*pVisibleLineArray)[ nTooSmallIndex ] ) );
      }
   }

   // region A
   // ------------ nTooSmallIndex top
   // B
   // ------------ nTooSmallIndex bottom
   // C
   // ------------ nTestIndex top
   // F
   // ------------ nTestIndex bottom
   // G
   //
   // ------------ nMaxIndex top
   // D
   // ------------ nMaxIndex bottom
   // E
   //

   while( 1 ) {
      if ( nMaxIndex - nTooSmallIndex == 1 ) {
         // nMaxIndex is the candidate

         if ( (*pVisibleLineArray)[ nMaxIndex ].nTopPixel_ 
              <= nPointerPixelY ) {
            return( &( (*pVisibleLineArray)[ nMaxIndex ] ) );
         }
         else
            return( NULL );
      }
      else {
         int nTestIndex = ( nTooSmallIndex + nMaxIndex ) / 2;
         if ( (*pVisibleLineArray)[ nTestIndex ].nBottomPixel_
              < nPointerPixelY )
            // case of pointer in region G or D
            nTooSmallIndex = nTestIndex;
         else
            // case of pointer in region C or F
            nMaxIndex = nTestIndex;
      }
   }
}



void guiDisplayDigest :: userClicked( XtPointer pCallData ) {



   if ( ((XmDrawingAreaCallbackStruct*) pCallData )->event->xany.type !=
        ButtonPress ) return;


   int nPixelX = ((XmDrawingAreaCallbackStruct*) pCallData )->event->xbutton.x;
   int nPixelY = ((XmDrawingAreaCallbackStruct*) pCallData )->event->xbutton.y;

   // just in case the temp cursors haven't yet caught up with the
   // pointer, move them

   pointerMoved( nPixelX, nPixelY );

   // now, which one of the temp cursors is the user pointing at?

   bool bActualNotPredictedFragment;
   restrictionFragment* pNewPermRes;
   restrictionFragment* pOldPermRes;
   if ( nPixelX <= nGetActualFragmentRightEndOnGel() ) {
      pNewPermRes = pTempMarkedActualRestrictionFragment_;
      pOldPermRes = pPermMarkedActualRestrictionFragment_;
      pPermMarkedActualRestrictionFragment_ = pNewPermRes;
      bActualNotPredictedFragment = true;
   }
   else {
      pNewPermRes = pTempMarkedPredictedRestrictionFragment_;
      pOldPermRes = pPermMarkedPredictedRestrictionFragment_;
      pPermMarkedPredictedRestrictionFragment_ = pNewPermRes;
      bActualNotPredictedFragment = false;
   }
  

   if ( !pNewPermRes ) {
      popupErrorMessage2( widPopupShell_,
                          "Before clicking, you must first point to a band so that an arrow points to it" );
      return;
   }

//    if ( !bActualNotPredictedFragment &&
//         ( pNewPermVis->aFragmentsAtSamePixel_.length() > 1 ) ) {
//       RWCString soMessage = "Warning--that line represents the following fragments of sizes:  ";
//       for( int nFrag = 0; 
//            nFrag < pNewPermVis->aFragmentsAtSamePixel_.length();
//            ++nFrag ) {
//          restrictionFragment* pFrag = 
//             pNewPermVis->aFragmentsAtSamePixel_[ nFrag ];
//          soMessage += RWCString( (long) pFrag->nSize_ );
//          soMessage += " ";
//       }

//       soMessage += " so I don't know which fragment you are referring to";
//       popupErrorMessage2( widPopupShell_, soMessage );
//    }


   if ( pNewPermRes->cActualOrPredictedFragment_ == restrictionFragment::PREDICTED_FRAGMENT ) {

      highlightTextWindowLineForPredictedFragment( pNewPermRes );
   }

   // erase the perm indicators in the last place

   if ( pOldPermRes ) {
      clearLineIndicator2( pOldPermRes->cActualOrPredictedFragment_,
                           nGetPixelYFromGelPosition( pOldPermRes->fPositionOnGel_ ) );
   }

   drawVisibleLine( pNewPermRes->cActualOrPredictedFragment_, true );
}


void guiDisplayDigest :: highlightTextWindowLineForPredictedFragment(
                            restrictionFragment* pResFragClickedOn ) {

   // find that fragment in the list

   arrayOfRestrictionFragments* pPredictedFragmentArray =
      pGetPredictedFragmentsArray();

   int nChosenFrag = -666;
   for( int nPredicted = 0; 
        nPredicted < 
        pPredictedFragmentArray->length();
        ++nPredicted ) {
      restrictionFragment* pResFrag = 
         (*pPredictedFragmentArray)[ nPredicted ];
      if ( pResFrag == pResFragClickedOn ) {
         nChosenFrag = nPredicted;
         break;
      }
   }


   assert( nChosenFrag != -666 );

   // convert the index to 1-based as required by XmTextList widgets

   int nIndexInMotifList = nChosenFrag + 1;

   int nTopIndex;
   int nVisibleItems;
   XtVaGetValues( widTextList_,
                  XmNtopItemPosition, &nTopIndex,
                  XmNvisibleItemCount, &nVisibleItems,
                  NULL );

   int nBottomIndex = nTopIndex + nVisibleItems - 1;


   if ( nIndexInMotifList < nTopIndex ||
        nBottomIndex < nIndexInMotifList ) {
      // the item we want to select is not visible, so make it so.

      int nNewTopIndex = nIndexInMotifList - nVisibleItems / 2;
      if ( nNewTopIndex < 1 )
         nNewTopIndex = 1;

      XmListSetPos( widTextList_, nNewTopIndex );
   }

   XmListSelectPos( widTextList_, nIndexInMotifList, True );

   highlightContigMapForFragment( pResFragClickedOn );

}         




      

void guiDisplayDigest :: drawTitles() {
   
   char* szActual    = "Real";
   char* szPredicted = "In-silico";

   int nY = nGetTitleBaseline();
   
   int nLength = strlen( szActual );

   int nX = nGetActualFragmentRightEndOnGel() - 
      nLength * GuiApp::nGetFontWidth();

   XDrawString(
               XtDisplay( widGelWindow_ ),
               XtWindow( widGelWindow_ ),
               GuiApp::pGetGuiApp()->pColorOfRestrictionDigestScale_->gcGet(),
               nX,
               nY,
               szActual,
               nLength );

   nX = nGetPredictedFragmentLeftEndOnGel();

   nLength = strlen( szPredicted );

   XDrawString(
               XtDisplay( widGelWindow_ ),
               XtWindow( widGelWindow_ ),
               GuiApp::pGetGuiApp()->pColorOfRestrictionDigestScale_->gcGet(),
               nX,
               nY,
               szPredicted,
               nLength );

}
        


static int cmpRestrictionFragmentsBySize( const restrictionFragment** ppRes1,
                                          const restrictionFragment** ppRes2 ){
   
   if ( (*ppRes1)->nSize_ < (*ppRes2)->nSize_ )
      return( 1 );
   else if ( (*ppRes1)->nSize_ == (*ppRes2)->nSize_ )
      return( 0 );
   else
      return( -1 );
}


void guiDisplayDigest :: createProblemList( 
               RWTPtrOrderedVector<restrictionFragment>* pProblemList ) {


   // it doesn't matter whether we use aPredictedResFragsBySize_ or
   // aPredictedResFragsByConsPos_ since they both have the same
   // pointers, and we will sort the pointers differently later (below)
   // anyway

   for( int nPredicted = 0; 
        nPredicted < 
        pCurrentlyDisplayedDigest_->aPredictedResFragsBySize_.length();
        ++nPredicted ) {

      restrictionFragment* pResFrag = 
         pCurrentlyDisplayedDigest_->aPredictedResFragsBySize_[ nPredicted ];
      
      if ( !pResFrag->pCorrespondingFrag_ ) {
         pProblemList->insert( pResFrag );
      }
      else {
         if ( 
             ABS( pResFrag->fPositionOnGel_ - 
                  pResFrag->pCorrespondingFrag_->fPositionOnGel_ ) >
             pCP->nRestrictionDigestToleranceInPositionUnits_ ) {
            pProblemList->insert( pResFrag );
         }
      }
   }


   for( int nActual = 0;
        nActual < 
        pCurrentlyDisplayedDigest_-> aActualRestrictionFragments_.length();
        ++nActual ) {

      restrictionFragment* pActualFrag =
         pCurrentlyDisplayedDigest_->aActualRestrictionFragments_[ nActual ];
   
      
      if ( !pActualFrag->pCorrespondingFrag_ ) {
         pProblemList->insert( pActualFrag );
      }
      else {
         if ( 
             ABS( pActualFrag->fPositionOnGel_ -
                  pActualFrag->pCorrespondingFrag_->fPositionOnGel_ ) >
             pCP->nRestrictionDigestToleranceInPositionUnits_ ) {

            pProblemList->insert( pActualFrag );
         }
      }
   }


   // sort the list by fragment size (larger fragments first)

   void* pArray = (void*) pProblemList->data();
   size_t nNumberOfElementsInArray = pProblemList->length();
   size_t nSizeOfAnElement = sizeof( restrictionFragment* );
   
   qsort( pArray, nNumberOfElementsInArray, nSizeOfAnElement,
          ( ( int(*) ( const void*, const void*) ) cmpRestrictionFragmentsBySize )
          );

   // check that is really is sorted

   for( int nFrag = 1; nFrag < pProblemList->length(); ++nFrag ) {
      
      restrictionFragment* pFrag1 = (*pProblemList)[ nFrag - 1 ];
      restrictionFragment* pFrag2 = (*pProblemList)[ nFrag ];

      if ( pFrag1->nSize_ < pFrag2->nSize_ ) {
         // error in qsort

         RWCString soMessage = "qsort failed in guiDisplayDigest::createProblemList since (*pProblemList)[ ";
         soMessage += RWCString( (long) nFrag - 1 );
         soMessage += " ]->nSize_ = ";
         soMessage += RWCString( (long) pFrag1->nSize_ );
         soMessage += " < (*pProblemList)[ ";
         soMessage += RWCString( (long) nFrag );
         soMessage += " ]->nSize_ = ";
         soMessage += RWCString( (long) pFrag2->nSize_ );
         THROW_ERROR( soMessage );
      }
   }
}


void guiDisplayDigest :: userPushedShowProblems() {

   new guiDigestProblemNavigator( this );
}


// used by guiDigestProblemNavigator
void guiDisplayDigest :: highlightFragment( restrictionFragment* pResFrag ) {


   clearPermVisibleLines();
   clearTempVisibleLines();

   // first possibly need to scroll window so this fragment is in view

   if ( pResFrag->fPositionOnGel_ < nGetGelPositionAtTopOfGelWindow() || 
        nGetGelPositionAtBottomOfGelWindow() < pResFrag->fPositionOnGel_ ) {

      scrollGel( pResFrag->fPositionOnGel_ );
   }

   // now move pointer.

   if ( pResFrag->cActualOrPredictedFragment_ == 
        restrictionFragment::ACTUAL_FRAGMENT ) 
      pPermMarkedActualRestrictionFragment_ =  pResFrag;
   else
      pPermMarkedPredictedRestrictionFragment_ = pResFrag;


   drawVisibleLine( pResFrag->cActualOrPredictedFragment_, true );

   if ( pResFrag->cActualOrPredictedFragment_ == 
        restrictionFragment::PREDICTED_FRAGMENT ) 
      highlightTextWindowLineForPredictedFragment( pResFrag );
   else
      // unhighlight whatever was highlighted before
      XmListDeselectAllItems( widTextList_ );



}




void guiDisplayDigest :: zoomInForNavigate() {

   fPixelsPerGelUnit_ *= pCP->dRestrictionDigestZoomFactorForNavigate_;
   
   adjustScrollBarWhenZoom();

   displayGelWindow();
}



   

   
void guiDisplayDigest :: scrollGel( const float fPositionOnGel ) {

   // put this position in the center of the gel

   float fGelUnitsDisplayedAtOnce = nGetGelWindowPixelHeight() / fPixelsPerGelUnit_;

   int nNewGelPositionAtTopOfGelWindow = fPositionOnGel -
      fGelUnitsDisplayedAtOnce / 2;

   if ( nNewGelPositionAtTopOfGelWindow < nGetMinGelPosition()  )
      nNewGelPositionAtTopOfGelWindow = nGetMinGelPosition();
   
   // I'm going to allow scrolling to a too great position--we might be so
   // far zoomed out that the furthest visible position is beyond the 
   // maximum.

   nGelPositionAtTopOfGelWindow_ = nNewGelPositionAtTopOfGelWindow;

   
   displayGelWindow();
}

const int nExtraNumberOfPixelsBeyondLastFragment = 20;

int guiDisplayDigest :: nGetMaxGelPosition() {
      return( pCurrentlyDisplayedDigest_->nMaxGelPosition_ +
              nExtraNumberOfPixelsBeyondLastFragment / fPixelsPerGelUnit_ );
}


void guiDisplayDigest :: setMinGelPosition() {

   nMinGelPosition_ =
      ConsEd::fGetPositionOnGelFromRestrictionFragmentSize( 
         pCP->nRestrictionDigestDoNoShowAreaOfFragmentsOverThisSize_ );

}


void guiDisplayDigest :: highlightContigMapForFragment( restrictionFragment*
                                                        pResFrag ) {

   int nStartPos;
   int nEndPos;
   ConsEd::pGetAssembly()->findRestrictionFragmentInContigMap( pResFrag,
                                                               nStartPos,
                                                               nEndPos );

   // XmTextSetHighlight's end position is the 0-based position of
   // the first character that is *not* highlighted.  Hence:
   ++nEndPos;

   XtVaSetValues( widContigMap_,
                 XmNvalue,
                 ConsEd::pGetAssembly()->soContigMap_.data(),
                 NULL );

   XmTextFieldSetHighlight( widContigMap_, 0, 
                            ConsEd::pGetAssembly()->soContigMap_.length(), 
                            XmHIGHLIGHT_NORMAL );
   
   if ( nStartPos == -1 ) {
      return;
   }

   XmTextFieldSetHighlight( widContigMap_, nStartPos, nEndPos, 
                            XmHIGHLIGHT_SELECTED );
}



void guiDisplayDigest :: showTextOutput() {

   char szTitle[100];
   sprintf( szTitle, "Restriction Digest for %s", 
            pCurrentlyDisplayedDigest_->soEnzymeName_.data() );

   TextBox* pTB = new TextBox( szTitle,
                               30 ); // number of rows


   pTB->append( "---------    ----------------------\n" );
   pTB->append( "  Real           In  Silico        \n" );
   pTB->append( "Frag Size    Size    Position      \n" );
   pTB->append( "---------    -----   --------------\n" );


   int nPredictedFrag = 0;
   int nActualFrag = 0;


   const int nJustPrintActual = 1;
   const int nJustPrintPredicted = 2;
   const int nPrintBoth = 3;


   while( true ) {
      
      if ( nPredictedFrag >= 
           pCurrentlyDisplayedDigest_->aPredictedResFragsBySize_.length() &&
           nActualFrag >= 
           pCurrentlyDisplayedDigest_->aActualRestrictionFragments_.length() )
         break;

      restrictionFragment* pPredictedFrag = NULL;
      if ( nPredictedFrag < 
           pCurrentlyDisplayedDigest_->aPredictedResFragsBySize_.length() ) {
         pPredictedFrag = 
            pCurrentlyDisplayedDigest_->aPredictedResFragsBySize_[ nPredictedFrag ];
      }


      restrictionFragment* pActualFrag = NULL;
      if ( nActualFrag < 
           pCurrentlyDisplayedDigest_->aActualRestrictionFragments_.length() ) {
         pActualFrag = 
            pCurrentlyDisplayedDigest_->aActualRestrictionFragments_[ nActualFrag ];
      }

      int nWhichToPrint = 0;

      if ( !pPredictedFrag )
         // case in which there are no more predicted bands
         nWhichToPrint = nJustPrintActual;
      else if ( !pActualFrag )
         // case in which there are no more actual bands
         nWhichToPrint = nJustPrintPredicted;
      else {
         // case in which there are both actual bands

         // cases
         // 1) they correspond to each other
         //      print them on one line
         // 2) they don't correspond to each other
         //      print the one with the least position and advance it.


         if ( pPredictedFrag->pCorrespondingFrag_ &&
              pPredictedFrag->pCorrespondingFrag_ ==
              pActualFrag ) {

            nWhichToPrint = nPrintBoth;
         }
         else {
            if ( pPredictedFrag->fPositionOnGel_ < pActualFrag->fPositionOnGel_ ) {
               // just print the predicted fragment
            
               // this better not have a corresponding actual fragment
            
               assert( !pPredictedFrag->pCorrespondingFrag_ );
               nWhichToPrint = nJustPrintPredicted;
            }
            else {
               // just print the actual fragment

               // this better not have a corresponding predicted fragment

               assert( !pActualFrag->pCorrespondingFrag_ );

               nWhichToPrint = nJustPrintActual;
            }
         }
      } //       if ( !pPredictedFrag ) else if ... else 

      if (nWhichToPrint == nPrintBoth ) {

         RWCString soPredictedDescription;
         pPredictedFrag->getDescriptionLine( soPredictedDescription );

         pTB->appendWithArgs( "%8d  %8s\n",
                              pActualFrag->nSize_,
                              soPredictedDescription.data() );
         

         ++nPredictedFrag;
         ++nActualFrag;
      }            
      else if ( nWhichToPrint == nJustPrintPredicted ) {

         RWCString soPredictedDescription;
         pPredictedFrag->getDescriptionLine( soPredictedDescription );
         pTB->appendWithArgs( "          %s\n", soPredictedDescription.data() );

         ++nPredictedFrag;
      }
      else if ( nWhichToPrint == nJustPrintActual ) {

         pTB->appendWithArgs( "%8d\n",
                              pActualFrag->nSize_ );

         ++nActualFrag;
      } //  if (nWhichToPrint == nPrintBoth ) else if ... else
      else
         assert( false );
   } // while( true )


   pTB->append( "\n\n\n\n" );
   pTB->append( "-------------------------------\n" );
   pTB->append( "In  Silico Sorted By Position  \n" );
   pTB->append( "Frag Size   Frag Position\n" );
   pTB->append( "---------   -------------------\n" );



   RWCString soStringToDisplay( (size_t) 200 );
   
   for( int nPredictedFragment = 0; nPredictedFragment <
           pCurrentlyDisplayedDigest_->aPredictedResFragsByConsPos_.length();
        ++nPredictedFragment ) {

      restrictionFragment* pResFrag =
         pCurrentlyDisplayedDigest_->aPredictedResFragsByConsPos_[
                                                     nPredictedFragment ];

      pResFrag->getDescriptionLine( soStringToDisplay );

      pTB->append( soStringToDisplay );
      pTB->append( "\n" );
   }

   // for debugging, show the vector partial fragments

   pTB->append( "\n\n\n" );
   pTB->append( "partial vector fragments\n" );
   pTB->append( "(presumably joined above to partial insert fragments)\n" );


   for( int nFrag = 0; 
        nFrag < 
           pCurrentlyDisplayedDigest_->aPredictedVectorRestrictionFragmentsEndingAtVectorInsertJunction_.length(); 
        ++nFrag ) {
         restrictionFragment* pVectorFrag = 
            pCurrentlyDisplayedDigest_->aPredictedVectorRestrictionFragmentsEndingAtVectorInsertJunction_[ nFrag ];

         pTB->appendWithArgs( "size: %d\n", pVectorFrag->nSize_ );

   }
         


   

   pTB->makeVisible();

}



void guiDisplayDigest :: sortChanged() {

   updateTextDisplay();
}




arrayOfRestrictionFragments* guiDisplayDigest :: pGetPredictedFragmentsArray() {

   Boolean bSortByPosition = XmToggleButtonGetState( widSortByPosition_ );

   if ( bSortByPosition ) 
      return( 
         &( pCurrentlyDisplayedDigest_->aPredictedResFragsByConsPos_ )
         );
   else
      return(
         &( pCurrentlyDisplayedDigest_->aPredictedResFragsBySize_ ) 
         );
}
      


void guiDisplayDigest :: showDocumentationForRestrictionDigest() {

   TextBox* pTB = new TextBox( "Documentation",
                               30, // rows visible 
                               pCP->soGetDocumentation() );

   
   pTB->makeVisible();

   int nFoundPos = pCP->soGetDocumentation().index( "RESTRICTION DIGEST" );
   if ( nFoundPos == RW_NPOS ) {
      popupErrorMessage( "Internal program error finding RESTRICTION DIGEST in documentation." );
      return;
   }

   XmTextSetHighlight( pTB->widScrolledText_,
                       nFoundPos,
                       nFoundPos + strlen( "RESTRICTION DIGEST" ),
                       XmHIGHLIGHT_SELECTED );

   pTB->scrollWindowToLocation( nFoundPos );
}



void guiDisplayDigest :: userPushedComplVector() {

   bFlipVectorFromTheDefault_ = !bFlipVectorFromTheDefault_;

   RWCString soLabel;
   if ( bFlipVectorFromTheDefault_ )
      soLabel = "uncompl vec";
   else
      soLabel = "compl vector";

   XmString xms = XmStringCreateSimple( soLabel.data() );

   XtVaSetValues( widComplVector_,
                  XmNlabelString, xms,
                  NULL );

   // now do the real flipping, and do this for each enzyme.

   for( int nEnzyme = 0; nEnzyme < aDigests_.length();
        ++nEnzyme ) {
      digestForOneEnzyme* pDigest = aDigests_[ nEnzyme ];

      pDigest->processingAfterFindingAllPartialFragments( 
           bFlipVectorFromTheDefault_ );
   }

   // redisplay everything.  (This might not work if the changed
   // fragments cause some change in the resolution.)

   updateTextDisplay();
   displayGelWindow();
                  
}


void guiDisplayDigest :: tellAssemblyView() {

   if ( ConsEd::pGetConsEd()->pAssemblyView_ ) {

      ConsEd::pGetConsEd()->pAssemblyView_->drawEverything( true, // calculate positions
                                                            true ); // erase first
   }
}


int guiDisplayDigest :: nGetPixelYFromRestrictionFragmentSize( const int nFragmentSize ) {
      return( nGetPixelYFromGelPosition( 
      ConsEd::fGetPositionOnGelFromRestrictionFragmentSize( nFragmentSize ) )
              );
}


void guiDisplayDigest :: raiseWindow() {

   XtMapWidget( widPopupShell_ );

   XRaiseWindow(
                XtDisplay( widPopupShell_ ),
                XtWindow( widPopupShell_ )
                );
}