Compile function NDW_GAN_RDS_PROD_DEMO_EVENTS(CtrlEntId, Event, @PARAMS)
/***********************************************************************************************************************

    Name        :   NDW_GAN_RDS_PROD_DEMO_EVENTS

    Description :   Commuter module for the NDW_GAN_RDS_PROD_DEMO form.

    Notes       :   Application errors should be logged using the Error Services module. There are a few methodological
                    assumptions built into way errors are managed which are important to understand in order to properly
                    work with Error Services:

                    - The term 'top' refers to the originating procedure of a call stack and the term 'bottom' refers to
                      the last routine (or the current routine) within a call stack. Within the OpenInsight Debugger
                      this will appear backwards since the originating procedure always appears at the bottom of the
                      list and the current routine appears at the top of the list. We are using this orientation because
                      it is common to refer to the process of calling other procedures as 'drilling down'.

                    - The reason for defining the orientation of the call stack is because Error_Services allows for
                      multiple error conditions to be appended to an original error. In most cases this will happen when
                      a procedure at the bottom of the stack generates an error condition and then returns to its
                      calling procedure. This higher level procedure can optionally add more information relevant to
                      itself. This continues as the call stack 'bubbles' its way back to the top to where the
                      originating procedure is waiting.

                    - Native OpenInsight commands that handle errors (e.g., Set_Status, Set_FSError, Set_EventStatus)
                      preserve their error state until explicitly cleared. This can hinder the normal execution of code
                      since subsequent procedures (usually SSPs) will fail if a pre-existing error condition exists.
                      Our philosophy is that error conditions should automatically be cleared before a new procedure
                      is executed to avoid this problem. However, the nature of Basic+ does not make this easy to
                      automate for any given stored procedure. Therefore, if a stored procedure wants to conform to our
                      philosophy then it should include a call into the 'Clear' service request at the top of the
                      program. Alternatively this can be done through a common insert (see SERVICE_SETUP for example.)

                    - Service modules will use the SERVICE_SETUP insert and therefore automatically clear out any
                      error conditions that were set before.

    Parameters  :
        Service         [in] -- Name of the service being requested
        Param1-10   [in/out] -- Additional request parameter holders
        Response       [out] -- Response to be sent back to the Controller (MCP) or requesting procedure

    Metadata    :

    History     :   (Date, Initials, Notes)
        01/19/21    djs     Original programmer.

***********************************************************************************************************************/
#pragma precomp SRP_PreCompiler
#window NDW_GAN_RDS_PROD_DEMO

DECLARE SUBROUTINE Set_Property, End_Dialog, Send_Event, Set_Status, Center_Window, Post_Event, SRP_EditTable_Manager
DECLARE SUBROUTINE ErrMsg, Send_Message, Set_Property, Send_Event, Btree.Extract, obj_AppWindow, SRP_Show_Window
DECLARE SUBROUTINE obj_Notes, Security_Err_Msg, End_Window, Forward_Event, Start_Window, Create_Note, Excel_Services
DECLARE SUBROUTINE obj_RDS_Test, Print_Control_Plan, Print_RDS_Instruction, Send_Info, Post_Event, Database_Services
DECLARE SUBROUTINE obj_Run_Stage_Wfr, obj_WO_Wfr, obj_Run_Stage, GaN_Services, Utility, SRP_Stopwatch, COMM_NCR
DECLARE SUBROUTINE Dialog_Box, Get_Status, Logging_Services, Unlock, Error_Services, Disposition_Services
DECLARE SUBROUTINE Engineering_Services

DECLARE FUNCTION Get_Property, Get_Status, Dialog_Box, Utility, Center_Window, Popup, Collect.Ixvals, Security_Services
DECLARE FUNCTION Send_Message, Msg, Security_Check, RowExists,  NextKey, obj_React_Esc, obj_React_Run, Form_Services
DECLARE FUNCTION obj_RDS_Test, MemberOf, Create_Dialog, obj_Popup, obj_WO_Wfr, SRP_EditTable_Manager, Database_Services
DECLARE FUNCTION Obj_Run_Stage, Obj_Run_Stage_Wfr, Gan_Services, SRP_Array, DateTime, Error_Services, Obj_NCR
DECLARE FUNCTION Memory_Services, SRP_Get_Window_Rect, Excel_Services, Environment_Services, Logging_Services
DECLARE FUNCTION SRP_Date

$INSERT APPCOLORS
$INSERT RTI_STYLE_EQUATES
$INSERT EVENT_SETUP
$INSERT MSG_EQUATES
$INSERT LSL_USERS_EQU
$INSERT SECURITY_RIGHTS_EQU
$INSERT REACT_EVENT_EQUATES
$INSERT REACT_RUN_EQUATES
$INSERT WO_STEP_EQU
$INSERT WO_MAT_EQUATES
$INSERT WO_WFR_WIP_EQUATES
$INSERT EPI_SUSCEPTOR_EQUATES
$INSERT REACTOR_EQUATES
$INSERT POPUP_EQUATES
$INSERT TOOL_CLASS_EQUATES
$INSERT RUN_STAGE_EQUATES
$INSERT LOCATION_EQUATES
$INSERT RUN_STAGE_WFR_EQUATES
$INSERT WO_WFR_EQUATES
$INSERT SRP_POPUP_EQUATES
$INSERT LOGICAL
$INSERT WO_LOG_EQUATES
$INSERT GAN_PARAMS_EQUATES
$INSERT GAN_PARAM_CONFIG_EQUATES
$INSERT NCR_EQUATES

// Cassette / Wafer Action Combo Box Selections
EQU COMBO_X$            TO 1
EQU COMBO_START$        TO 2
EQU COMBO_STOP$         TO 3
EQU COMBO_COMP$         TO 4
EQU COMBO_PART$         TO 5

EQU COL$CHAR_WFR_ID		TO 1
EQU COL$SCRIBE			TO 2
EQU COL$SPLIT_BY		TO 3
EQU COL$SPLIT_DTM		TO 4
EQU COL$CURR_STAGE		TO 5
EQU COL$CHAR_DEST		TO 6
EQU COL$CHAR_TW_NO		TO 7
EQU COL$CHAR_WFR_STATUS	TO 8

EQU COL$CARR_SLOG_NO	TO 1
EQU COL$CARR_WFR_ID		TO 2
EQU COL$CARR_SCRIBE		TO 3
EQU COL$CARR_CHAR_FLAG	TO 4
EQU COL$CARR_NCR		TO 5
EQU COL$CARR_GRADE		TO 6

EQU COL$SIG_PROF		TO 1
EQU COL$SIGNATURE		TO 2
EQU COL$SIG_DTM			TO 3
EQU COL$STAGE_COMMENT	TO 4
EQU COL$STAGE_STATUS	TO 5

EQU COL$MET_STAGE       TO 1
EQU COL$MET_TOOL_ID     TO 2

// Disposition OLE Edit Table
EQU COL$DISP_SLOT        TO 1
EQU COL$DISP_WFR_ID      TO 2
EQU COL$DISP_SCRIBE      TO 3
EQU COL$DISP_GRADE       TO 4
EQU COL$DISP_REASON      TO 5
EQU COL$DISP_ROOT_CAUSE  TO 6
EQU COL$DISP_RDS_NCR     TO 7
EQU COL$DISP_WMO_NCR     TO 8
EQU COL$DISP_SHIP_ID     TO 9
EQU COL$DISP_RETAIN_BOX  TO 10
EQU COL$DISP_RETAIN_SLOT TO 11

// NCR OLE Edit Table
EQU COL$NCR_NO			 TO 1
EQU COL$NCR_STATUS		 TO 2
EQU COL$NCR_REJ_QTY		 TO 3
EQU COL$NCR_RESP		 TO 4
EQU COL$NCR_STAGE		 TO 5
EQU COL$NCR_LOSS_DESC	 TO 6
EQU COL$NCR_LOSS_COMM	 TO 7
EQU COL$NCR_FIN_SIG		 TO 8
EQU COL$NCR_FIN_SIG_DTM	 TO 9

EQU COL$SUSC_LOAD_WFR_ID        TO 6    ;* SUSC_LOAD control
EQU COL$SUSC_LOAD_WFR_SCRIBE	TO 7

EQU EDITABLE$			TO 4
EQU PROTECTED$			TO 8			;* Protected  - Edittable COLSTYLE constants
EQU MULTILINE_STYLE$	TO 512 			;* MultiLine Select
EQU LOCKED$				TO 8192
EQU DROPDOWN_STYLE$		TO 131072

LogPath     = Environment_Services('GetApplicationRootPath') : '\LogFiles\GaNWIP'
LogDate     = Oconv(Date(), 'D4/')
LogTime     = Oconv(Time(), 'MTS')
LogFileName = LogDate[7, 4] : '-' : LogDate[1, 2] : '-' : LogDate[4, 2] : ' GaN WIP Log.csv'
Headers     = 'Logging DTM' : @FM : 'RDS Key ID' : @FM : 'Username' : @FM : 'Notes'
objLog      = Logging_Services('NewLog', LogPath, LogFileName, CRLF$, Comma$, Headers, '', False$, False$)
LoggingDTM  = LogDate : ' ' : LogTime   ; // Logging DTM

SubclassInfo    = Form_Services('FindSubclassControl')
Subclass        = SubclassInfo<1>

// Update the arguments so that the OpenInsight OLE event will treate the ActiveX event as a native event handler.
If Event EQ 'OLE' then
    Transfer Event to OIEvent
    Transfer Param1 to Event
    Transfer Param2 to Param1
    Transfer Param3 to Param2
    Transfer Param4 to Param3
    Transfer Param5 to Param4
    Transfer Param6 to Param5
    Transfer Param7 to Param6
    Transfer Param8 to Param7
end

GoToEvent Event for CtrlEntId else
    // Event not implemented
end

Return EventFlow or 1

//-----------------------------------------------------------------------------
// EVENT HANDLERS
//-----------------------------------------------------------------------------

Event WINDOW.CREATE(CreateParam)
    
    GoSub PopulateControls
    SRP_Show_Window(@Window, '', 'C', 'C', 1, '', False$, False$, '', 1)
    
End Event


Event WINDOW.CLOSE(CancelFlag)
    
    obj_Notes('Inbox',@USER4)	;* Checks for any new messages
    
end event


Event WINDOW.OMNIEVENT(Message, Param1, Param2, Param3, Param4)
    
    Begin Case
        Case Message _EQC 'FillDispEditTable'
            GoSub FillDispEditTable
        Case Message _EQC 'FillNCREditTable'
            GoSub FillNCREditTable
    End Case
    
end event

Event CMB_GAN_RUN_ID.CHANGED(NewData)
    
    If NewData NE '' then
        GaNRunID          = NewData
        ReactorNo         = Get_Property(@Window, '@REACTOR')
        GaNRunInfo        = Gan_Services('GetRunInfo', GaNRunID)
        Recipe            = GaNRunInfo<1,1>
        SuscSerialNo      = GaNRunInfo<2,1>
        SPCWaferTrackPart = GaNRunInfo<6,1>
        Set_Property(@Window:'.EDL_WAFER_TRACK_PART', 'TEXT', SPCWaferTrackPart)
        Set_Property(@Window:'.OLE_REACTOR_EDT', "OLE.HeaderText[1; 2]", 'Reactor ':ReactorNo)
        WOLogOpenInsightPart = Get_Property(@Window:'.EPI_PART_NO', 'TEXT')
        Convert @Lower.Case to @Upper.Case in GaNRunID
        SchedWaferTrackPart  = Xlate('GAN_SCHEDULE', GaNRunID, 'WAFER_TRACK_PART', 'X')
        SchedOpenInsightPart = Xlate('GAN_SCHEDULE', GaNRunID, 'OPENINSIGHT_PART', 'X')
        // OpenInsightPart Verification
        If SchedOpenInsightPart NE WOLogOpenInsightPart then
            Set_Property(@Window:'.EPI_PART_NO', 'BACKCOLOR', RED$)
        end else
            Set_Property(@Window:'.EPI_PART_NO', 'BACKCOLOR', GREEN$)
        end
        // WaferTrackPart Verification
        If SchedWaferTrackPart NE SPCWaferTrackPart then
            Set_Property(@Window:'.EDL_WAFER_TRACK_PART', 'BACKCOLOR', RED$)
        end else
            Set_Property(@Window:'.EDL_WAFER_TRACK_PART', 'BACKCOLOR', GREEN$)
        end
        Set_Property(@Window, '@GANRUNINFO', GaNRunInfo)
        Set_Property(@Window : '.GAN_RECIPE', 'TEXT', Recipe)
        Set_Property(@Window : '.GAN_SUSC_SERIAL', 'TEXT', SuscSerialNo)
        GoSub VerifyRecipe   
    end
    
end event


Event CMB_GAN_ETCH_ID.CHANGED(NewData)
    
    ExternalEtchID = NewData
    Begin Case
        Case (ExternalEtchID _EQC 'No Etch Required')
            Set_Property(@Window : '.ETCH_RECIPE', 'TEXT', 'Not Applicable')
        Case (ExternalEtchID NE '') and (ExternalEtchID _NEC 'No Etch Required')
            GaNEtchInfo  = Gan_Services('GetRunInfo', ExternalEtchID)
            Recipe       = GaNEtchInfo<1,1>
            Set_Property(@Window : '.ETCH_RECIPE', 'TEXT', Recipe)
    End Case
    
end event


Event CTRL_PLAN.CLICK()
    
    PSNo = Get_Property(@WINDOW:'.PS_NO','DEFPROP')
    
    IF PSNo NE '' THEN
        Print_Control_Plan(PSNo)
    END
    
end event


Event WONO_BUTTON.CLICK()
    
    WONo = Get_Property(@WINDOW:'.WO_NO','DEFPROP')
    IF WONo NE '' THEN
        Start_Window('WO_LOG2',@WINDOW, WONo:'*CENTER', '', '' )	;* Added (copied from ViewPSN) -dkk 10/23/14
    END
    
end event


Event SEND_MSG.CLICK()
    
    CurrWindow	= @WINDOW
    CurrKey		= Get_Property(CurrWindow,'ID')
    
    IF CurrKey = '' THEN 
        MsgInfo = ''
        MsgInfo<MTEXT$> = 'You must have a record  present...' 
        MsgInfo<MICON$> = 'H'
        Msg( '', MsgInfo )
        RETURN
    END
    
    IF RowExists('REACT_RUN',CurrKey) THEN
        
        NoteID = NextKey('NOTES')
        obj_AppWindow('ViewRelated','NOTE_MESSAGE':@RM:NoteID:@RM:@WINDOW:@FM:CurrKey)
        
    END ELSE
        
        MsgInfo = ''
        MsgInfo<mtext$> = 'You must save this run data sheet first...' 
        MsgInfo<micon$> = 'H'
        Msg( '', MsgInfo )
    END
    
end event


Event PSNO_BUTTON.CLICK()
    
    PSNo = Get_Property(@WINDOW:'.PS_NO','DEFPROP')
    
    IF PSNo NE '' THEN
        Start_Window('PROD_SPEC',@WINDOW, PSNo:'*CENTER', '', '' )	;* Old style call to old style window
    END
    
end event


Event EDB_CASS_COMMENTS.CHANGED(NewData)
    
    NewComments = NewData
    OrigComments = Get_Property(@Window, '@COMMENTS')
    
    If NewComments NE OrigComments then
        Set_Property(@Window:'.PUB_SAVE_COMMENTS', 'ENABLED', True$)
    end else
        Set_Property(@Window:'.PUB_SAVE_COMMENTS', 'ENABLED', True$)
    end
    
end event


Event PUB_SAVE_COMMENTS.CLICK()
    
    RDSNo = Get_Property(@Window:'.RDS_NO', 'TEXT')
    CassComments = Get_Property(@Window:'.EDB_CASS_COMMENTS', 'TEXT')
    ReactRunRec = Database_Services('ReadDataRow', 'REACT_RUN', RDSNo)
    ReactRunRec<REACT_RUN_CASS_COMMENTS$> = CassComments
    Database_Services('WriteDataRow', 'REACT_RUN', RDSNo, ReactRunRec, True$, False$, True$)
    Set_Property(CtrlEntID, 'ENABLED', False$)
    Set_Property(@Window, '@COMMENTS', CassComments)
    
end event


Event PUB_UPDATE_EA_DATA.CLICK()
    
    RDSNo = Get_Property(@Window:'.RDS_NO', 'TEXT')
    Engineering_Services('UpdateAll', RDSNo)
    
end event


Event PUB_CLOSE_RDS.CLICK()
    
    RDSNo       = Get_Property(@Window:'.RDS_NO', 'TEXT')
    AllWfrsComp = GaN_Services('ReadyToClose', RDSNo)
    
    If AllWfrsComp EQ True$ then
        
        MsgText = 'Are you sure you want to close this RDS? Once closed an RDS cannot be re-opened.'
        MsgHead	= 'Warning'                
        Response = Msg(@WINDOW,'','YESNO','',MsgHead:@FM:MsgText)
        If Response EQ Yes$ then          
            GaN_Services('CloseRDS', RDSNo)
            GoSub FillDispEditTable
            GoSub EnableCloseRDSButton
            GoSub UpdateRDSStatus
            // Refresh the WO_PROD_GAN form if it is open to reflect possible updates to outbound cassettes.
            GaNProdVis = Get_Property('WO_PROD_GAN', 'VISIBLE')
            If GaNProdVis EQ True$ then Send_Event('WO_PROD_GAN', 'READ')
        end     
    end else
        Dialog_Box('NDW_WAFER_STATUS', @Window, RDSNo)
    end
    
end event


Event PUB_CREATE_NCR.CLICK()
    
    DispEDTCtrl  = @Window:".OLE_DISP_EDT"
    CarrSlotList = Get_Property(DispEDTCtrl, 'OLE.List')
    SelectedRows = Get_Property(DispEDTCtrl, "OLE.ColumnData[":COL$DISP_RDS_NCR:"]")
    
    CONVERT @VM TO @FM in SelectedRows
    NumWfrs		= DCount(SelectedRows, @FM)
    
    WONo		= Get_Property(@Window:'.WO_NO', 'TEXT')
    RDSNo		= Get_Property(@Window:'.RDS_NO', 'TEXT')
    Reactor		= Get_Property(@Window, '@REACTOR')
    RejWfrIDs	= ''
    RejSlotIDs	= ''
    
    GoodLines = 0
    FOR WfrIndex = 1 TO NumWfrs
        RowSelected = SelectedRows<WfrIndex>
        If RowSelected EQ True$ then
            SlotNo = CarrSlotList<WfrIndex, COL$DISP_SLOT>
            IF CarrSlotList<WfrIndex,COL$CARR_WFR_ID> NE '' Then
                GoodLines += 1
                RejWfrIDs<1,GoodLines> 		= CarrSlotList<WfrIndex,COL$DISP_WFR_ID>
                RejSlotIDs<1,GoodLines>		= RDSNo:'*':SlotNo
            END
        end        
    NEXT I
    
    ncrParms  = WONo:@RM
    ncrParms := '1':@RM
    ncrParms := '':@RM			;* Place holder for WO_MAT_CASS_NO
    ncrParms := RDSNo:@RM		;* Single RDS field 
    ncrParms := Reactor:@RM		;* Reactor No
    ncrParms := '':@RM			;* Loss Stage
    ncrParms := RejWfrIDs:@RM	;* WfrIDs			;* CarrWafer IDs
    ncrParms := RejSlotIDs:@RM	;* CarrSlotIDs		;* GaN PostEpi Carrier Slot ID	-> GaN non-characterization wafers
    ncrParms := '':@RM			;* CassSlotIDs		;* WOMat Cassette Slot ID		-> Rej from cassette
    ncrParms := ''				;* RunPocketZone	;* RPZ							-> Rej from susceptor
    
    Set_Status(0)
    NCRNo = obj_NCR('CreateWfr',ncrParms)		;* Create new NCR for this wafer/group of wafers
    
    IF Get_Status(errCode) THEN
        ErrMsg(errCode)
    end else
        // Mark wafers as scrap
        ReactRunRec = Database_Services('ReadDataRow', 'REACT_RUN', RDSNo)
        Grades      = Xlate('REACT_RUN', RDSNo, 'WFR_GRADES', 'X')
        WfrIDs      = ReactRunRec<REACT_RUN_IN_WFR_ID$>
        OutSlotIDs  = ReactRunRec<REACT_RUN_OUT_SLOT_ID$>
        For each RejWfrID in RejWfrIDs using @VM setting vPos
            Locate RejWfrID in WfrIDs using @VM setting wPos then
                Grades<0, wPos>     = 'Scrap'
                // Check if this wafer is in an outbound cassette. If so,
                // then remove it. Wafers cannot be shipped and scrapped at the same time.
                OutSlotID = OutSlotIDs<0, wPos>
                If OutSlotID NE '' then
                    // Remove wafer from outbound cassette
                    OutCass = Field(OutSlotID, '*', 1, 2)
                    GaN_Services('RemoveWfrsFromOutCass', OutCass, RejWfrID)
                end
            end
            WOWfrRec = Database_Services('ReadDataRow', 'WO_WFR', RejWfrID)
            WOWfrRec<WO_WFR_GRADE$> = 'Scrap'
            WOWfrRec<WO_WFR_RDS_NCR_NO$> = NCRNo
            Database_Services('WriteDataRow', 'WO_WFR', RejWfrID, WOWfrRec, True$, False$, True$)            
        Next RejWfrID
        
        Dialog_Box('NCR', @Window, NCRNo)
        PrevCursor  = Set_Property('SYSTEM', 'CURSOR', 'H')
        
        Def = ""
        Def<MCAPTION$>   = "Loading..."
        Def<MTYPE$>      = "G"
        Def<MEXTENT$>    = 100 ; // 100%
        Def<MTEXTWIDTH$> = 400
        Def<MCOL$>       = -2        ;* message h-pos in pixels, or -2 (center screen, the default), -1 (center parent)
        Def<MROW$>       = -2        ;* message v-pos in pixels
        MsgUp  = Msg(@Window, Def)
        Disposition_Services('AutoDispositionRun', RDSNo)        
        Msg(@Window, MsgUp, 20, MSGINSTUPDATE$)
        GoSub FillMetEditTable
        Msg(@Window, MsgUp, 40, MSGINSTUPDATE$)
        GoSub FillDispEditTable
        Msg(@Window, MsgUp, 60, MSGINSTUPDATE$)
        GoSub FillNCREditTable
        Msg(@Window, MsgUp, 80, MSGINSTUPDATE$)
        GoSub EnableCloseRDSButton
        Msg(@Window, MsgUp, 100, MSGINSTUPDATE$)
        Msg(@Window, MsgUp)
        
        PrevCursor  = Set_Property('SYSTEM', 'CURSOR', 'A')
    end
    
    GoSub EnableNCRButton
    
end event


Event PUB_LOT_ABORT.CLICK()
    
    RDSNo  = Get_Property(@Window : '.RDS_NO', 'TEXT')
    WfrIDs = Xlate('REACT_RUN', RDSNo, 'IN_WFR_ID', 'X')
    For each WfrID in WfrIDs using @VM setting vPos
        FormattedWfrID = WfrID
        Convert '*' to '.' in FormattedWfrID
        CurrStage = Gan_Services('GetCurrStage', WfrID)
        Begin Case
            Case ( (CurrStage EQ 'UV') or (CurrStage EQ 'UV_PRE') or (CurrStage EQ 'UV_PST') or (CurrStage EQ 'WARP') or (CurrStage EQ 'CAN') or (CurrStage EQ 'CAN_PRE') or (CurrStage EQ 'CAN_PST') )
                // Pre-SPLIT wafer
                // a) Skip any pre-SPLIT stages
                // b) Mark all wafers as "Disposition" at SPLIT stage
                Loop                
                    StageKey = RDSNo:'*':CurrStage:'*':FormattedWfrID
                    StageStatus = Xlate('RUN_STAGE_WFR', StageKey, 'STATUS', 'X')
                    Begin Case
                        Case StageStatus _EQC 'INIT'
                            // Skip stage - Moves wafer to next stage
                            Gan_Services('SkipWaferStage', RDSNo, WfrID, CurrStage)
                        Case StageStatus _EQC 'START'
                            // Stop wafer - Moves wafer to next stage
                            Gan_Services('StopWaferStage', RDSNo, WfrID, CurrStage)
                        Case StageStatus _EQC 'COMP'
                            Null                       
                        Case Otherwise$
                            Null
                    End Case                   
                    CurrStage = Gan_Services('GetCurrStage', WfrID)
                Until CurrStage _EQC 'SPLIT'
                Repeat
                If CurrStage _EQC 'SPLIT' then Gan_Services('DispositionWfr', RDSNo, WfrID)         
                
            Case CurrStage _EQC 'SPLIT'
                // SPLIT wafer - Simply disposition the wafer
                Gan_Services('DispositionWfr', RDSNo, WfrID)               
                
            Case (CurrStage _EQC 'XRD') or (CurrStage _EQC 'AFM')       | 
                or (CurrStage _EQC 'RPM')  or (CurrStage _EQC 'PR')    or (CurrStage _EQC 'SCOPE')     |
                or (CurrStage _EQC 'HALL') or (CurrStage _EQC 'EBEAM') or (CurrStage _EQC 'RTA_HALL')  |
                or (CurrStage _EQC 'RTA')   or (CurrStage _EQC 'HALL_PGAN') |
                or (CurrStage _EQC 'BV') or (CurrStage _EQC 'JV_XRD')
                // Post-SPLIT wafer
                // a) Currently running wafers will need to be stopped
                // b) All subsequent stages will need to be auto-skipped including unprescribed stages
                Loop
                    CurrQ = Gan_Services('GetWfrQueue', WfrID)
                    QType = Gan_Services('GetQueueType', CurrQ)
                    Begin Case
                        Case QType _EQC 'Location'
                            // Wafer not running on a tool. Skip the stage.
                            Gan_Services('SkipWaferStage', RDSNo, WfrID, CurrStage)
                        Case QType _EQC 'Tool'
                            // Wafer running on tool. Stop the stage.
                            Gan_Services('StopWaferStage', RDSNo, WfrID, CurrStage)                            
                    End Case                    
                    CurrStage = Gan_Services('GetCurrStage', WfrID)
                Until CurrStage _EQC 'DISP'
                Repeat
                
            Case CurrStage _EQC 'DISP'
                // Wafer is where it needs to be. Nothing needed to do.
                Null            
                
            Case Otherwise$
                ErrorMsg = 'Error aborting wafer ':WfrID:'. Contact FI team for assistance.'
                ErrMsg(ErrorMsg)
                
        End Case
        Disposition_Services('AutoDispositionWfr', WfrID)
    Next WfrID
    
    GoSub FillMetEditTable
    GoSub FillDispEditTable
    
end event


Event OLE_METROLOGY_EDT.OnButtonClick(Cell, Point, Button, Shift, Ctrl)
    
    Row       = Field(Cell, ';', 2)
    Col       = Field(Cell, ';', 1)
    SelStage     = Get_Property(CtrlEntID, "OLE.CellText[":Col:";":Row:"]")
    SelStageID   = GaN_Services('GetStageID', SelStage)
    
    If ( (SelStageID EQ 'UV') or (SelStageID EQ 'UV_PRE') or (SelStageID EQ 'UV_PST') or (SelStageID EQ 'WARP') or (SelStageID EQ 'WET_CLEAN') or (SelStageID EQ 'CAN_PRE') or (SelStageID EQ 'CAN_PST') ) then
        RDSNo            = Get_Property(@Window : '.RDS_NO', 'TEXT')
        ToolID           = Get_Property(@Window : '.OLE_METROLOGY_EDT', 'OLE.CellText[2; ':Row:']')
        IsSplit          = Gan_Services('IsCassSplit', RDSNo)
        Menu             = ""
        // Initialize menu options
        StartStatus      = False$
        StopStatus       = False$
        CompStatus       = False$
        SkipStatus       = False$
        UnskipStatus     = False$
        WfrIDs           = Xlate('REACT_RUN', RDSNo, 'IN_WFR_ID', 'X')
        WfrStages        = Xlate('REACT_RUN', RDSNo, 'WFR_STAGE', 'X')
        CanPreStartCnt   = 0
        CanPstStartCnt   = 0
        WetCleanStartCnt = 0
        NumWfrs          = Get_Property(@Window, '@NUMWFRS')
        // Check each wafer in the selected stage to determine which menu options should be enabled.
        For each WfrID in WfrIDs using @VM setting wPos
            Convert '*' to '.' in WfrID
            Begin Case                   
                Case SelStageID EQ 'UV_PRE'
                    // Check if UV stage exists
                    UVStageWfrKey = RDSNo:'*UV*':WfrID
                    If RowExists('RUN_STAGE_WFR', UVStageWfrKey) then
                        // Display this on the UV_PRE line
                        RunStageWfrKey = UVStageWfrKey
                    end else
                        RunStageWfrKey = RDSNo:'*':SelStageID:'*':WfrID
                    end
                Case SelStageID EQ 'CAN_PRE'
                    // Check if CAN stage exists
                    CanStageWfrKey = RDSNo:'*CAN*':WfrID
                    If RowExists('RUN_STAGE_WFR', CanStageWfrKey) then
                        // Display this on the CAN_PRE line
                        RunStageWfrKey = CanStageWfrKey
                    end else
                        RunStageWfrKey = RDSNo:'*':SelStageID:'*':WfrID
                    end    
                Case Otherwise$
                    RunStageWfrKey = RDSNo:'*':SelStageID:'*':WfrID                           
            End Case
            WfrStatus = Xlate('RUN_STAGE_WFR', RunStageWfrKey, 'STATUS', 'X')
            Begin Case
                Case WfrStatus EQ 'INIT' and ToolID NE 'Select'
                    StartStatus = True$
                    SkipStatus  = True$
                Case WfrStatus EQ 'INIT'
                    SkipStatus  = True$ 
                Case WfrStatus EQ 'START'
                    StopStatus  = True$
                Case WfrStatus EQ 'STOP'
                    CompStatus  = True$                        
                Case WfrStatus EQ 'SKIP'  
                    If IsSplit EQ False$ then UnskipStatus = True$
            End Case
        Next WfrID
        Menu<-1> = "START"   :@VM:"Start"                :@VM:StartStatus
        Menu<-1> = "STOP"    :@VM:"Stop"                 :@VM:StopStatus
        Menu<-1> = "COMP"    :@VM:"Complete"             :@VM:CompStatus
        Menu<-1> = "SKIP"    :@VM:"Skip"                 :@VM:SkipStatus
        Menu<-1> = "UNSKIP"  :@VM:"Unskip"               :@VM:UnskipStatus
        
        Send_Message(CtrlEntID, "OLE.ShowContextMenu", Point, Menu, Cell)
    end
    
end event


Event OLE_REACTOR_EDT.OnButtonClick(Cell, Point, Button, Shift, Ctrl)
    
    
    RecipeMismatch  = Get_Property(@Window, '@RECIPEMISMATCH')
    RDSNo           = Get_Property(@Window:'.RDS_NO', 'TEXT')
    Row             = Field(Cell, ';', 2)
    Col             = Field(Cell, ';', 1)
    Stage           = Get_Property(CtrlEntID, "OLE.CellText[":Col:";":Row:"]")
    StageID         = Gan_Services('GetStageID', Stage)
    If StageID NE 'ETCH' then
        Menu            = ""
        // Initialize all menu options to false until we deem they need to be turned on
        StartStatus     = False$
        StopStatus      = False$
        LoadStatus      = False$
        UnloadStatus    = False$
        CompStatus      = False$
        
        // Get inventory actions associated with this particular stage
        RDSNo       = Get_Property(@Window : '.RDS_NO', 'TEXT')
        RunStageKey = RDSNo:'*':StageID
        InvActions  = Xlate('RUN_STAGE', RunStageKey, 'SPEC_INV_ACTION', 'X')
        CurrStatus  = Xlate('RUN_STAGE', RunStageKey, 'STATUS', 'X')
        Begin Case
            Case StageID EQ 'G_RDS'
                // Need to check if GaN Run ID has been selected and if the GaN Recipe is populated.
                GaNRunID      = Get_Property(@Window:'.CMB_GAN_RUN_ID', 'TEXT')
                GaNRecipe     = Get_Property(@Window:'.GAN_RECIPE', 'TEXT')
                EtchKey       = RDSNo:'*ETCH'
                EtchStageComp = Xlate('RUN_STAGE', EtchKey, 'STATUS', 'X')
                If (GaNRunID NE '') and (GaNRecipe NE '') and (EtchStageComp _EQC 'COMP') and (CurrStatus NE 'COMP') then
                    CompStatus = True$
                end
            Case StageID EQ 'GROWTH'
                PrevStageKey = RDSNo:'*':'ETCH'
                PrevStageStatus  = Xlate('RUN_STAGE', PrevStageKey, 'STATUS', 'X')
                If PrevStageStatus EQ 'COMP' then
                    Begin Case
                        Case CurrStatus EQ 'START'
                            UnloadStatus = True$
                        Case CurrStatus EQ 'COMP'
                            Null
                        Case Otherwise$
                            LoadStatus = True$
                    End Case
                end            
            Case StageID EQ 'G_RATE'
                PrevStageKey = RDSNo:'*':'GROWTH'
                PrevStageStatus  = Xlate('RUN_STAGE', PrevStageKey, 'STATUS', 'X')
                If PrevStageStatus EQ 'COMP' and CurrStatus NE 'COMP' then CompStatus = True$
        End Case
        
        For each Action in InvActions using @VM
            Begin Case
                Case Action EQ "START"
                    Menu<-1> = "START"  :@VM:"Start"        :@VM:StartStatus
                Case Action EQ "STOP"
                    Menu<-1> = "STOP"   :@VM:"Stop"         :@VM:StopStatus
                Case Action EQ "LOAD"
                    Menu<-1> = "LOAD"   :@VM:"Load"         :@VM:LoadStatus
                Case Action EQ "UNLOAD"
                    Menu<-1> = "UNLOAD" :@VM:"Unload"       :@VM:UnloadStatus
            End Case
            
        Next Action
        
        If RecipeMismatch EQ True$ then CompStatus = False$
        If StageID NE 'GROWTH' then Menu<-1> = "COMP"   :@VM:"Complete" :@VM:CompStatus
        
        Send_Message(CtrlEntID, "OLE.ShowContextMenu", Point, Menu, Cell)
    end
    
end event


Event OLE_REACTOR_EDT.OnContextMenuClick(Item, UserData)
    
    Set_Property(@Window:'.OLE_METROLOGY_EDT'   , "OLE.Redraw", False$)
    Set_Property(@Window:'.OLE_DISP_STAGE_EDT'  , "OLE.Redraw", False$)
    
    CurrDTM          = DateTime()
    SelCell          = UserData
    Row              = Field(SelCell, ';', 2)
    RowData          = Get_Property(CtrlEntID, "OLE.RecordData[":Row:"]")
    ReactorStageCtrl = @Window:'.OLE_REACTOR_EDT'
    RDSNo            = Get_Property(@Window : '.RDS_NO', 'TEXT')   
    PSNo             = Xlate('REACT_RUN', RDSNo, 'PS_NO', 'X')
    NumWfrs          = DCount(InWfrIDs, @VM)
    StartCol         = 3
    EndCol           = StartCol + (NumWfrs - 1)
    WfrActions       = ''
    WfrStage         = RowData<1, 1>
    For Col = StartCol to EndCol
        WfrActions<1, -1> = RowData<1, Col>
    Next Col
    StageName        = Get_Property(CtrlEntID, 'OLE.CellText[1; ':Row:']')
    StageID          = Gan_Services('GetStageID', StageName)
    PRSStageKey      = PSNo :'*': StageID
    CurrAction       = Item
    RunStageKey      = RDSNo:'*':StageID
    RunStageRec      = Database_Services('ReadDataRow', 'RUN_STAGE', RunStageKey)
    WONo             = Get_Property(@Window:'.WO_NO', 'TEXT')
    CassNo           = Get_Property(@Window:'.CASS_NO', 'TEXT')
    WOMatKey         = WONo:'*':CassNo
    WOMatRec         = Database_Services('ReadDataRow', 'WO_MAT', WOMatKey)
    ReactRunRec      = Database_Services('ReadDataRow', 'REACT_RUN', RDSNo)
    
    Begin Case
        
        Case CurrAction EQ 'UNLOAD'
            
            Begin Case
                
                Case StageID EQ 'GROWTH'
                    
                    GaN_Services('UnloadSusceptor', RDSNo)
                    If Error_Services('NoError') then
                        Set_Property(ReactorStageCtrl, "OLE.CellText[2; ":Row:"]", 'Complete')
                        ReactRunRec = Database_Services('ReadDataRow', 'REACT_RUN', RDSNo)
                        CarrSlotIDs = ReactRunRec<REACT_RUN_CARR_WFR_ID$>
                        Scribes     = Xlate('REACT_RUN', RDSNo, 'WFR_SCRIBES', 'X')
                        Set_Property(@Window, '@CARRSLOTIDS', CarrSlotIDs)
                        Set_Property(@Window, '@SCRIBES', Scribes)
                        Engineering_Services('PostEARequest', RDSNo, 'GROWTH')
                        GaN_Services('GetGaNMetrologyData', RDSNo, 'GROWTH')
                        GaN_Services('GetGaNMetrologyData', RDSNo, 'TEMP')
                    end else
                        ErrorMessages = Error_Services('GetMessages')
                        Convert @FM to CRLF$ in ErrorMessages
                        ErrMsg(ErrorMesssages)
                    end
                    
            End Case
            
        Case CurrAction EQ 'LOAD'
            
            Begin Case
                
                Case StageID EQ 'GROWTH'
                    
                    RunStageKey = RDSNo:'*':StageID
                    Reactor = Get_Property(@Window, '@REACTOR')
                    // Need to sign 'LOAD' inventory action                   
                    LoadComplete = Dialog_Box('DIALOG_LOAD_SUSCEPTOR', @WINDOW, RDSNo:@FM:StageName:@FM:Reactor)
                    If LoadComplete EQ True$ then
                        // Update the UI
                        Set_Property(ReactorStageCtrl, "OLE.CellText[2; ":Row:"]", 'Load')
                        Scribes = Xlate('REACT_RUN', RDSNo, 'WFR_SCRIBES', 'X')
                        WfrIDs  = Xlate('REACT_RUN', RDSNo, 'IN_WFR_ID', 'X')
                        Set_Property(@Window, '@WFRIDS', WfrIDs)
                        HeaderTitles = "Stage":@VM:"Tool ID":@VM:Scribes
                        Set_Property(MetStageCtrl, "OLE.TitleList", HeaderTitles)
                        GaNProdVis = Get_Property('WO_PROD_GAN', 'VISIBLE')
                        If GaNProdVis EQ True$ then Send_Event('WO_PROD_GAN', 'READ')
                        GoSub FillDispEditTable
                        GoSub FillNCREditTable
                        GoSub ReadCurrParams
                        GoSub FillDispStageCtrl                        
                        GoSub ColorTabs
                        GoSub EnableTabs
                    end
                    
            End Case
            
            
        Case CurrAction EQ 'COMP'
            // 1. Save REACT_RUN record (Bind REACT_RUN (RDS) key id to GaN Run ID and to GaN Etch ID). Remove GaN Run ID and GaN Etch ID from their respective lists.
            // 2. Remove all wafers from previous Location/Tool ID queue if applicable
            // 3. Insert all wafers into Location/Tool ID queue (e.g. LOCATION*GCH*Q_ETCH/TOOL_WFR*R69)
            // 4. Add COMP_BY and COMP_DTM to RUN_STAGE record
            // 5. Update UI
            // 6. Refresh GaN Work Order status form
            Begin Case
                
                Case StageID EQ 'G_RDS'
                    GaNRunID            = Get_Property(@Window:'.CMB_GAN_RUN_ID', 'TEXT')
                    GanSuscSerial       = Get_Property(@Window:'.GAN_SUSC_SERIAL', 'TEXT')
                    GaNRunRecipe        = Get_Property(@Window:'.GAN_RECIPE', 'TEXT')
                    SPCWaferTrackPart   = Get_Property(@Window:'.EDL_WAFER_TRACK_PART', 'TEXT')
                    ReactRunRec         = Database_Services('ReadDataRow', 'REACT_RUN', RDSNo)
                    RunInfo             = Gan_Services('GetRunInfo', GaNRunID)
                    PocketNos           = RunInfo<3>
                    Scribes             = RunInfo<4>
                    SatSerialNos        = RunInfo<5>
                    // Save the Wafer Track Part from SPC into the WO_LOG record.
                    WOLogRec            = Database_Services('ReadDataRow', 'WO_LOG', WONo)
                    WOLogRec<WO_LOG_WAFER_TRACK_PART$> = SPCWaferTrackPart
                    Database_Services('WriteDataRow', 'WO_LOG', WONo, WOLogRec, True$, False$, True$)
                    // Just get the first reator in the list
                    InWfrIDs = ReactRunRec<REACT_RUN_IN_WFR_ID$>          
                    Reactor       = Get_Property(@Window, '@REACTOR')
                    ReactRunRec<REACT_RUN_GAN_RUN_ID$>      = GaNRunID
                    ReactRunRec<REACT_RUN_GAN_RECIPE$>      = GaNRunRecipe
                    ReactRunRec<REACT_RUN_GAN_SUSC_SERIAL$> = GanSuscSerial
                    ReactRunRec<REACT_RUN_PKT_SAT_ID$>      = SatSerialNos
                    ReactRunRec<REACT_RUN_REACTOR$>         = Reactor
                    GaN_Services('RemoveRunID', GaNRunID)
                    Database_Services('WriteDataRow', 'REACT_RUN', RDSNo, ReactRunRec, True$, False$, True$)                    
                    // 2 - N/A       
                    // 3 - Move cassette to GROWTH queue.
                    GrowthQ = 'GCH*Q_GROWTH'
                    GaN_Services('MoveCassToQueue', WOMatKey, GrowthQ)
                    WOMatRec = Database_Services('ReadDataRow', 'WO_MAT', WOMatKey)
                    WOMatRec<WO_MAT_LOC_DTM$, -1> = CurrDTM
                    WOMatRec<WO_MAT_LOC_BY$, -1>  = @User4
                    WOMatRec<WO_MAT_INV_LOC$, -1> = GrowthQ
                    Database_Services('WriteDataRow', 'WO_MAT', WOMatKey, WOMatRec, True$, False$, True$)
                    // 4
                    RunStageRec<RUN_STAGE_COMP_BY$>  = @User4
                    RunStageRec<RUN_STAGE_COMP_DTM$> = CurrDTM
                    RunStageRec<RUN_STAGE_STATUS$>   = 'COMP'
                    Database_Services('WriteDataRow', 'RUN_STAGE', RunStageKey, RunStageRec, True$, False$, True$)
                    // 5
                    Set_Property(ReactorStageCtrl, "OLE.CellText[2; ":Row:"]", 'Complete')
                    // 6
                    GaNProdVis = Get_Property('WO_PROD_GAN', 'VISIBLE')
                    If GaNProdVis EQ True$ then Send_Event('WO_PROD_GAN', 'READ')                   
                    
                Case StageID EQ 'G_RATE'
                    GaNRunID            = Get_Property(@Window:'.CMB_GAN_RUN_ID', 'TEXT')
                    RunInfo             = Gan_Services('GetRunInfo', GaNRunID)
                    PocketNos           = RunInfo<3>
                    Scribes             = RunInfo<4>
                    // 1. Remove all wafers from current Location queue
                    // 2. Lookup next Location queue
                    // 3. Insert all wafers into next Location queue                    
                    CurrLocQID = 'GCH*Q_RATE'
                    NextLocQID = 'GCH*UV_PRE_Q'
                    InWfrIDs   = ReactRunRec<REACT_RUN_IN_WFR_ID$>
                    For each WOWfrID in InWfrIDs using @VM setting vPos
                        If WOWfrID NE '' then
                            GaN_Services('RemoveWfrFromWIP', WOWfrID)
                            WOWfrRec = Database_Services('ReadDataRow', 'WO_WFR', WOWfrID)
                            LocDTMs  = WOWfrRec<WO_WFR_LOC_DTM$>
                            NextIndex = DCount(LocDTMs, @VM) + 1
                            WOWfrRec<WO_WFR_LOC_DTM$, NextIndex>    = CurrDTM
                            WOWfrRec<WO_WFR_LOC_BY$, NextIndex>     = @User4
                            WOWfrRec<WO_WFR_INV_LOC$, NextIndex>    = NextLocQID
                            WOWfrRec<WO_WFR_LOC_EVENT$, NextIndex>  = 'COMP'
                            WOWfrRec<WO_WFR_POCKET$>                = PocketNos<0, vPos>
                            WOWfrRec<WO_WFR_SCRIBE$>                = Scribes<0, vPos>
                            Database_Services('WriteDataRow', 'WO_WFR', WOWfrID, WOWfrRec, True$, False$, True$)
                            Gan_Services('MoveWfrToQueue', WOWfrID, NextLocQID)
                            
                        end
                    Next WOWfrID
                    // 3. Add COMP_BY and COMP_DTM to RUN_STAGE record
                    RunStageRec<RUN_STAGE_COMP_BY$>  = @User4
                    RunStageRec<RUN_STAGE_COMP_DTM$> = CurrDTM
                    RunStageRec<RUN_STAGE_STATUS$>   = 'COMP'
                    Database_Services('WriteDataRow', 'RUN_STAGE', RunStageKey, RunStageRec, True$, False$, True$)
                    // 4. Create prescribed RUN_STAGE_WFR records
                    Gan_Services('CreateAllRunStageWfr', RDSNo, 'SPLIT')
                    // 5. Update REACT_RUN form
                    Set_Property(ReactorStageCtrl, "OLE.CellText[2; ":Row:"]", 'Complete')
                    GoSub EnableRows
                    GoSub FillMetEditTable
                    GoSub FillMetHeader
                    GoSub FillDispStageHeader
                    
                    // 6. Refresh GaN Work Order status form if it is open
                    GaNProdVis = Get_Property('WO_PROD_GAN', 'VISIBLE')
                    If GaNProdVis EQ True$ then Send_Event('WO_PROD_GAN', 'READ')                   
                    
            End Case
    End Case
    
    Set_Property(@Window:'.OLE_METROLOGY_EDT'   , "OLE.Redraw", True$)
    Set_Property(@Window:'.OLE_DISP_STAGE_EDT'  , "OLE.Redraw", True$)
    
end event


Event OLE_METROLOGY_EDT.OnContextMenuClick(Item, UserData)
    
    PrevCursor  = Set_Property('SYSTEM', 'CURSOR', 'H')
    // Suppress redraw until all properties are set
    Set_Property(@Window:'.OLE_METROLOGY_EDT', "OLE.Redraw", False$)
    Set_Property(@Window:'.OLE_DISP_STAGE_EDT', "OLE.Redraw", False$)
    Set_Property(@Window:'.OLE_DISP_EDT', "OLE.Redraw", False$)
    Set_Property(@Window:'.OLE_NCR_EDT', "OLE.Redraw", False$)
    
    SelCell     = UserData
    Row         = Field(SelCell, ';', 2)
    RowData     = Get_Property(CtrlEntID, "OLE.RecordData[":Row:"]")
    RDSNo       = Get_Property(@Window : '.RDS_NO', 'TEXT')
    InWfrIDs    = Xlate('REACT_RUN', RDSNo, 'IN_WFR_ID', 'X')
    PSNo        = Xlate('REACT_RUN', RDSNo, 'PS_NO', 'X')
    NumWfrs     = DCount(InWfrIDs, @VM)
    StartCol    = 3
    EndCol      = StartCol + (NumWfrs - 1)
    WfrActions  = ''
    WfrStage    = RowData<1, 1>
    For Col = StartCol to EndCol
        WfrActions<1, -1> = RowData<1, Col>
    Next Col
    StageName       = Get_Property(@Window : '.OLE_METROLOGY_EDT', 'OLE.CellText[1; ':Row:']')
    StageID         = Gan_Services('GetStageID', StageName)
    ToolID          = Get_Property(@Window : '.OLE_METROLOGY_EDT', 'OLE.CellText[2; ':Row:']')
    If ToolID EQ 'Select' then ToolID = ''
    PRSStageKey     = PSNo :'*': StageName
    Action          = Item
    SpecToolClass   = Xlate('PRS_STAGE', PRSStageKey, 'PROC_TOOL_CLASS', 'X')
    ToolClassRec    = Database_Services('ReadDataRow', 'TOOL_CLASS', SpecToolClass)
    CurrDTM         = DateTime()
    NextStage       = Gan_Services('GetNextRxStage', RDSNo, StageID)
    
    Begin Case
        
        Case Action _EQC 'START'
            
            For each WfrID in InWfrIDs using @VM setting WaferIndex
                FormattedWfrID = WfrID
                Swap '*' with '.' in FormattedWfrID
                RunStageWfrKey = RDSNo:'*':StageID:'*':FormattedWfrID
                StageStatus    = Xlate('RUN_STAGE_WFR', RunStageWfrKey, 'STATUS', 'X')
                ReadyToStart   = GaN_Services('ReadyToStart', RDSNo, WfrID)
                If ( (StageStatus EQ 'INIT') and (ReadyToStart EQ True$) ) then GaN_Services('StartWaferStage', RDSNo, WfrID, StageID, ToolID)         
            Next WfrID
            
        Case Action _EQC 'STOP'
            
            Def = ""
            If StageID NE 'WET_CLEAN' then
                Def<MCAPTION$>   = "Stopping Stage and Retrieving SPC Data..."
            end else
                Def<MCAPTION$>   = "Stopping Stage..."
            end
            Def<MTYPE$>      = "G"
            Def<MEXTENT$>    = 100 ; // 100%
            Def<MTEXTWIDTH$> = 400
            Def<MCOL$>       = -2        ;* message h-pos in pixels, or -2 (center screen, the default), -1 (center parent)
            Def<MROW$>       = -2        ;* message v-pos in pixels
            MsgUp            = Msg(@Window, Def)
            
            NumWfrs      = Get_Property(@Window, '@NUMWFRS')
            Increment    = Int(100 / NumWfrs) + 1
            AutoComplete = False$
            For each WfrID in InWfrIDs using @VM setting WaferIndex
                FormattedWfrID = WfrID
                Swap '*' with '.' in FormattedWfrID
                RunStageWfrKey = RDSNo:'*':StageID:'*':FormattedWfrID
                StageStatus    = Xlate('RUN_STAGE_WFR', RunStageWfrKey, 'STATUS', 'X')
                If StageStatus EQ 'START' then
                    GaN_Services('StopWaferStage', RDSNo, WfrID, StageID)
                    If StageID NE 'WET_CLEAN' then GaN_Services('GetGaNMetrologyData', RDSNo, StageID, ToolID, WfrID)
                    If Error_Services('NoError') then AutoComplete = True$
                end                
                * update the gauge
                Msg(@Window, MsgUp, (Increment * WaferIndex), MSGINSTUPDATE$)                 
            Next WfrID                    
            Msg(@Window, MsgUp, 90, MSGINSTUPDATE$)        
            Msg(@Window, MsgUp, 100, MSGINSTUPDATE$)
            Msg(@Window, MsgUp)         ;* take down the gauge           
            
            If AutoComplete EQ True$ then
                Def = ""                
                Def<MCAPTION$>   = "Auto-Completing Stage..."
                Def<MTYPE$>      = "G"
                Def<MEXTENT$>    = 100 ; // 100%
                Def<MTEXTWIDTH$> = 400
                Def<MCOL$>       = -2        ;* message h-pos in pixels, or -2 (center screen, the default), -1 (center parent)
                Def<MROW$>       = -2        ;* message v-pos in pixels
                MsgUp            = Msg(@Window, Def)
                For each WfrID in InWfrIDs using @VM setting vPos                    
                    FormattedWfrID = WfrID
                    Swap '*' with '.' in FormattedWfrID
                    RunStageWfrKey = RDSNo:'*':StageID:'*':FormattedWfrID
                    StageStatus    = Xlate('RUN_STAGE_WFR', RunStageWfrKey, 'STATUS', 'X')                                     
                    If StageStatus EQ 'STOP' then GaN_Services('CompleteWaferStage', RDSNo, WfrID, StageID)
                    * update the gauge
                    Msg(@Window, MsgUp, (Increment * vPos), MSGINSTUPDATE$)  
                Next WfrID
                Msg(@Window, MsgUp, 90, MSGINSTUPDATE$)
                Engineering_Services('PostEARequest', RDSNo, StageID)
                If NextStage EQ 'SPLIT' then GaN_Services('SplitSelection', RDSNo)                
                Msg(@Window, MsgUp, 100, MSGINSTUPDATE$)
                Msg(@Window, MsgUp)         ;* take down the gauge
            end else
                ErrorMsg  = 'Warning: Auto-complete failed. Unable to find ':StageID:' data in SPC.':CRLF$
                ErrorMsg := 'Verify metrology data, then attempt to complete the stage again.'
                Error_Services('Add', ErrorMsg)
                ErrMsg(ErrorMsg)
            end
            
            If Error_Services('NoError') then Disposition_Services('AutoDispositionRun', RDSNo)
            
            GoSub ReadCurrParams
            GoSub FillDispStageCtrl
            GoSub ColorTabs
            GoSub FillDispEditTable
            
        Case Action _EQC 'COMP'
            
            NumWfrs      = Get_Property(@Window, '@NUMWFRS')
            Increment    = Int(100 / NumWfrs) + 1
            OkToComplete = False$
            If StageID NE 'WET_CLEAN' then 
                Def = ""
                Def<MCAPTION$>   = "Retrieving SPC Data..."
                Def<MTYPE$>      = "G"
                Def<MEXTENT$>    = 100
                Def<MTEXTWIDTH$> = 400
                Def<MCOL$>       = -2 ;* message h-pos in pixels, or -2 (center screen, the default), -1 (center parent)
                Def<MROW$>       = -2 ;* message v-pos in pixels
                MsgUp            = Msg(@Window, Def)               
                For each WfrID in InWfrIDs using @VM setting WaferIndex
                    FormattedWfrID = WfrID
                    Swap '*' with '.' in FormattedWfrID
                    RunStageWfrKey = RDSNo:'*':StageID:'*':FormattedWfrID
                    StageStatus    = Xlate('RUN_STAGE_WFR', RunStageWfrKey, 'STATUS', 'X')
                    If StageStatus EQ 'STOP' then
                        GaN_Services('GetGaNMetrologyData', RDSNo, StageID, ToolID, WfrID)
                        If Error_Services('NoError') then OkToComplete = True$
                    end                    
                    * update the gauge
                    Msg(@Window, MsgUp, (Increment * WaferIndex), MSGINSTUPDATE$)                                          
                Next WfrID
                Msg(@Window, MsgUp, 100, MSGINSTUPDATE$)
                Msg(@Window, MsgUp)         ;* take down the gauge
            end else
                OkToComplete = True$
            end
            
            If OkToComplete EQ True$ then
                Def = ""
                Def<MCAPTION$>   = "Completing Stage..."
                Def<MTYPE$>      = "G"
                Def<MEXTENT$>    = 100 ; // 100%
                Def<MTEXTWIDTH$> = 400
                Def<MCOL$>       = -2 ;* message h-pos in pixels, or -2 (center screen, the default), -1 (center parent)
                Def<MROW$>       = -2 ;* message v-pos in pixels
                MsgUp            = Msg(@Window, Def)
                
                For each WfrID in InWfrIDs using @VM setting vPos
                    FormattedWfrID = WfrID
                    Swap '*' with '.' in FormattedWfrID
                    RunStageWfrKey = RDSNo:'*':StageID:'*':FormattedWfrID
                    StageStatus    = Xlate('RUN_STAGE_WFR', RunStageWfrKey, 'STATUS', 'X')
                    If StageStatus EQ 'STOP' then GaN_Services('CompleteWaferStage', RDSNo, WfrID, StageID)
                    * update the gauge
                    Msg(@Window, MsgUp, (Increment * vPos), MSGINSTUPDATE$)  
                Next WfrID 
                If NextStage EQ 'SPLIT' then GaN_Services('SplitSelection', RDSNo)
                Msg(@Window, MsgUp, 90, MSGINSTUPDATE$)
                If Error_Services('NoError') then
                    Disposition_Services('AutoDispositionRun', RDSNo)
                    GoSub ReadCurrParams
                    GoSub FillDispStageCtrl
                    GoSub ColorTabs
                    GoSub FillDispEditTable
                end
                Engineering_Services('PostEARequest', RDSNo, StageID)
                Msg(@Window, MsgUp, 100, MSGINSTUPDATE$)
                Msg(@Window, MsgUp)         ;* take down the gauge
            end else
                ErrorMsg  = 'Warning: Complete stage failed. Unable to find ':StageID:' data in SPC.':CRLF$
                ErrorMsg := 'Verify metrology data, then attempt to complete the stage again.'
                Error_Services('Add', ErrorMsg)
                ErrMsg(ErrorMsg)
            end
            
        Case Action _EQC 'SKIP'
            
            For each WfrID in InWfrIDs using @VM setting vPos
                FormattedWfrID = WfrID
                Swap '*' with '.' in FormattedWfrID
                RunStageWfrKey = RDSNo:'*':StageID:'*':FormattedWfrID
                StageStatus    = Xlate('RUN_STAGE_WFR', RunStageWfrKey, 'STATUS', 'X')
                If StageStatus EQ 'INIT' then GaN_Services('SkipWaferStage', RDSNo, WfrID, StageID)                                                
            Next WfrID
            If NextStage EQ 'SPLIT' then
                Gan_Services('SplitSelection', RDSNo)
                If Error_Services('NoError') then 
                    Disposition_Services('AutoDispositionRun', RDSNo)
                    GoSub ReadCurrParams
                    GoSub FillDispStageCtrl
                    GoSub ColorTabs
                    GoSub FillDispEditTable
                end
            end
            
        Case Action _EQC 'UNSKIP'
            
            For each WfrID in InWfrIDs using @VM setting vPos
                FormattedWfrID = WfrID
                Swap '*' with '.' in FormattedWfrID
                RunStageWfrKey = RDSNo:'*':StageID:'*':FormattedWfrID
                StageStatus    = Xlate('RUN_STAGE_WFR', RunStageWfrKey, 'STATUS', 'X')
                If StageStatus EQ 'SKIP' then GaN_Services('UnskipWaferStage', RDSNo, WfrID, StageID)                             
            Next WfrID
            
    End Case
    GoSub FillMetEditTable
    // Re-enable redraw now that all properties are set
    Set_Property(@Window:'.OLE_METROLOGY_EDT', "OLE.Redraw", True$)
    Set_Property(@Window:'.OLE_DISP_STAGE_EDT', "OLE.Redraw", True$)
    Set_Property(@Window:'.OLE_DISP_EDT', "OLE.Redraw", True$)
    Set_Property(@Window:'.OLE_NCR_EDT', "OLE.Redraw", True$)   
    PrevCursor   = Set_Property('SYSTEM', 'CURSOR', PrevCursor)
    
end event


Event OLE_METROLOGY_EDT.OnClick(Cell, Point, Button, Shift, Ctrl)
    
    If Button _EQC 'Right' then
        Column          = Field(Cell, ';', 1, 1)
        Row             = Field(Cell, ';', 2, 1)
        PopupCtrl       = @Window : '.OLE_POPUP'
        AllowPopup      = False$
        PopupVisible    = Get_Property(PopupCtrl, 'OLE.Visible')
        If PopupVisible EQ True$ then
            GoSub DismissPopup
        end
        GoSub DisplayPopup
    end
    
end event


Event OLE_METROLOGY_EDT.OnHeaderDblClick(Cell, Point, Button, Shift, Ctrl)
    
    Col = Field(Cell, ';', 1, 1)
    If Col GT 3 then
        RDSNo       = Get_Property(@Window:'.RDS_NO', 'TEXT')
        WfrIDs      = Xlate('REACT_RUN', RDSNo, 'IN_WFR_ID', 'X')
        WfrIndex    = Col - 3 
        WfrID       = WfrIDs<0, WfrIndex>
        WfrComments = ''
        WfrComments = Xlate('WO_WFR', WfrID, 'COMMENTS', 'X')
        // Display wafer comments and allow user to edit/erase comments. 
        Response    = Dialog_Box('NDW_WFR_COMMENTS', @WINDOW, WfrComments)
        Save        = Response<1>
        NewComments = Response<2>
        
        If Save EQ True$ then
            // Insert comments into WO_WFR record
            WOWfrRec    = Database_Services('ReadDataRow', 'WO_WFR', WfrID)
            WOWfrRec<WO_WFR_COMMENTS$> = NewComments
            Database_Services('WriteDataRow', 'WO_WFR', WfrID, WOWfrRec, True$, False$, True$)
            ColNo = WfrIndex + 3
            Set_Property(CtrlEntID, "OLE.HeaderToolTip[":ColNo:";1]", NewComments)
            HeaderColors = Get_Property(CtrlEntID, "OLE.HeaderColors[":ColNo:";1]")
            If NewComments NE '' then
                // Set header to cyan so the user knows there's a comment                
                HeaderColors<2> = 'LightCyan'
                HeaderColors<4> = 'LightCyan'
            end else
                // Comment has been removed, so reset header colors back to default colors
                HeaderColors<2> = 'None'
                HeaderColors<4> = OI_HOT_BLUE$
            end
            Set_Property(CtrlEntID, "OLE.HeaderColors[":ColNo:";1]", HeaderColors)
        end
    end
    
end event


Event OLE_REACTOR_EDT.OnClick(Cell, Point, Button, Shift, Ctrl)
    
    If Button _EQC 'Right' then
        Column          = Field(Cell, ';', 1, 1)
        Row             = Field(Cell, ';', 2, 1)
        PopupCtrl       = @Window : '.OLE_POPUP'
        AllowPopup      = False$
        PopupVisible    = Get_Property(PopupCtrl, 'OLE.Visible')
        If PopupVisible EQ True$ then
            GoSub DismissPopup
        end
        GoSub DisplayPopup
    end
    
end event


Event PUB_IMPORT_MET_DATA.CLICK()
    
    Def = ""
    Def<MCAPTION$>   = "Importing..."
    Def<MTYPE$>      = "G"
    Def<MEXTENT$>    = 100 ; // 100%
    Def<MTEXTWIDTH$> = 400
    Def<MCOL$>       = -2        ;* message h-pos in pixels, or -2 (center screen, the default), -1 (center parent)
    Def<MROW$>       = -2        ;* message v-pos in pixels
    MsgUp  = Msg(@Window, Def)
    
    RDSNo           = Get_Property(@Window:'.RDS_NO', 'TEXT')
    MetStageCtrl    = @Window:'.OLE_METROLOGY_EDT'
    GaNParamKeys    = Xlate('REACT_RUN', RDSNo, 'GAN_PARAM_KEYS', 'X')
    MetStageList    = ''
    AllStageList    = Database_Services('ReadDataRow', 'APP_INFO', 'GAN_MET_STAGES')
    For each GaNParamKey in GaNParamKeys using @VM
        Stage = Field(GaNParamKey, '*', 2, 1)
        MetStageList<0, -1> = Stage
    Next GaNParamKey
    InWfrIDs        = Get_Property(@Window, '@WFRIDS')
    For each Stage in MetStageList using @VM       
        If ( (Stage EQ 'GROWTH') or (Stage EQ 'TEMP') ) then
            Gan_Services('GetGaNMetrologyData', RDSNo, Stage)
        end else
            Locate Stage in AllStageList using @FM setting Row then
                Msg(@Window, MsgUp, (Row * 5), MSGINSTUPDATE$)
                ToolType    = GaN_Services('GetStageID', Stage)                
                Tool        = Get_Property(@Window : '.OLE_METROLOGY_EDT', 'OLE.CellText[2; ':Row:']')
                WaferIndex  = 1 ; // Just use the first wafer's status to determine if the stage is complete.
                StageStatus = Get_Property(@Window : '.OLE_METROLOGY_EDT', 'OLE.CellText[':(WaferIndex + 2):'; ':Row:']')
                If ( ( (ToolType EQ 'UV') or (ToolType EQ 'UV_PRE') or (ToolType EQ 'UV_PST') or (ToolType EQ 'WARP') or (ToolType EQ 'CAN') or (ToolType EQ 'CAN_PRE') or (ToolType EQ 'CAN_PST') ) and (StageStatus EQ 'Complete') ) then         
                    Gan_Services('GetGaNMetrologyData', RDSNo, ToolType, Tool)
                end else
                    For each WfrID in InWfrIDs using @VM setting WaferIndex
                        StageStatus = Get_Property(@Window : '.OLE_METROLOGY_EDT', 'OLE.CellText[':(WaferIndex + 2):'; ':Row:']')
                        If StageStatus EQ 'Complete' then Gan_Services('GetGaNMetrologyData', RDSNo, ToolType, Tool, WfrID)
                    Next WfrID
                end
            end
        end
        
        
    Next Stage
    
    Disposition_Services('AutoDispositionRun', RDSNo)
    Msg(@Window, MsgUp, 90, MSGINSTUPDATE$)
    GoSub ReadCurrParams
    GoSub FillDispStageCtrl
    Msg(@Window, MsgUp, 95, MSGINSTUPDATE$)
    GoSub ColorTabs
    GoSub FillDispEditTable
    GoSub EnableCloseRDSButton
    Msg(@Window, MsgUp, 100, MSGINSTUPDATE$)
    Msg(@Window, MsgUp)         ;* take down the gauge
    
end event


Event OLE_METROLOGY_EDT.OnComboClicked(Cell, SelPos, Value)
    
    PrevCursor      = Set_Property('SYSTEM', 'CURSOR', 'H')
    Column          = Field(Cell, ';', 1, 1)
    Row             = Field(Cell, ';', 2, 1)
    MetStageCtrl    = @Window:'.OLE_METROLOGY_EDT'
    MetStageList    = Get_Property(MetStageCtrl, "OLE.ColumnData[1]")
    StageDesc       = MetStageList<0, Row>
    StageID         = GaN_Services('GetStageID', StageDesc)
    RDSNo           = Get_Property(@Window:'.RDS_NO', 'TEXT')
    WfrIDs          = Xlate('REACT_RUN', RDSNo, 'IN_WFR_ID', 'X')
    MetRowsEnabled  = Get_Property(@Window, '@METROWSENABLED')
    ColorArray      = 'None':@FM:'None':@FM:'None':@FM:'None':@FM:'None'
    ReactRunRec     = Database_Services('ReadDataRow', 'REACT_RUN', RDSNo)
    WfrStages       = ReactRunRec<REACT_RUN_WFR_STAGE$>
    UnRxStages      = ReactRunRec<REACT_RUN_UNPRESCRIBED_WFR_STAGE$>
    ToolID          = Get_Property(@Window : '.OLE_METROLOGY_EDT', 'OLE.CellText[2; ':Row:']')
    CurrDTM         = DateTime()
    WfrIndex        = Column - 2
    PartNo          = Get_Property(@Window:'.EPI_PART_NO', 'TEXT')
    Reactor         = Get_Property(@Window, '@REACTOR')
    RunID           = Get_Property(@Window:'.CMB_GAN_RUN_ID', 'TEXT')
    SelStage        = Get_Property(CtrlEntID, "OLE.CellText[":Column:";":Row:"]")
    ToolType        = GaN_Services('GetStageID', SelStage)
    Tool            = Get_Property(@Window : '.OLE_METROLOGY_EDT', 'OLE.CellText[2; ':Row:']')
    MetParameter    = ''
    Abort           = False$
    
    If Column EQ COL$MET_TOOL_ID then
        ToolID = Value
        // A tool ID has been selected.  Need to check all RUN_STAGE_WFR statuses. Tool IDs can only be updated if the
        // status is 'INIT' or if the stage is CAN.
        For each WfrID in WfrIDs using @VM setting vPos
            If WfrID NE '' then
                WfrIDFormatted = WfrID
                Swap '*' with '.' in WfrIDFormatted
                RunStageWfrKey = RDSNo:'*':StageID:'*':WfrIDFormatted
                If RowExists('RUN_STAGE_WFR', RunStageWfrKey) then
                    WfrStatus = Xlate('RUN_STAGE_WFR', RunStageWfrKey, 'STATUS', 'X')
                    If ( (WfrStatus EQ 'INIT') or (StageID EQ 'CAN') or (StageID EQ 'CAN_PRE') or (StageID EQ 'CAN_PST') ) then
                        Set_Property(MetStageCtrl, "OLE.CellProtection[":Column:";":Row:"]", "None")
                        RunStageWfrRec = Database_Services('ReadDataRow', 'RUN_STAGE_WFR', RunStageWfrKey)
                        RunStageWfrRec<RUN_STAGE_WFR_TOOL_ID$> = ToolID
                        Database_Services('WriteDataRow','RUN_STAGE_WFR',RunStageWfrKey,RunStageWfrRec,True$,False$,True$)
                    end
                end
            end
        Next WfrID
        MetRowsEnabled<Row> = True$
        Set_Property(@Window, '@METROWSENABLED', MetRowsEnabled)       
        
    end else
        
        Action = Value
        WfrID  = WfrIDs<0, WfrIndex> 
        Begin Case
            Case Action _EQC 'START'
                
                Gan_Services('StartWaferStage', RDSNo, WfrID, StageID, ToolID)        
                
            Case Action _EQC 'STOP'
                
                AutoComplete   = False$
                FormattedWfrID = WfrID
                Swap '*' with '.' in FormattedWfrID
                RunStageWfrKey = RDSNo:'*':StageID:'*':FormattedWfrID
                StageStatus    = Xlate('RUN_STAGE_WFR', RunStageWfrKey, 'STATUS', 'X')
                If StageStatus EQ 'START' then
                    GaN_Services('StopWaferStage', RDSNo, WfrID, StageID)
                    If StageID NE 'WET_CLEAN' then GaN_Services('GetGaNMetrologyData', RDSNo, StageID, ToolID, WfrID)
                    If Error_Services('NoError') then AutoComplete = True$
                end                
                
                If AutoComplete EQ True$ then                   
                    FormattedWfrID = WfrID
                    Swap '*' with '.' in FormattedWfrID
                    RunStageWfrKey = RDSNo:'*':StageID:'*':FormattedWfrID
                    StageStatus    = Xlate('RUN_STAGE_WFR', RunStageWfrKey, 'STATUS', 'X')                                     
                    If StageStatus EQ 'STOP' then GaN_Services('CompleteWaferStage', RDSNo, WfrID, StageID)
                    Engineering_Services('PostEARequest', RDSNo, StageID)
                    If NextStage EQ 'SPLIT' then GaN_Services('SplitSelection', RDSNo)                
                end 
                
            Case Action _EQC 'Complete'
                
                OkToComplete = False$
                If StageID NE 'WET_CLEAN' then 
                    FormattedWfrID = WfrID
                    Swap '*' with '.' in FormattedWfrID
                    RunStageWfrKey = RDSNo:'*':StageID:'*':FormattedWfrID
                    StageStatus    = Xlate('RUN_STAGE_WFR', RunStageWfrKey, 'STATUS', 'X')
                    If StageStatus EQ 'STOP' then
                        GaN_Services('GetGaNMetrologyData', RDSNo, StageID, ToolID, WfrID)
                        If Error_Services('NoError') then OkToComplete = True$
                    end                                                         
                end else
                    OkToComplete = True$
                end
                
                If OkToComplete EQ True$ then
                    FormattedWfrID = WfrID
                    Swap '*' with '.' in FormattedWfrID
                    RunStageWfrKey = RDSNo:'*':StageID:'*':FormattedWfrID
                    StageStatus    = Xlate('RUN_STAGE_WFR', RunStageWfrKey, 'STATUS', 'X')
                    If StageStatus EQ 'STOP' then GaN_Services('CompleteWaferStage', RDSNo, WfrID, StageID) 
                    Engineering_Services('PostEARequest', RDSNo, StageID)
                end else
                    ErrorMsg  = 'Warning: Complete stage failed. Unable to find ':StageID:' data in SPC.':CRLF$
                    ErrorMsg := 'Verify metrology data, then attempt to complete the stage again.'
                    Error_Services('Add', ErrorMsg)
                    ErrMsg(ErrorMsg)
                end
                
            Case Action _EQC 'SKIP'
                
                Gan_Services('SkipWaferStage', RDSNo, WfrID, StageID)          
                
            Case Action _EQC 'UNSKIP'
                
                Gan_Services('UnskipWaferStage', RDSNo, WFrID, StageID)       
                
            Case Action _EQC 'ADD'
                
                Gan_Services('AddWaferStage', RDSNo, WfrID, StageID, ToolID)
                
            Case Action _EQC 'REMOVE'
                
                Gan_Services('RemoveWaferStage', RDSNo, WfrID, StageID)
                
            Case Action _EQC 'CHARACTERIZE'
                
                If Not( Memberof(@User4, 'GAN_WIP_SUPERVISOR') ) then
                    Response    = Dialog_Box('NDW_VERIFY_USER', @Window, @User4 : @FM : 'GAN_WIP_SUPERVISOR')
                    Valid       = Response<1>
                end else
                    Valid       = True$
                end
                
                If Valid EQ True$ then
                    Gan_Services('CharacterizeWafer', RDSNo, WfrID)    
                end else
                    Abort  = True$
                end
                
            Case Action _EQC 'DISPOSITION'
                
                If Not( Memberof(@User4, 'GAN_WIP_SUPERVISOR') ) then
                    Response    = Dialog_Box('NDW_VERIFY_USER', @Window, @User4 : @FM : 'GAN_WIP_SUPERVISOR')
                    Valid       = Response<1>
                end else
                    Valid       = True$
                end
                
                If Valid EQ True$ then
                    Gan_Services('DispositionWfr', RDSNo, WfrID)                   
                end else
                    Abort  = True$
                end
                
            Case Action _EQC 'WITHDRAW'
                
                If Not( Memberof(@User4, 'GAN_WIP_SUPERVISOR') ) then
                    Response    = Dialog_Box('NDW_VERIFY_USER', @Window, @User4 : @FM : 'GAN_WIP_SUPERVISOR')
                    Valid       = Response<1>
                end else
                    Valid       = True$
                end
                
                If Valid EQ True$ then
                    Gan_Services('WithdrawWfr', RDSNo, WfrID)                 
                end else
                    Abort  = True$
                end
                
            Case Otherwise$
                
        End Case
        
    end
    
    If Error_Services('HasError') then
        Errmsg(Error_Services('GetMessage'))
    end else
        If Abort EQ False$ then
            CurrStage = Gan_Services('GetCurrStage', WfrID)
            If CurrStage _EQC 'DISP' then
                // Update the Disposition DTM for all wafers that have been through or are at disposition
                ReactRunRec = Database_Services('ReadDataRow', 'REACT_RUN', RDSNo)
                InWfrIDs = ReactRunRec<REACT_RUN_IN_WFR_ID$>                    
                For each WOWfrID in InWfrIDs using @VM setting vPos
                    ThisWOWfrRec = Database_Services('ReadDataRow', 'WO_WFR', WOWfrID)
                    LocDTMs      = ThisWOWfrRec<WO_WFR_LOC_DTM$>
                    LocQs        = ThisWOWfrRec<WO_WFR_INV_LOC$>
                    Locate 'GGR*Q_DISP' in LocQs using @VM setting vPos then
                        // Wafer has been dispositioned at some point, so update the disposition DTM
                        LocDTMs<0, vPos> = CurrDTM
                        ThisWOWfrRec<WO_WFR_LOC_DTM$> = LocDTMs
                        Database_Services('WriteDataRow', 'WO_WFR', WOWfrID, ThisWOWfrRec, True$, False$, True$)
                    end
                Next WOWfrID
                Set_Property(@Window:'.PUB_UPDATE_DISP', 'ENABLED', True$)
            end
            
            Disposition_Services('AutoDispositionRun', RDSNo)
            GoSub ReadCurrParams
            GoSub FillDispEditTable
            GoSub FillMetEditTable
            GoSub ColorTabs
            GoSub EnableCloseRDSButton
        end
    end
    
    PrevCursor = Set_Property('SYSTEM', 'CURSOR', 'A')
    
end event


Event OLE_DISP_EDT.OnCheckChanged(Cell, OldValue, NewValue)
    
    Col = Field(Cell, ';', 1, 1)
    Row = Field(Cell, ';', 2, 1)
    NCRButton = ''
    Begin Case    
        
        Case Col EQ COL$DISP_RDS_NCR
            // The checkbox is only used for creating NCRs. We don't need to save anything at this time.
            // Check (no pun intended) if any of the checkboxes in this column are True$. If so, then enable
            // the "Create NCR" button, otherwise disable it.
            GoSub EnableNCRButton
            
    End Case
    
end event


Event COMBO_PRIORITY.CHANGED(NewData)
    
    Priority    = NewData
    RDSNo       = Get_Property(@Window:'.RDS_NO', 'TEXT')
    ReactRunRec = Database_Services('ReadDataRow', 'REACT_RUN', RDSNo)
    ReactRunRec<REACT_RUN_RUN_PRI$> = Priority
    Database_Services('WriteDataRow', 'REACT_RUN', RDSNo, ReactRunRec, True$, False$, True$)
    
end event


Event CMB_GAN_ETCH_ID.DROPDOWN(EditLineText)
    
    /*
                If ETCH stage complete, then display dropdown of all external etch IDs bound to this RDS.
                If ETCH stage is not complete, then provide a popup of all available etch IDs and allow the user to select
                multiple external etch IDs to bind to the RDS    
                */
    RDSNo       = Get_Property(@Window:'.RDS_NO', 'TEXT')
    
    LogData     = ''
    LogData<1>  = OConv(Datetime(), 'DT')
    LogData<2>  = RDSNo                     
    LogData<3>  = @User4
    LogData<4>  = 'Begin dropdown event.'                  
    Logging_Services('AppendLog', objLog, LogData, @RM, @FM, True$)
    
    
    EtchStageKey    = RDSNo:'*ETCH'
    EtchStageStatus = Xlate('RUN_STAGE', EtchStageKey, 'STATUS', 'X')
    
    LogData<4>  = 'Etch Stage Status: ':EtchStageStatus                  
    Logging_Services('AppendLog', objLog, LogData, @RM, @FM, True$)
    
    If EtchStageStatus _NEC 'COMP' then
        // Open the External Etch Manager so that users can select one or more internal and external etch ID(s) to
        // bind to this RDS (REACT_RUN) record.
        Reactor = Get_Property(@Window, '@REACTOR')
        
        LogData<4>  = 'Reactor: ':Reactor                 
        Logging_Services('AppendLog', objLog, LogData, @RM, @FM, True$)
        
        If (Reactor NE '') then
            SelEtchIDs  = ''
            SelEtchIDs  = Dialog_Box('NDW_EXTERNAL_ETCH_MANAGER', @Window, Reactor)
            
            LogEtchIDs = SelEtchIDs
            Convert @FM to ',' in LogEtchIDs 
            LogData<4>  = 'Selected etch IDs: ':LogEtchIDs       
            Logging_Services('AppendLog', objLog, LogData, @RM, @FM, True$)
            // If SelEtchIDs is equal to False$ (0) then the user canceled the external etch selection process.
            If SelEtchIDs NE False$ then                   
                SelIntEtchIDs = SelEtchIDs<1>
                SelExtEtchIDs = SelEtchIDs<2>
                // Update RUN_STAGE record
                RunStageKey      = RDSNo:'*ETCH'
                RunStageRec      = Database_Services('ReadDataRow', 'RUN_STAGE', RunStageKey)
                If Error_Services('NoError') then
                    CurrDTM          = DateTime()
                    RunStageRec<RUN_STAGE_COMP_BY$>  = @User4
                    RunStageRec<RUN_STAGE_COMP_DTM$> = CurrDTM
                    RunStageRec<RUN_STAGE_STATUS$>   = 'COMP'
                    RunStageRec<RUN_STAGE_ETCH_IDS$> = SelIntEtchIDs
                    Database_Services('WriteDataRow', 'RUN_STAGE', RunStageKey, RunStageRec, True$, False$, True$)
                    If Error_Services('NoError') then
                        // Update REACT_RUN record
                        NumExtEtchIDs  = DCount(SelExtEtchIDs, @VM)
                        LastExtEtchID  = SelExtEtchIDs<0, NumExtEtchIDs>
                        ExtEtchRecipes = ''
                        Set_Property(@Window:'.CMB_GAN_ETCH_ID', 'LIST', SelExtEtchIDs)
                        Set_Property(@Window:'.CMB_GAN_ETCH_ID', 'SELPOS', -1)
                        Set_Property(@Window:'.CMB_GAN_RUN_ID', 'ENABLED', True$)              
                        For each ExtEtchID in SelExtEtchIDs using @VM setting vPos
                            If ExtEtchID _NEC 'No Etch Required' then
                                
                                LogData<4>  = 'Calling Gan_Services("GetRunInfo", ':ExtEtchID:').'
                                Logging_Services('AppendLog', objLog, LogData, @RM, @FM, True$)                               
                                GaNEtchInfo           = Gan_Services('GetRunInfo', ExtEtchID)
                                
                                If Error_Services('NoError') then
                                    LogData<4>  = 'Call to Gan_Services("GetRunInfo", ':ExtEtchID:') was successful.'
                                    Logging_Services('AppendLog', objLog, LogData, @RM, @FM, True$)
                                end else
                                    LogData<4>  = 'Error Calling Gan_Services("GetRunInfo", ':ExtEtchID:').'
                                    Logging_Services('AppendLog', objLog, LogData, @RM, @FM, True$)
                                end
                                
                                ExtEtchRecipes<0, -1> = GaNEtchInfo<1,1>
                                
                                LogData<4>  = 'Calling Gan_Services("ConsumeExtEtchID", ':ExtEtchID:').'
                                Logging_Services('AppendLog', objLog, LogData, @RM, @FM, True$)                                
                                GaN_Services('ConsumeExtEtchID', ExtEtchID)
                                
                                If Error_Services('NoError') then
                                    LogData<4>  = 'Call to Gan_Services("ConsumeExtEtchID", ':ExtEtchID:') was successful.'
                                    Logging_Services('AppendLog', objLog, LogData, @RM, @FM, True$)
                                end else
                                    ErrorMessage = Error_Services('GetMessage')
                                    LogData<4>  = 'Error Calling Gan_Services("ConsumeExtEtchID", ':ExtEtchID:'). Error message: ':ErrorMessage
                                    Logging_Services('AppendLog', objLog, LogData, @RM, @FM, True$)
                                end                                
                            end else
                                ExtEtchRecipes = 'Not Applicable'
                            end                       
                        Next ExtEtchID
                        LastExtEtchRecipe = ExtEtchRecipes<0, NumExtEtchIDs>
                        Set_Property(@Window:'.ETCH_RECIPE', 'TEXT', LastExtEtchRecipe)
                        ReactRunRec = Database_Services('ReadDataRow', 'REACT_RUN', RDSNo)
                        If Error_Services('NoError') then
                            ReactRunRec<REACT_RUN_GAN_ETCH_ID$>     = SelExtEtchIDs
                            ReactRunRec<REACT_RUN_GAN_ETCH_RECIPE$> = ExtEtchRecipes 
                            Database_Services('WriteDataRow', 'REACT_RUN', RDSNo, ReactRunRec, True$, False$, True$)
                            If Error_Services('NoError') then                                            
                                For each IntEtchID in SelIntEtchIDs using @VM setting vPos                                    
                                    LogData<4>  = 'Calling Gan_Services("ConsumeIntEtchID", ':IntEtchID:').'
                                    Logging_Services('AppendLog', objLog, LogData, @RM, @FM, True$)                                    
                                    GaN_Services('ConsumeIntEtchID', IntEtchID)
                                    
                                    If Error_Services('NoError') then
                                        LogData<4>  = 'Call to Gan_Services("ConsumeIntEtchID", ':IntEtchID:') was successful.'
                                        Logging_Services('AppendLog', objLog, LogData, @RM, @FM, True$)
                                    end else
                                        ErrorMessage = Error_Services('GetMessage')
                                        LogData<4>  = 'Error Calling Gan_Services("ConsumeIntEtchID", ':IntEtchID:'). Error message: ':ErrorMessage
                                        Logging_Services('AppendLog', objLog, LogData, @RM, @FM, True$)
                                    end
                                    
                                Next IntEtchID                               
                                // Update the UI
                                Row = 1 ; // Etch Configuration Row
                                Set_Property(@Window:'.OLE_REACTOR_EDT', "OLE.CellText[2; ":Row:"]", 'Complete')
                                Set_Property(@Window:'.CMB_GAN_RUN_ID', 'ENABLED', True$)
                            end else
                                ErrorMessage = Error_Services('GetMessage')
                                LogData<4>  = 'Error writing REACT_RUN record: ':RDSNo:'. Error message: ':ErrorMessage:'.'
                                Logging_Services('AppendLog', objLog, LogData, @RM, @FM, True$)
                            end
                            
                        end else
                            ErrorMessage = Error_Services('GetMessage')
                            LogData<4>  = 'Error reading REACT_RUN record: ':RDSNo:'. Error message: ':ErrorMessage:'.'
                            Logging_Services('AppendLog', objLog, LogData, @RM, @FM, True$)
                        end
                    end else
                        ErrorMessage = Error_Services('GetMessage')
                        LogData<4>  = 'Error writing RUN_STAGE record: ':RunStageKey:'. Error message: ':ErrorMessage:'.'
                        Logging_Services('AppendLog', objLog, LogData, @RM, @FM, True$)
                    end
                end else
                    ErrorMessage = Error_Services('GetMessage')
                    LogData<4>  = 'Error reading RUN_STAGE record: ':RunStageKey:'. Error message: ':ErrorMessage:'.'
                    Logging_Services('AppendLog', objLog, LogData, @RM, @FM, True$)
                end
            end
        end else
            ErrorMsg = 'Reactor number is missing. Unable to complete ETCH stage.'
            ErrMsg(ErrorMsg)
        end        
    end
    
    If Error_Services('NoError') then
        LogData<4>  = 'Dropdown event successful.'                  
        Logging_Services('AppendLog', objLog, LogData, @RM, @FM, True$)
    end else
        LogData<4>  = 'Error in dropdown event.'                  
        Logging_Services('AppendLog', objLog, LogData, @RM, @FM, True$)
    end
    
    LogData<4>  = 'End dropdown event.'                  
    Logging_Services('AppendLog', objLog, LogData, @RM, @FM, True$)
    
end event


Event OLE_TAB.SelChanged(Index, PrevIndex)
    
    GoSub FillDispStageCtrl
    
end event


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Internal GoSubs
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

Setup_OLE_Controls:
    
    NumReactorCols = 2
    NumReactorRows = 4
    NumMetCols     = 10
    NumMetRows     = 20
    NumDispCols    = 11
    NumDispRows    = 8
    NumNCRCols     = 9
    NumNCRRows     = 5
    
    ReactorCtrlList     = ''
    MetCtrlList         = ''
    DispCtrlList        = ''
    DispParamCtrlList   = 'LSL':@FM:'USL'
    ReactorToolIDArray  = ''
    MetToolIDArray      = ''
    GaNStageArray = Database_Services('ReadDataRow', 'APP_INFO', 'GAN_STAGES_DEMO')
    
    Set_Property(@Window, '@GAN_STAGES', GaNStageArray)
    ReactorStageIndex = 1
    MetStageIndex     = 1
    
    For each Row in GaNStageArray using @FM setting fPos
        StageDesc    = Row<0,2>
        ToolClassIDs = Row<0,3>
        RunType      = Row<0,5>
        Begin Case
            Case RunType EQ 'Reactor'                
                ReactorCtrlList<ReactorStageIndex> = StageDesc
                ReactorStageIndex += 1                
            Case RunType EQ 'Metrology'              
                MetCtrlList<MetStageIndex> = StageDesc
                TempArray = ''
                MetCtrlList<MetStageIndex, 2> = 'Select'
                For each ToolClassID in ToolClassIDs using @SVM setting svPos                    
                    ProdTools = 'Tool1':@VM:'Tool2'
                    Convert @VM to @STM in ProdTools
                    TempArray = SRP_Array('Join', TempArray, ProdTools, 'OR', @STM)                               
                Next ToolClassID
                If TempArray[-1, 1] EQ @STM then TempArray[-1, 1] = ''                
                MetToolIDArray<MetStageIndex> = TempArray
                MetStageIndex += 1      
        End Case
    Next Row 
    
    CarrSlotIDs  = 23:@VM:20:@VM:17:@VM:14:@VM:11:@VM:8:@VM:5:@VM:2
    Slots        = CarrSlotIDs
    NumWfrs      = DCount(Scribes, @VM)
    debug
    Set_Property(@Window, '@SCRIBES', Scribes)
    Set_Property(@Window, '@CARRSLOTIDS', CarrSlotIDs)
    Set_Property(@Window, '@NUMWFRS', NumWfrs)
    Set_Property(@Window, '@WFRIDS', WfrIDs)
    Set_Property(@Window, '@SLOTS', Slots)
    NumDummyWfrs = 0
    DummyPockets = ''
    NumEmptyWfrs = 0
    EmptyPockets = ''
    For each Scribe in Scribes using @VM setting vPos
        DummyID = GanRunID[1,7]:'D'
        EmptyID = GaNRunID[1,7]:'E'
        If Scribe[1,8] EQ DummyID then
            NumDummyWfrs += 1
            DummyPockets<1, vPos> = True$
        end
        If Scribe[1,8] EQ EmptyID then
            NumEmptyWfrs += 1
            EmptyPockets<1, vPos> = True$
        end
    Next Scribe
    Set_Property(@Window, '@DUMMYPOCKETS', DummyPockets)
    Set_Property(@Window, '@EMPTYPOCKETS', EmptyPockets)
    
    SuscUnloaded = False$
    If NumWfrs GT 0 then
        // Wafers have not yet been unloaded from the susceptor. We will use this flag to
        // deactivate various control elements.
        SuscUnloaded = True$
    end
    ReactorStageCtrl  = @Window:'.OLE_REACTOR_EDT'
    MetStageCtrl      = @Window:'.OLE_METROLOGY_EDT'
    DispCtrl          = @Window:'.OLE_DISP_EDT'
    NCRCtrl           = @Window:'.OLE_NCR_EDT'
    DispParamCtrl     = @Window:'.OLE_DISP_PARAM_EDT'
    
    HeaderFontArray   = 'Segoe UI':@SVM:8:@SVM:700
    ReactorDimArray   = NumReactorCols :@FM: NumReactorRows
    MetDimArray       = NumMetCols :@FM: NumMetRows
    DispDimArray      = NumDispCols :@FM: NumDispRows
    NCRDimArray       = NumNCRCols :@FM: NumNCRRows
    Set_Property(@Window, '@METDIMARRAY', MetDimArray)
    Set_Property(@Window, '@DISPDIMARRAY', DispDimArray)
    Set_Property(@Window, '@NCRDIMARRAY', NCRDimArray)
    
    Set_Property(ReactorStageCtrl, "OLE.CellFont[All; All]", 'Segoe UI':@SVM:8)
    Set_Property(ReactorStageCtrl, "OLE.Dimension", ReactorDimArray)
    Set_Property(ReactorStageCtrl, "OLE.CellFont[1;All]", HeaderFontArray)
    Set_Property(ReactorStageCtrl, "OLE.LIST", ReactorCtrlList)
    Set_Property(ReactorStageCtrl, "OLE.HeaderFont[All; 1]", HeaderFontArray)
    Set_Property(ReactorStageCtrl, "OLE.HeaderFont[1; All]", HeaderFontArray)
    
    Set_Property(MetStageCtrl, "OLE.CellFont[All; All]", 'Segoe UI':@SVM:8)
    Set_Property(MetStageCtrl, "OLE.Dimension", MetDimArray)
    Set_Property(MetStageCtrl, "OLE.CellFont[1;All]", HeaderFontArray)
    Set_Property(MetStageCtrl, "OLE.LIST", MetCtrlList)
    Set_Property(MetStageCtrl, "OLE.HeaderFont[All; 1]", HeaderFontArray)
    Set_Property(MetStageCtrl, "OLE.HeaderFont[1; All]", HeaderFontArray)
    
    Set_Property(DispCtrl, "OLE.CellFont[All; All]", 'Segoe UI':@SVM:8)
    Set_Property(DispCtrl, "OLE.Dimension", DispDimArray)
    Set_Property(DispCtrl, "OLE.HeaderFont[All; 1]", HeaderFontArray)
    Set_Property(DispCtrl, "OLE.HeaderFont[1; All]", HeaderFontArray)
    
    Set_Property(NCRCtrl, "OLE.CellFont[All; All]", 'Segoe UI':@SVM:8)
    Set_Property(NCRCtrl, "OLE.Dimension", NCRDimArray)
    Set_Property(NCRCtrl, "OLE.HeaderFont[All; 1]", HeaderFontArray)
    Set_Property(NCRCtrl, "OLE.HeaderFont[1; All]", HeaderFontArray)
    
    ScribesCopy = Scribes
    Convert @VM to '' in ScribesCopy
    HeaderTitles = "Stage":@VM:"Tool ID"
    ScribeHeaderTitles = ''
    If ScribesCopy NE '' then       
        For each Scribe in Scribes using @VM setting vPos
            SlotID                    = CarrSlotIDs<0, vPos>
            ScribeHeaderTitles<0, -1> = Scribe:' (':SlotID:')'
        Next Scribe
        HeaderTitles<0, -1> = ScribeHeaderTitles
        Set_Property(@Window, '@SCRIBE_HEADER_TITLES', ScribeHeaderTitles)
    end else
        DefWfrTitles = ''
        For WfrIndex = 1 to NumWfrs
            DefWfrTitles<1, -1> = 'Wafer ':WfrIndex
        Next WfrIndex
        HeaderTitles = "Stage":@VM:"Tool ID":@VM:DefWfrTitles
    end
    
    ReactorNo = Get_Property(@Window, '@REACTOR')
    ReactorHeaderTitles = "Stage":@VM:"Status"
    Set_Property(ReactorStageCtrl, "OLE.TitleList", ReactorHeaderTitles)
    Set_Property(ReactorStageCtrl, "OLE.HeaderMerge[1; 2]", 1:@FM:NumReactorRows)
    Set_Property(ReactorStageCtrl, "OLE.HeaderText[1; 2]", 'Reactor ':ReactorNo)
    Set_Property(ReactorStageCtrl, "OLE.HeaderAlignment[All; 1]", 'C':@FM:'C':@FM:'L')
    Set_Property(ReactorStageCtrl, "OLE.CellAlignment[All; All]", 'C':@FM:'C':@FM:'L')
    Set_Property(ReactorStageCtrl, "OLE.CellAlignment[1; All]", 'C':@FM:'L':@FM:'L')
    Set_Property(ReactorStageCtrl, "OLE.AllowDeletions", False$)
    Set_Property(ReactorStageCtrl, "OLE.AllowInserts", False$)
    
    Set_Property(MetStageCtrl, "OLE.TitleList", HeaderTitles)
    Set_Property(MetStageCtrl, "OLE.HeaderMerge[1; 2]", 1:@FM:NumMetRows)
    Set_Property(MetStageCtrl, "OLE.HeaderText[1; 2]", 'Metrology')
    Set_Property(MetStageCtrl, "OLE.HeaderAlignment[All; 1]", 'C':@FM:'C':@FM:'L')
    Set_Property(MetStageCtrl, "OLE.CellAlignment[All; All]", 'C':@FM:'C':@FM:'L')
    Set_Property(MetStageCtrl, "OLE.CellAlignment[1; All]", 'C':@FM:'L':@FM:'L')
    Set_Property(MetStageCtrl, "OLE.AllowDeletions", False$)
    Set_Property(MetStageCtrl, "OLE.AllowInserts", False$)
    
    DispHeaderTitles  = 'Slot':@VM:'Inbound':@VM:'Scribe':@VM:'Grade':@VM:'Reason':@VM:'Root Cause':@VM:'RDS NCR':@VM:'WMO NCR':@VM
    DispHeaderTitles := 'Outbound':@VM:'Retain Box':@VM:'Retain Slot'
    Set_Property(DispCtrl, "OLE.TitleList", DispHeaderTitles)
    Set_Property(DispCtrl, "OLE.HeaderText[1; 2]", 'Disposition')
    Set_Property(DispCtrl, "OLE.HeaderAlignment[All; 1]", 'C':@FM:'C':@FM:'L')
    Set_Property(DispCtrl, "OLE.CellAlignment[":COL$DISP_SLOT:"-":COL$DISP_GRADE:"; All]", 'C':@FM:'C':@FM:'L')
    Set_Property(DispCtrl, "OLE.CellAlignment[":COL$DISP_REASON:"-":COL$DISP_ROOT_CAUSE:"; All]", 'C':@FM:'L':@FM:'L')
    Set_Property(DispCtrl, "OLE.CellAlignment[":COL$DISP_RDS_NCR:"-":COL$DISP_RETAIN_SLOT:"; All]", 'C':@FM:'C':@FM:'L')
    Set_Property(DispCtrl, "OLE.AllowDeletions", False$)
    Set_Property(DispCtrl, "OLE.AllowInserts", False$)
    
    NCRHeaderTitles = 'NCR':@VM:'Status':@VM:'Qty':@VM:'Responsible':@VM:'Stage':@VM:'Loss Desc':@VM:'Loss Comments' |
    :@VM:'Signature':@VM:'Date & Time'
    Set_Property(NCRCtrl, "OLE.TitleList", NCRHeaderTitles)
    Set_Property(NCRCtrl, "OLE.HeaderMerge[1; 2]", 1:@FM:NumNCRRows)
    Set_Property(NCRCtrl, "OLE.HeaderText[1; 2]", 'Scrap')
    Set_Property(NCRCtrl, "OLE.HeaderAlignment[All; 1]", 'C':@FM:'C':@FM:'L')
    Set_Property(NCRCtrl, "OLE.CellAlignment[All; All]", 'C':@FM:'C':@FM:'L')
    Set_Property(NCRCtrl, "OLE.AllowDeletions", False$)
    Set_Property(NCRCtrl, "OLE.AllowInserts", False$)
    
    // Set default header colors
    HeaderColorArray    = ''
    HeaderColorArray<1> = 'Auto'
    HeaderColorArray<2> = 'None'
    HeaderColorArray<3> = 'None'
    HeaderColorArray<4> = OI_HOT_BLUE$
    HeaderColorArray<5> = False$
    Set_Property(ReactorStageCtrl, "OLE.HeaderColors[All; All]", HeaderColorArray)
    Set_Property(MetStageCtrl, "OLE.HeaderColors[All; All]", HeaderColorArray)
    Set_Property(DispCtrl, "OLE.HeaderColors[All; All]", HeaderColorArray)
    Set_Property(NCRCtrl, "OLE.HeaderColors[All; All]", HeaderColorArray)
    Set_Property(DispParamCtrl, "OLE.HeaderColors[All; All]", HeaderColorArray)
    
    // Set header tooltips (wafer comments)    
    For each WfrID in WfrIDs using @VM setting WfrIndex
        WfrComments = ''
        WfrComments = Xlate('WO_WFR', WfrID, 'COMMENTS', 'X')
        ColNo = WfrIndex + 3
        If WfrComments NE '' then
            Set_Property(MetStageCtrl, "OLE.HeaderToolTip[":ColNo:";1]", WfrComments)
            // Set header to light cyan so the user knows there's a comment
            HeaderColors = Get_Property(MetStageCtrl, "OLE.HeaderColors[":ColNo:";1]")
            HeaderColors<2> = 'LightCyan'
            HeaderColors<4> = 'LightCyan'
            Set_Property(MetStageCtrl, "OLE.HeaderColors[":ColNo:";1]", HeaderColors)
        end       
    Next WfrID
    
    // Qualify OLE events that we want to intercept
    Qualifier = ''
    Qualifier<1> = 1
    Qualifier<4> = 0 ; * process synchronously (i.e. immediately)
    Send_Message(ReactorStageCtrl,  'QUALIFY_EVENT', 'OLE.OnClick',             Qualifier)
    Send_Message(ReactorStageCtrl,  'QUALIFY_EVENT', 'OLE.OnButtonClick',       Qualifier)
    Send_Message(ReactorStageCtrl,  'QUALIFY_EVENT', 'OLE.OnContextMenuClick',  Qualifier)
    Send_Message(MetStageCtrl,      'QUALIFY_EVENT', 'OLE.OnClick',             Qualifier)
    Send_Message(MetStageCtrl,      'QUALIFY_EVENT', 'OLE.PosChanged',          Qualifier)
    Send_Message(MetStageCtrl,      'QUALIFY_EVENT', 'OLE.OnButtonClick',       Qualifier)
    Send_Message(MetStageCtrl,      'QUALIFY_EVENT', 'OLE.OnComboClicked',      Qualifier)
    Send_Message(MetStageCtrl,      'QUALIFY_EVENT', 'OLE.OnContextMenuClick',  Qualifier)
    Send_Message(MetStageCtrl,      'QUALIFY_EVENT', 'OLE.OnHeaderDblClick',    Qualifier)
    Send_Message(DispCtrl,          'QUALIFY_EVENT', 'OLE.OnCheckChanged',      Qualifier)
    Send_Message(DispCtrl,          'QUALIFY_EVENT', 'OLE.OnClick',             Qualifier)
    Send_Message(DispCtrl,          'QUALIFY_EVENT', 'OLE.OnContextMenuClick',  Qualifier)
    Send_Message(DispCtrl,          'QUALIFY_EVENT', 'OLE.OnComboClicked',      Qualifier)
    Send_Message(NCRCtrl,           'QUALIFY_EVENT', 'OLE.OnDblClick',          Qualifier)
    // Process BeforeUpdate event synchronously
    Qualifier<4> = 1
    Send_Message(DispCtrl,          'QUALIFY_EVENT', 'OLE.BeforeUpdate',        Qualifier)
    
    // Setup Tool ID and Wafer status/action combo boxes
    CellTypeArray = ""
    CellTypeArray<1>    = "Combo"
    CellTypeArray<2, 1> = ""
    CellTypeArray<2, 2> = "L"
    CellTypeArray<2, 3> = ''
    CellTypeArray<2, 4> = 1                          ;// Column 1 contains the values we care about
    CellTypeArray<2, 5> = 1                          ;// Auto fill on
    CellTypeArray<2, 6> = 0                          ;// Case sensitive on
    CellTypeArray<2, 7> = 10                         ;// 10 visible rows max
    CellTypeArray<2, 8> = 0                          ;// Don't fire the OnOptionClick
    CellTypeArray<2, 9> = 1                          ;// Reduce the list to partial matches
    CellTypeArray<2, 10> = 0                         ;// Only show the drop down when the user types
    CellTypeArray<2, 11> = 0                         ;// Do not use LIST Format
    CellTypeArray<2, 12> = 1                         ;// Autofill on Tool ID name
    CellTypeArray<2, 13> = 1                         ;// Hide dropdown when user clears cell
    CellTypeArray<2, 14> = 0                         ;// Let navigation keys show the drop down
    CellTypeArray<2, 15> = 0                         ;// Show the drop down regardless of the cell's contents
    CellTypeArray<2, 16> = 0                         ;// Show the drop down during autofill
    CellTypeArray<2, 17> = 1                         ;// Remove selection when user backspaces/deletes
    CellTypeArray<2, 18> = 0                         ;// Show Popup while in read only mode
    CellTypeArray<2, 19> = 1                         ;// Show Popup When Navigating
    CellTypeArray<2, 20> = 1                         ;// Always Tab Out on Enter
    CellTypeArray<2, 21> = -1                        ;// Always show the dropdown above when close to the screen bottom
    CellTypeArray<2, 23> = 1                         ;// Limit possible values to those in dropdown
    // Store this for later use elsewhere   
    Set_Property(@Window, '@COMBOBOX', CellTypeArray)
    
*    For RowIndex = 1 to NumMetRows
*        ThisComboArray = CellTypeArray
*        ThisComboArray<2, 3> = MetToolIDArray<RowIndex>
*        Set_Property(MetStageCtrl, "OLE.CellType[2; ":RowIndex:"]", ThisComboArray)
*    Next RowIndex
    
    // Cell selection style setup
    Set_Property(ReactorStageCtrl,  "OLE.ResetSelPos", False$)  ;// Prevent cell selection from being reset upon lost focus event
    Set_Property(MetStageCtrl,      "OLE.ResetSelPos", False$)
    Set_Property(DispCtrl,     "OLE.ResetSelPos", False$)
    Set_Property(NCRCtrl,           "OLE.ResetSelPos", False$)
    ReactorSelStyleArray    = Get_Property(ReactorStageCtrl, "OLE.SelectionStyle")
    ReactorSelStyleArray<8> = True$
    MetSelStyleArray        = Get_Property(MetStageCtrl, "OLE.SelectionStyle")
    MetSelStyleArray<8>     = True$                         ;// Keep cell highlighted when table loses focus
    DispSelStyleArray       = Get_Property(DispCtrl, "OLE.SelectionStyle")
    DispSelStyleArray<8>    = True$                         ;// Keep cell highlighted when table loses focus
    NCRSelStyleArray        = Get_Property(NCRCtrl, "OLE.SelectionStyle")
    NCRSelStyleArray<8>     = True$                         ;// Keep cell highlighted when table loses focus
    Set_Property(ReactorStageCtrl,  'OLE.SelectionStyle', ReactorSelStyleArray)
    Set_Property(MetStageCtrl,      'OLE.SelectionStyle', MetSelStyleArray)
    Set_Property(DispCtrl,     'OLE.SelectionStyle', DispSelStyleArray)
    Set_Property(NCRCtrl,           'OLE.SelectionStyle', MCRSelStyleArray)
    
    CellSelStyleArray    = ''
    CellSelStyleArray<1> = 'White'                      ;// Selected cell foreground color
    CellSelStyleArray<2> = OI_BLUE$                     ;// Selected cell background color
    CellSelStyleArray<3> = 'None'                       ;// Selected record (row) foreground color - none = default
    CellSelStyleArray<4> = OI_HOT_BLUE$                 ;// Selected record (row) background color
    CellSelStyleArray<5> = 'None'                       ;// Selected field (column) foreground color - none = default
    CellSelStyleArray<6> = OI_HOT_BLUE$                 ;// Selected field (column) background color
    Set_Property(ReactorStageCtrl,  'OLE.CellSelColors[2; All]', CellSelStyleArray)
    Set_Property(MetStageCtrl,      'OLE.CellSelColors[2-':NumDummyWfrs+2:'; All]', CellSelStyleArray)
    Set_Property(NCRCtrl,           'OLE.CellSelColors[All; All]', CellSelStyleArray)
    
    // Stage cell button style setup
    ButtonTypeArray       = ''
    ButtonTypeArray<1>    = 'Push Button'
    ButtonTypeArray<2>    = ''
    ButtonTypeArray<2, 1> = False$
    ButtonTypeArray<2, 2> = True$
    ButtonTypeArray<2, 3> = True$
    ButtonTypeArray<3>    = 'None'
    ButtonTypeArray<4>    = "Vertical(Gradient(":OI_HOT_BLUE$:", ":OI_HOT_BLUE$:"), Border(":OI_BLUE$:"))"
    ButtonTypeArray<5>    = "Vertical(Gradient(":OI_CLICK_BLUE$:", ":OI_CLICK_BLUE$:"), Border(":OI_BLUE$:"))"
    ButtonTypeArray<6>    = 'OD'
    ButtonTypeArray<7>    = 'None'
    Set_Property(ReactorStageCtrl, "OLE.CellType[1; All]", ButtonTypeArray)
    Set_Property(MetStageCtrl, "OLE.CellType[1; All]", ButtonTypeArray)
    
    MetRowsEnabled = ''
    For RowIndex = 1 to NumMetRows
        MetRowsEnabled<RowIndex> = False$
    Next RowIndex
    
    // Get associated run stage keys and check them for assigned Tool IDs. If Tool ID is
    // set, then set the Tool ID combo box selection accordingly.
    ReactorStageList    = Get_Property(ReactorStageCtrl, "OLE.ColumnData[1]")
    MetStageList        = Get_Property(MetStageCtrl, "OLE.ColumnData[1]")
    ReactorStageIDList  = ''
    MetStageIDList      = ''
    For each StageDesc in ReactorStageList using @VM setting vPos
        ReactorStageIDList<1, vPos> = 'R-STAGE0':vPos
    Next StageDesc
    For each StageDesc in MetStageList using @VM setting vPos
        MetStageIDList<1, vPos> = Gan_Services('GetStageID', StageDesc)
    Next StageDesc
    Set_Property(@Window, '@METSTAGEIDLIST', MetStageIDList)
*    RunStageKeys = ReactRunRec<REACT_RUN_RUN_STAGE_KEY$>
*    MetStages    = ReactRunRec<REACT_RUN_WFR_STAGE$>
    Set_Property(@Window, '@METTOOLIDARRAY', MetToolIDArray)
    
    // Protect and color dummy and empty wafer columns
    ColorArray = @FM:'OD'
    CellColorArray = 'None':@FM:'None':@FM:'None':@FM:'None':@FM:'None'
    For each Pocket in DummyPockets using @VM setting vPos
        If Pocket EQ True$ then
            ColNo = vPos + 2
            Set_Property(MetStageCtrl,"OLE.CellProtection[":ColNo:"; All]", "None")
            Set_Property(MetStageCtrl,"OLE.CellColors[":ColNo:"; All]", ColorArray)
            Set_Property(MetStageCtrl,"OLE.ColumnData[":ColNo:"]", '')
            Set_Property(MetStageCtrl,"OLE.HeaderColors[":ColNo+1:"; 1]", ColorArray)
        end
    Next Pocket
    
    For each Pocket in EmptyPockets using @VM setting vPos
        If Pocket EQ True$ then
            ColNo = vPos + 2
            Set_Property(MetStageCtrl,"OLE.CellProtection[":ColNo:"; All]", "None")
            Set_Property(MetStageCtrl,"OLE.CellColors[":ColNo:"; All]", ColorArray)
            Set_Property(MetStageCtrl,"OLE.ColumnData[":ColNo:"]", '')
            Set_Property(MetStageCtrl,"OLE.HeaderColors[":ColNo+1:"; 1]", ColorArray)
        end
    Next Pocket
    
    // Protect and color N/A wafer columns
    If NumWfrs LT 8 then         ; // 8 wafers make a full cassette in GaN       
        StartCol = NumWfrs + 3  ; // Must add the three columns before the wafer columns 
        Set_Property(MetStageCtrl,"OLE.CellProtection[":StartCol:"-":NumMetCols:"; All]", "None")
        Set_Property(MetStageCtrl,"OLE.CellColors[":StartCol:"-":NumMetCols:"; All]", ColorArray)
        Set_Property(MetStageCtrl,"OLE.ColumnData[":StartCol:"-":NumMetCols:"]", '')
        Set_Property(MetStageCtrl,"OLE.HeaderColors[":StartCol+1:"-":NumMetCols+1:"; 1]", ColorArray)       
    end else
        StartCol = 3
        Set_Property(MetStageCtrl,"OLE.CellProtection[":StartCol:"-":NumMetCols:"; All]", "None")
        Set_Property(MetStageCtrl,"OLE.CellColors[":StartCol:"-":NumMetCols:"; All]", CellColorArray)
        Set_Property(MetStageCtrl,"OLE.ColumnData[":StartCol:"-":NumMetCols:"]", '')
        Set_Property(MetStageCtrl,"OLE.HeaderColors[":StartCol+1:"-":NumMetCols+1:"; 1]", CellColorArray)
    end
    // Get and set each cassette's current status for each reactor stage
    // Cassette level (RUN_STAGE)
    For each Stage in ReactorStageIDList using @VM setting StageIndex
        DispStatus = 'Complete'
        Set_Property(ReactorStageCtrl, "OLE.CellText[2; ":StageIndex:"]", DispStatus)
        Set_Property(ReactorStageCtrl, "OLE.CellProtection[2; ":StageIndex:"]", "None")
    Next Stage
    // Get and set each wafer's current status for each stage within the Metrology and Disposition edit tables.
    GoSub FillMetEditTable   
    GoSub SetupDispEDT
    GoSub SetupTabCtrl
    GoSub SetupDispStageCtrl
    GoSub ReadCurrParams
    GoSub FillDispStageCtrl
    GoSub ColorTabs
    GoSub EnableTabs
    
    //////////////////////////////////// Code below here only runs once //////////////////////////////////////////
    
    FirstPassComp = Get_Property(@Window, '@FIRSTPASS')
    
    If FirstPassComp EQ '' or FirstPassComp EQ False$ then
        
        // Color headers
        Set_Property(MetStageCtrl, "OLE.HeaderColors[All; 1]", @FM:"{200, 200, 200}")
        
        Set_Property(@Window, '@FIRSTPASS', True$)
        
        // Disable resizing of the header row and header column
        // Resize header column to fit contents
        HeaderRowArray = Get_Property(MetStageCtrl, "OLE.HeaderRow[1]")
        HeaderColArray = Get_Property(MetStageCtrl, "OLE.HeaderColumn[1]")
        HeaderRowArray<3> = False$
        HeaderColArray<1> = 80
        HeaderColArray<3> = False$
        Set_Property(MetStageCtrl, "OLE.HeaderColumn[1]", HeaderColArray)
        Set_Property(MetStageCtrl, "OLE.HeaderRow[1]", HeaderRowArray)
        // Disable resizing of columns as there is no need for this on this form
        StageColSize = Get_Property(MetStageCtrl, "OLE.DataColumn[1]")
        StageColSize<3> = False$
        Set_Property(MetStageCtrl, "OLE.DataColumn[All]", StageColSize)
        // Resize the stage column to fit stage descriptions
        StageColSize<1> = 186
        Set_Property(MetStageCtrl, "OLE.DataColumn[1]", StageColSize)
        WfrColSize = Get_Property(MetStageCtrl, "OLE.DataColumn[3]")
        WfrColSize<1> = 96
        Set_Property(MetStageCtrl, "OLE.DataColumn[3-10]", WfrColSize)
        // Disable resizing of rows as there is no need for this on this form
        RowSizeProps = Get_Property(MetStageCtrl, "OLE.DataRow[1]")
        RowSizeProps<3> = False$
        Set_Property(MetStageCtrl, "OLE.DataRow[All]", RowSizeProps)
        
        // Disable resizing of the header row and header column
        // Resize header column to fit contents
        HeaderRowArray = Get_Property(ReactorStageCtrl, "OLE.HeaderRow[1]")
        HeaderColArray = Get_Property(ReactorStageCtrl, "OLE.HeaderColumn[1]")
        HeaderRowArray<3> = False$
        HeaderColArray<1> = 80
        HeaderColArray<3> = False$
        Set_Property(ReactorStageCtrl, "OLE.HeaderColumn[1]", HeaderColArray)
        Set_Property(ReactorStageCtrl, "OLE.HeaderRow[1]", HeaderRowArray)
        // Disable resizing of columns as there is no need for this on this form
        StageColSize = Get_Property(ReactorStageCtrl, "OLE.DataColumn[1]")
        StageColSize<3> = False$
        Set_Property(ReactorStageCtrl, "OLE.DataColumn[All]", StageColSize)
        // Resize the stage column to fit stage descriptions
        StageColSize<1> = 186
        Set_Property(ReactorStageCtrl, "OLE.DataColumn[1]", StageColSize)
        // Disable resizing of rows as there is no need for this on this form
        RowSizeProps = Get_Property(ReactorStageCtrl, "OLE.DataRow[1]")
        RowSizeProps<3> = False$
        Set_Property(ReactorStageCtrl, "OLE.DataRow[All]", RowSizeProps)
        
        // Color headers
        Set_Property(ReactorStageCtrl, "OLE.HeaderColors[All; 1]", @FM:"{200, 200, 200}")
        
        //////////////////////////////////// Setup NCR OLE Edit Table //////////////////////////////////////////////
        
        // Disable resizing of the header row and header column
        // Resize header column to fit contents
        HeaderRowArray = Get_Property(NCRCtrl, "OLE.HeaderRow[1]")
        HeaderColArray = Get_Property(NCRCtrl, "OLE.HeaderColumn[1]")
        HeaderRowArray<3> = False$
        HeaderColArray<1> = 80
        HeaderColArray<3> = False$
        Set_Property(NCRCtrl, "OLE.HeaderColumn[1]", HeaderColArray)
        Set_Property(NCRCtrl, "OLE.HeaderRow[1]", HeaderRowArray)
        // Disable resizing of columns as there is no need for this on this form
        ColSize = Get_Property(NCRCtrl, "OLE.DataColumn[1]")
        ColSize<3> = False$
        ColSize<1> = 56
        Set_Property(NCRCtrl, "OLE.DataColumn[":COL$NCR_NO:"]", ColSize)
        ColSize<1> = 45
        Set_Property(NCRCtrl, "OLE.DataColumn[":COL$NCR_STATUS:"]", ColSize)
        ColSize<1> = 35
        Set_Property(NCRCtrl, "OLE.DataColumn[":COL$NCR_REJ_QTY:"]", ColSize)
        ColSize<1> = 90
        Set_Property(NCRCtrl, "OLE.DataColumn[":COL$NCR_RESP:"]", ColSize)
        ColSize<1> = 58
        Set_Property(NCRCtrl, "OLE.DataColumn[":COL$NCR_STAGE:"]", ColSize)
        ColSize<1> = 140
        Set_Property(NCRCtrl, "OLE.DataColumn[":COL$NCR_LOSS_DESC:"]", ColSize)
        ColSize<1> = 173
        Set_Property(NCRCtrl, "OLE.DataColumn[":COL$NCR_LOSS_COMM:"]", ColSize)
        ColSize<1> = 100
        Set_Property(NCRCtrl, "OLE.DataColumn[":COL$NCR_FIN_SIG:"]", ColSize)
        ColSize<1> = 120
        Set_Property(NCRCtrl, "OLE.DataColumn[":COL$NCR_FIN_SIG_DTM:"]", ColSize)
        
        // Disable resizing of rows as there is no need for this on this form
        RowSizeProps = Get_Property(NCRCtrl, "OLE.DataRow[1]")
        RowSizeProps<3> = False$
        Set_Property(NCRCtrl, "OLE.DataRow[All]", RowSizeProps)   
        Set_Property(NCRCtrl, "OLE.CellProtection[":COL$NCR_NO:"-":COL$NCR_FIN_SIG_DTM:"; All]", 'None')
        
        // Color headers
        Set_Property(NCRCtrl, "OLE.HeaderColors[All; 1]", @FM:"{200, 200, 200}")
        // Set Loss Comments column to autosized so that the table resizes when scrollbars are necessary
        ColArray = Get_Property(NCRCtrl, "OLE.DataColumn[":COL$NCR_LOSS_COMM:"]")
        ColArray<4> = True$
        Set_Property(NCRCtrl, "OLE.DataColumn[":COL$NCR_LOSS_COMM:"]", ColArray)
    end
    
return


FillMetEditTable:
    
    RDSNo          = Get_Property(@Window:'.RDS_NO', 'TEXT')
    WfrIDs         = Get_Property(@Window, '@WFRIDS')
    NumWfrs        = Get_Property(@Window, '@NUMWFRS')
    MetStageIDList = Get_Property(@Window, '@METSTAGEIDLIST')
*    If WfrIDs EQ '' then
*        WfrIDs = Xlate('REACT_RUN', RDSNo, 'IN_WFR_ID', 'X')
*        Set_Property(@Window, '@WFRIDS', WfrIDs)
*    end
*    If NumWfrs EQ '' then
*        NumWfrs = DCount(WfrIDs, @VM)
*        Set_Property(@Window, '@NUMWFRS')
*    end
    
    GoSub AutoSelectToolID
    MetStageCtrl      = @Window:'.OLE_METROLOGY_EDT'
    MetRowsEnabled    = Get_Property(@Window, '@METROWSENABLED')
    CellTypeArray     = Get_Property(@Window, '@COMBOBOX')
    ColorArray        = @FM:'OD'
    CellColorArray    = 'None':@FM:'None':@FM:'None':@FM:'None':@FM:'None'
    EnabledColorArray = CellColorArray
    // Get and set each wafer's current status for each stage within the Metrology edit table.
    EndCol = NumWfrs + 2
    For each Stage in MetStageIDList using @VM setting StageIndex          
        For each WfrID in WfrIDs using @VM setting WfrIndex
            BackgroundColor = 'None'
            CurrWfrRow  = StageIndex
            CurrWfrCol  = WfrIndex + 2
            
            ThisComboArray = CellTypeArray            
            
            DispStatus   = ''
            CurrStatus   = 'COMP'
            Begin Case
                Case CurrStatus _EQC 'COMP'                           
                    DispStatus = 'Complete'
                    MetActionArray = 'Complete'
                Case CurrStatus _EQC 'START'
                    DispStatus = 'Start'
                    MetActionArray = 'Stop'
                Case CurrStatus _EQC 'STOP'
                    DispStatus = 'Stop'
                    MetActionArray = 'Complete'
                Case CurrStatus _EQC 'SKIP'
                    DispStatus = 'Skip'
                    MetActionArray = 'Unskip'
                Case CurrStatus _EQC 'CHAR'
                    DispStatus = 'Characterize'
                    MetActionArray    = ''
                    // If any metrology stages after split have been started and/or completed, then withdraw
                    // will not be an option.
                Case CurrStatus _EQC 'DISP'
                    DispStatus = 'Disposition'
                    MetActionArray    = ''
                Case CurrStatus _EQC 'INIT'                          
                    DispStatus = 'X'
            End Case
            Convert @FM to @STM in MetActionArray                                
            ThisComboArray<2, 3> = MetActionArray
*            Set_Property(MetStageCtrl, "OLE.CellType[":CurrWfrCol:";":CurrWfrRow:"]", ThisComboArray)
            Destructive = (StageIndex GT 13)
            RowEnabled  = True$
            If (Destructive EQ True$) then
                // Set row text color to red
                If (RowEnabled EQ True$) then
                    DestEditArray = 'Red':@FM:BackgroundColor:@FM:'White':@FM:OI_BLUE$:@FM:'None'
                    Set_Property(MetStageCtrl,"OLE.CellProtection[":CurrWfrCol:";":CurrWfrRow:"]", "None")
                    Set_Property(MetStageCtrl,"OLE.CellColors[":CurrWfrCol:";":CurrWfrRow:"]", DestEditArray)
                    Set_Property(MetStageCtrl,"OLE.CellProtection[":COL$MET_STAGE:'-':COL$MET_TOOL_ID:";":CurrWfrRow:"]", "None")
                    Set_Property(MetStageCtrl,"OLE.CellColors[":COL$MET_STAGE:'-':COL$MET_TOOL_ID:";":CurrWfrRow:"]", DestEditArray)                           
                end else
                    DestEditArray = 'Red':@FM:'OD':@FM:'None':@FM:'None':@FM:'None'
                    Set_Property(MetStageCtrl,"OLE.CellProtection[":CurrWfrCol:";":CurrWfrRow:"]", "None")
                    Set_Property(MetStageCtrl,"OLE.CellColors[":CurrWfrCol:";":CurrWfrRow:"]", DestEditArray)
                    Set_Property(MetStageCtrl,"OLE.CellProtection[":COL$MET_STAGE:'-':COL$MET_TOOL_ID:";":CurrWfrRow:"]", "None")                        
                    Set_Property(MetStageCtrl,"OLE.CellColors[":COL$MET_STAGE:'-':COL$MET_TOOL_ID:";":CurrWfrRow:"]", DestEditArray)                            
                end
            end else
                // Set row text color to default (i.e. 'None')
                If (RowEnabled EQ True$) then
                    ColorArray = 'None':@FM:BackgroundColor:@FM:'White':@FM:OI_BLUE$:@FM:'None'
                    Set_Property(MetStageCtrl,"OLE.CellProtection[":CurrWfrCol:";":CurrWfrRow:"]", "None")
                    Set_Property(MetStageCtrl,"OLE.CellColors[":CurrWfrCol:";":CurrWfrRow:"]", ColorArray)
                    Set_Property(MetStageCtrl,"OLE.CellProtection[":COL$MET_STAGE:'-':COL$MET_TOOL_ID:";":CurrWfrRow:"]", "None")
                    Set_Property(MetStageCtrl,"OLE.CellColors[":COL$MET_STAGE:'-':COL$MET_TOOL_ID:";":CurrWfrRow:"]", ColorArray)                           
                end else
                    ColorArray = 'None':@FM:'OD':@FM:'None':@FM:'None':@FM:'None'
                    Set_Property(MetStageCtrl,"OLE.CellProtection[":CurrWfrCol:";":CurrWfrRow:"]", "None")
                    Set_Property(MetStageCtrl,"OLE.CellColors[":CurrWfrCol:";":CurrWfrRow:"]", ColorArray)
                    Set_Property(MetStageCtrl,"OLE.CellProtection[":COL$MET_STAGE:'-':COL$MET_TOOL_ID:";":CurrWfrRow:"]", "None")                        
                    Set_Property(MetStageCtrl,"OLE.CellColors[":COL$MET_STAGE:'-':COL$MET_TOOL_ID:";":CurrWfrRow:"]", ColorArray)                            
                end
            end
            
        Next WfrID
        
    Next Stage
    Set_Property(@Window, '@METROWSENABLED', MetRowsEnabled)
    
return


AutoSelectToolID:
    
    EnabledColorArray   = 'None':@FM:'None':@FM:'None':@FM:'None':@FM:'None'
    MetStageIDList      = Get_Property(@Window, '@METSTAGEIDLIST')
    WfrIDs              = Get_Property(@Window, '@WFRIDS')
    MetStageCtrl        = @Window:'.OLE_METROLOGY_EDT'
    MetRowsEnabled      = Get_Property(@Window, '@METROWSENABLED')
    MetToolIDArray      = Get_Property(@Window, '@METTOOLIDARRAY')
    
    For each MetStage in MetStageIDList using @VM setting mPos
        If MetStage _NEC 'SPLIT' then
            RunStageWfrKey = ''
            For each WfrID in WfrIDs using @VM setting wPos
                If WfrID NE '' then
                    CurrWfrCol = wPos + 2
                    Convert '*' to '.' in WfrID
                    Begin Case                   
                        Case MetStage EQ 'UV_PRE'
                            // Check if UV stage exists
                            UVStageWfrKey = RDSNo:'*UV*':WfrID
                            If RowExists('RUN_STAGE_WFR', UVStageWfrKey) then
                                // Display this on the UV_PRE line
                                RunStageWfrKey = UVStageWfrKey
                            end else
                                RunStageWfrKey = RDSNo:'*':MetStage:'*':WfrID
                            end
                        Case MetStage EQ 'CAN_PRE'
                            // Check if CAN stage exists
                            CanStageWfrKey = RDSNo:'*CAN*':WfrID
                            If RowExists('RUN_STAGE_WFR', CanStageWfrKey) then
                                // Display this on the CAN_PRE line
                                RunStageWfrKey = CanStageWfrKey
                            end else
                                RunStageWfrKey = RDSNo:'*':MetStage:'*':WfrID
                            end    
                        Case Otherwise$
                            RunStageWfrKey = RDSNo:'*':MetStage:'*':WfrID                           
                    End Case
                    KeyFound = RowExists('RUN_STAGE_WFR', RunStageWfrKey)
                    If KeyFound EQ True$ then
                        RunStageWfrRec = Database_Services('ReadDataRow', 'RUN_STAGE_WFR', RunStageWfrKey)
                        ToolID         = RunStageWfrRec<RUN_STAGE_WFR_TOOL_ID$>
                        If ToolID EQ '' then
                            // Check to see how many tools exist for the current stage. If only one exists, then
                            // auto-select it for convenience.
                            ToolIDs     = Gan_Services('GetToolIDs', MetStage, 'PROD')
                            NumTools    = DCount(ToolIDs, @VM)
                            If NumTools EQ 1 then
                                ToolID = ToolIDs<0, 1>
                                RunStageWfrRec<RUN_STAGE_WFR_TOOL_ID$> = ToolID
                                Database_Services('WriteDataRow', 'RUN_STAGE_WFR', RunStageWfrKey, RunStageWfrRec, True$, False$, True$)
                            end
                        end
                        If ToolID NE '' then
                            Locate MetStage in MetStageIDList using @VM setting RowIndex then                               
                                ThisComboArray = MetToolIDArray<RowIndex>
                                Convert @STM to @VM in ThisComboArray                                    
                                Locate ToolID in ThisComboArray using @VM setting vPos then
                                    Set_Property(MetStageCtrl, "OLE.CellComboSelPos[2; ":RowIndex:"]", vPos)                                    
                                end else
                                    Set_Property(MetStageCtrl, "OLE.CellText[2;":RowIndex:"]", ToolID)
                                end
                                // Tool ID is set, so enable wafer action dropdown menus.                               
                                If ( (MetStage NE 'UV') and (MetStage NE 'UV_PRE') and (MetStage NE 'UV_PST') and (MetStage NE 'WARP') and (MetStage NE 'CAN') and (MetStage NE 'CAN_PRE') and (MetStage NE 'CAN_PST') and (MetStage NE 'WET_CLEAN') ) then
                                    Set_Property(MetStageCtrl,"OLE.CellProtection[":CurrWfrCol:"; ":RowIndex:"]","None")
                                end
                                MetRowsEnabled<RowIndex> = True$
                            end
                        end
                    end
                end
            Next WfrID
        end
    Next MetStage
    Set_Property(@Window, '@METROWSENABLED', MetRowsEnabled)
    
return


FillDispStageHeader:
    
    DispStageCtrl = @Window:'.OLE_DISP_STAGE_EDT'
    ScribeHeaderTitles = Get_Property(@Window, '@SCRIBE_HEADER_TITLES')
    HeaderRowTitles   = 'LSL':@VM:'Target':@VM:'USL':@VM:ScribeHeaderTitles
    Set_Property(DispStageCtrl, "OLE.TitleList", HeaderRowTitles)
    Set_Property(DispStageCtrl, "OLE.HeaderColors[All; 1]", @FM:"{200, 200, 200}")
    
return


FillMetHeader:
    
    Scribes      = Xlate('REACT_RUN', RDSNo, 'WFR_SCRIBES', 'X')
    CarrSlotIDs  = Xlate('REACT_RUN', RDSNo, 'CARR_SLOT_NO', 'X')
    Set_Property(@Window, '@SCRIBES', Scribes)
    Set_Property(@Window, '@CARRSLOTIDS', CarrSlotIDs)
    MetStageCtrl = @Window:'.OLE_METROLOGY_EDT'
    ScribesCopy  = Scribes
    Convert @VM to '' in ScribesCopy
    HeaderTitles = "Stage":@VM:"Tool ID"
    ScribeHeaderTitles = ''
    If ScribesCopy NE '' then       
        For each Scribe in Scribes using @VM setting vPos
            SlotID = CarrSlotIDs<0, vPos>
            ScribeHeaderTitles<0, -1> = Scribe:' (':SlotID:')'
        Next Scribe
        HeaderTitles<0, -1> = ScribeHeaderTitles
        Set_Property(@Window, '@SCRIBE_HEADER_TITLES', ScribeHeaderTitles)
    end else
        DefWfrTitles = ''
        For WfrIndex = 1 to NumWfrs
            DefWfrTitles<1, -1> = 'Wafer ':WfrIndex
        Next WfrIndex
        HeaderTitles = "Stage":@VM:"Tool ID":@VM:DefWfrTitles
    end
    Set_Property(MetStageCtrl, "OLE.TitleList", HeaderTitles)
    Set_Property(MetStageCtrl, "OLE.HeaderColors[All; 1]", @FM:"{200, 200, 200}")
    
return


EnableRows:
    
    // Enable rows and columns now that RUN_STAGE_WFR records have been created
    GaNRunID      = Get_Property(@Window:'.CMB_GAN_RUN_ID', 'TEXT')
    RDSNo         = Get_Property(@Window:'.RDS_NO', 'TEXT')
    MetStageCtrl  = @Window:'.OLE_METROLOGY_EDT'
    Scribes       = Xlate('REACT_RUN', RDSNo, 'PKT_SAT_ID', 'X')
    DummyPockets  = ''
    NumDummyWfrs = 0
    For each Scribe in Scribes using @VM setting vPos
        DummyID = GanRunID[1,7]:'D'
        If Scribe[1,8] EQ DummyID then
            NumDummyWfrs += 1
            DummyPockets<1, vPos> = True$
        end else
            DummyPockets<1, vPos> = False$
        end
    Next Scribe
    NumWfrs       = DCount(Scribes, @VM)
    Set_Property(@Window, '@DUMMYPOCKETS', DummyPockets)
    Set_Property(@Window, '@NUMWFRS', NumWfrs)
    MetDimArray   = Get_Property(@Window, '@METDIMARRAY')
    NumMetCols    = MetDimArray<1>
    DispDimArray  = Get_Property(@Window, '@DISPDIMARRAY')
    NumDispCols   = DispDimArray<1>
    EnabledColorArray = 'None':@FM:'None':@FM:'None':@FM:'None':@FM:'None'
    For each Pocket in DummyPockets using @VM setting vPos
        If Pocket EQ True$ then
            ColNo = vPos + 2
            Set_Property(MetStageCtrl,"OLE.CellProtection[":ColNo:"; All]", "None")
            Set_Property(MetStageCtrl,"OLE.CellColors[":ColNo:"; All]", EnabledColorArray)
            Set_Property(MetStageCtrl,"OLE.ColumnData[":ColNo:"]", '')
            Set_Property(MetStageCtrl,"OLE.HeaderColors[":ColNo+1:"; 1]", EnabledColorArray)
        end
    Next Pocket
    // Protect and color empty wafer columns
    If NumWfrs GT 0 then
        ColOffset = 3    
        StartCol = ColOffset
        EndCol   = NumWfrs + ColOffset
        Set_Property(MetStageCtrl,"OLE.CellProtection[":StartCol:"-":EndCol:"; 1-6]", "None")
        Set_Property(MetStageCtrl,"OLE.CellColors[":StartCol:"-":EndCol:"; 1-6]", EnabledColorArray)
        Set_Property(MetStageCtrl,"OLE.ColumnData[":StartCol:"-":EndCol:"]", '')
        Set_Property(MetStageCtrl,"OLE.HeaderColors[":StartCol+1:"-":EndCol+1:"; 1]", EnabledColorArray)
    end
    
return


FillDispEditTable:
    
    InWfrIDs = ''
    Scribes  = ''
    For WfrIndex = 1 to 8
        InWfrIDs<0, WfrIndex> = '123456*1*':WfrIndex
        Scribes<0, WfrIndex>  = 'Scribe0':WfrIndex
    Next WfrIndex
    RDSNo         = Get_Property(@Window:'.RDS_NO', 'TEXT')
    DispCtrl      = @Window:'.OLE_DISP_EDT'
    DispDimArray  = Get_Property(@Window, '@DISPDIMARRAY')
    NumDispRows   = DispDimArray<2>
    Set_Property(DispCtrl, "OLE.HeaderMerge[1; 2]", 1:@FM:NumDispRows)
    DispCtrlArray = ''
    Slots         = Get_Property(@Window, '@SLOTS')
    NumWfrs       = DCount(InWfrIDs, @VM)
    RDSClosed     = False$
    For WfrIndex = 1 to NumWfrs
        Row                                       = WfrIndex
        WfrID                                     = InWfrIDs<0, WfrIndex>
        DispCtrlArray<COL$DISP_SLOT, WfrIndex>    = Slots<0, WfrIndex>
        DispCtrlArray<COL$DISP_WFR_ID, WfrIndex>  = WfrID
        DispCtrlArray<COL$DISP_SCRIBE, WfrIndex>  = Scribes<0, WfrIndex>
        DispCtrlArray<COL$DISP_RDS_NCR, WfrIndex> = ''
        DispCtrlArray<COL$DISP_WMO_NCR, WfrIndex> = ''
        DispCtrlArray<COL$DISP_SHIP_ID, WfrIndex> = ''
        DispCtrlArray<COL$DISP_GRADE, WfrIndex>   = 'Prod'      
    Next WfrIndex
    
    Set_Property(DispCtrl, "OLE.ARRAY", DispCtrlArray)
    GoSub EnableNCRButton
    
return


Event OLE_NCR_EDT.OnDblClick(Cell, Point, Button, Shift, Ctrl)
    
    DispCtrlArray = Get_Property(@Window:'.OLE_DISP_EDT', "OLE.ARRAY")
    Row       = Field(Cell, ';', 2, 1)
    RDSNCRNos = DispCtrlArray<COL$DISP_RDS_NCR>
    WMONCRNos = DispCtrlArray<COL$DISP_WMO_NCR>
    NCRNos    = SRP_Array('Join', RDSNCRNos, WMONCRNos, 'OR', @VM)
    NCRNo     = Get_Property(CtrlEntID, "OLE.CellText[":COL$NCR_NO:";":Row:"]")  
    If RowExists('NCR', NCRNo) then
        PreNCRRec  = Database_Services('ReadDataRow', 'NCR', NCRNo)
        PostNCRRec = ''
        
        Dialog_Box('NCR', @Window, NCRNo)
        
        If RowExists('NCR', NCRNo) then PostNCRRec = Database_Services('ReadDataRow', 'NCR', NCRNo)
        If PreNCRRec NE PostNCRRec then
            
            RDSNo = Get_Property(@Window:'.RDS_NO', 'TEXT')
            PrevCursor  = Set_Property('SYSTEM', 'CURSOR', 'H')        
            Def = ""
            Def<MCAPTION$>   = "Loading..."
            Def<MTYPE$>      = "G"
            Def<MEXTENT$>    = 100 ; // 100%
            Def<MTEXTWIDTH$> = 400
            Def<MCOL$>       = -2        ;* message h-pos in pixels, or -2 (center screen, the default), -1 (center parent)
            Def<MROW$>       = -2        ;* message v-pos in pixels
            MsgUp  = Msg(@Window, Def)
            Disposition_Services('AutoDispositionRun', RDSNo)        
            Msg(@Window, MsgUp, 20, MSGINSTUPDATE$)
            Msg(@Window, MsgUp, 40, MSGINSTUPDATE$)
            GoSub FillDispEditTable
            Msg(@Window, MsgUp, 60, MSGINSTUPDATE$)
            GoSub FillNCREditTable
            Msg(@Window, MsgUp, 80, MSGINSTUPDATE$)
            GoSub EnableCloseRDSButton
            Msg(@Window, MsgUp, 100, MSGINSTUPDATE$)
            GoSub EnableNCRButton
            Msg(@Window, MsgUp)           
            PrevCursor  = Set_Property('SYSTEM', 'CURSOR', 'A')
        end           
    end
    
end event


Event OLE_DISP_STAGE_EDT.OnClick(Cell, Point, Button, Shift, Ctrl)
    
    If Button EQ 'Right' then
        Col = Field(Cell, ';', 1, 1)
        Row = Field(Cell, ';', 2, 1)
        CellColorArray = Get_Property(@Window, '@COLOR_ARRAY')
        SelTabIndex    = Get_Property(@Window:".OLE_TAB", "OLE.SelectedTab")
        CaptionList    = Get_Property(@Window:".OLE_TAB", "OLE.CaptionList")
        StageID        = Field(CaptionList, ',', SelTabIndex, 1)
        BackColor      = CellColorArray<SelTabIndex, Row, Col-3>      
        CellText       = Get_Property(CtrlEntID, "OLE.CellText[":Col:";":Row:"]")
        Begin Case
            Case CellText EQ 'Multi'                
                PopupCtrl       = @Window : '.OLE_POPUP'
                PopupVisible    = Get_Property(PopupCtrl, 'OLE.Visible')
                If PopupVisible EQ True$ then
                    GoSub DismissPopup
                end
                GoSub DisplayMetPopup        
            Case BackColor EQ 'Yellow'
                PopupCtrl       = @Window : '.OLE_POPUP'
                PopupVisible    = Get_Property(PopupCtrl, 'OLE.Visible')
                If PopupVisible EQ True$ then
                    GoSub DismissPopup
                end
                GoSub DisplayStageDisPopup  
        End Case
    end
    
end event


Event OLE_DISP_STAGE_EDT.OnHeaderClick(Cell, Point, Button, Shift, Ctrl)
    
    If Button EQ 'Right' then
        Col = Field(Cell, ';', 1, 1)
        Row = Field(Cell, ';', 2, 1)
        Scribe    = Get_Property(CtrlEntID, "OLE.HeaderText[":Col:";":Row:"]")
        Scribe    = Scribe[1, 'F ']
        RDSNo     = Get_Property(@Window:'.RDS_NO', 'TEXT')       
        Scribes   = Get_Property(@Window, '@SCRIBES')
        RDSNo     = Get_Property(@Window:'.RDS_NO', 'TEXT')
        RDSClosed = Xlate('REACT_RUN', RDSNo, 'DISP_COMPLETE', 'X')
        Locate Scribe in Scribes using @VM setting WfrIndex then
            ReactRunRec            = Database_Services('ReadDataRow', 'REACT_RUN', RDSNo)
            DataValidationDisabled = ReactRunRec<REACT_RUN_MISSING_DATA_VALID_DISABLED$, WfrIndex>
            DataIsMissing          = ReactRunRec<REACT_RUN_DATA_MISSING$, WfrIndex>
            DataOutOfSpec          = ReactRunRec<REACT_RUN_DATA_OUT_OF_SPEC$, WfrIndex>                        
            If RDSClosed EQ True$ then
                Enabled = False$     
            end else
                Enabled = True$
            end
            Menu = ''
            Begin Case
                Case DataValidationDisabled EQ True$                              
                    Menu<-1> = 'ENABLE'     :@VM:   'Enable Data Validation'    :@VM:   Enabled
                Case ( ( (DataValidationDisabled NE True$) and (DataIsMissing EQ True$) ) or (DataOutOfSpec EQ True$) )                    
                    Menu<-1> = 'DISABLE'    :@VM:   'Disable Data Validation'   :@VM:   Enabled                
                Case Otherwise$
                    Menu<-1> = 'DISABLE'    :@VM:   'Disable Data Validation'   :@VM:   False$                
            End Case
            // Note you must pass all variables when calling Send_Message otherwise the call will fail
            User = ''
            Locate Scribe in Scribes using @VM setting WfrIndex then
                User = WfrIndex
            end
            Send_Message(CtrlEntID, "OLE.ShowContextMenu", Point, Menu, User)
        end
    end
    
end event


Event OLE_DISP_STAGE_EDT.OnContextMenuClick(Item, UserData)
    
    Abort = False$
    If Not( Memberof(@User4, 'GAN_WIP_SUPERVISOR') ) then
        MsgText = 'A member of the "GAN_WIP_SUPERVISOR" group must override.'
        Response = Msg(@Window, '', 'OVERRIDE', '', MsgText)
        If Response EQ Yes$ then
            // Verify credentials
            Response    = Dialog_Box('NDW_VERIFY_USER', @WINDOW, @USER4:@FM:'GAN_WIP_SUPERVISOR')
            Valid       = Response<1>
            If Valid NE True$ then Abort = True$
        end else
            Abort = True$
        end
    end
    If Abort EQ False$ then
        RDSNo          = Get_Property(@Window:'.RDS_NO', 'TEXT')
        ReactRunRec    = Database_Services('ReadDataRow', 'REACT_RUN', RDSNo)
        WfrIDs         = ReactRunRec<REACT_RUN_IN_WFR_ID$>
        Action         = Item
        WfrIndex       = UserData
        WfrID          = WfrIDs<0, WfrIndex>
        TabCount       = Get_Property(@Window:'.OLE_TAB', 'OLE.TabCount')
        CellColorArray = Get_Property(@Window, '@COLOR_ARRAY')
        Begin Case
            Case Action EQ 'DISABLE'
                ReactRunRec<REACT_RUN_MISSING_DATA_VALID_DISABLED$, WfrIndex> = True$ 
                ReactRunRec<REACT_RUN_MISSING_DATA_VALID_USER$, WfrIndex> = @User4 
                ReactRunRec<REACT_RUN_MISSING_DATA_VALID_DTM$, WfrIndex> = Datetime()                
            Case Action EQ 'ENABLE'
                ReactRunRec<REACT_RUN_MISSING_DATA_VALID_DISABLED$, WfrIndex> = False$ 
                ReactRunRec<REACT_RUN_MISSING_DATA_VALID_USER$, WfrIndex> = '' 
                ReactRunRec<REACT_RUN_MISSING_DATA_VALID_DTM$, WfrIndex> = ''                
                
        End Case
        
        For TabIndex = 1 to TabCount
            ThisTabCellColorArray   = CellColorArray<TabIndex>
            Convert @VM to @FM in ThisTabCellColorArray
            Convert @SVM to @VM in ThisTabCellColorArray
            ThisTabCellColorArray   = SRP_Array('Rotate', ThisTabCellColorArray, @FM, @VM)
            ThisWaferCellColorArray = ThisTabCellColorArray<WfrIndex>
            Stage                   = Get_Property(@Window:'.OLE_TAB', "OLE.TabCaption[":TabIndex:"]")
            Swap ' ' with '_' in Stage
            Swap '*' with '.' in WfrID
            RunStageWfrKey          = RDSNo:'*':Stage:'*':WfrID
            ParamOutOfSpec          = Xlate('RUN_STAGE_WFR', RunStageWfrKey, RUN_STAGE_WFR_PARAM_OUT_OF_SPEC$, 'X')
            DataOutOfSpec           = False$
            DataMissing             = False$
            For each Value in ParamOutOfSpec using @VM
                If Value EQ 1 then DataOutOfSpec = True$
                If Value EQ -1 then DataMissing = True$
            Next Value
            Begin Case
                Case Action EQ 'DISABLE'
                    Begin Case
                        Case DataOutOfSpec EQ True$
                            Swap 'Red' with 'SlateBlue L=75' in ThisWaferCellColorArray
                        Case DataMissing EQ True$
                            Swap 'Yellow' with 'SlateBlue L=75' in ThisWaferCellColorArray
                    End Case
                Case Action EQ 'ENABLE'
                    Begin Case
                        Case DataOutOfSpec EQ True$
                            Swap 'SlateBlue L=75' with 'Red' in ThisWaferCellColorArray
                        Case DataMissing EQ True$
                            Swap 'SlateBlue L=75' with 'Yellow' in ThisWaferCellColorArray
                    End Case
            End Case            
            ThisTabCellColorArray<WfrIndex> = ThisWaferCellColorArray
            ThisTabCellColorArray = SRP_Array('Rotate', ThisTabCellColorArray, @FM, @VM)
            Convert @VM to @SVM in ThisTabCellColorArray
            Convert @FM to @VM in ThisTabCellColorArray           
            CellColorArray<TabIndex> = ThisTabCellColorArray
            
        Next TabIndex
        
        Set_Property(@Window, '@COLOR_ARRAY', CellColorArray)
        Database_Services('WriteDataRow', 'REACT_RUN', RDSNo, ReactRunRec, True$, False$, True$)
        Disposition_Services('AutoDispositionRun', RDSNo)               
        GoSub ColorCells
        GoSub ColorTabs
        GoSub FillDispEditTable
        GoSub EnableCloseRDSButton
    end
    
end event


Event OLE_DISP_EDT.OnClick(Cell, Point, Button, Shift, Ctrl)
    
    Col = Field(Cell, ';', 1, 1)
    Row = Field(Cell, ';', 2, 1)
    Begin Case
        Case Col EQ COL$DISP_WFR_ID
            If Button _EQC 'Right' then
                RDSNo       = Get_Property(@Window:'.RDS_NO', 'TEXT')           
                WfrID       = Get_Property(CtrlEntID, "OLE.CellText[":COL$DISP_WFR_ID:";":Row:"]")
                Menu        = ''
                MenuEnabled = False$
                If RowExists('WO_WFR', WfrID) then MenuEnabled = True$
                Menu<-1> = "CharStages"   :@VM:"View Char Stages"   :@VM:MenuEnabled
                Menu<-1> = "WaferTrace"   :@VM:"View Wafer Trace"   :@VM:MenuEnabled            
                Send_Message(CtrlEntID, "OLE.ShowContextMenu", Point, Menu, WfrID)
            end
    End Case
    If Col EQ COL$DISP_WFR_ID then
        If Button _EQC 'Right' then
            RDSNo       = Get_Property(@Window:'.RDS_NO', 'TEXT')           
            WfrID       = Get_Property(CtrlEntID, "OLE.CellText[":COL$DISP_WFR_ID:";":Row:"]")
            Menu        = ''
            MenuEnabled = False$
            If RowExists('WO_WFR', WfrID) then MenuEnabled = True$
            Menu<-1> = "CharStages"   :@VM:"View Char Stages"   :@VM:MenuEnabled
            Menu<-1> = "WaferTrace"   :@VM:"View Wafer Trace"   :@VM:MenuEnabled            
            Send_Message(CtrlEntID, "OLE.ShowContextMenu", Point, Menu, WfrID)
        end
    end
    
end event


Event OLE_DISP_EDT.OnContextMenuClick(Item, UserData)
    
    RDSNo  = Get_Property(@Window:'.RDS_NO', 'TEXT')
    Action = Item
    WfrID  = UserData
    Begin Case
        Case Action _EQC 'CharStages'
            
            WfrSigProfile       = obj_React_Run('GetWfrSigKeys', RDSNo:@RM:WfrID)
            TypeOver            = ''
            TypeOver<PDISPLAY$> = WfrSigProfile
            Dummy               = Popup(@Window, TypeOver, 'CHAR_WFR_STAGES')
            
        Case Action _EQC 'WaferTrace'
            
            TraceData           = obj_WO_Wfr('TraceData', WfrID:@RM:'')
            TypeOver            = ''
            TypeOver<PDISPLAY$> = TraceData
            Dummy               = Popup(@Window, TypeOver, 'WAFER_TRACE')         
            
    End Case
    
end event


EnableNCRButton:
    
    Checkmarks = Get_Property(@Window:".OLE_DISP_EDT", "OLE.CellCheck[":COL$DISP_RDS_NCR:"; All]")
    Checksum   = Sum(Checkmarks)
    If ( Checksum GT 0 ) then
        NCRButton = True$ 
    end else
        NCRButton = False$
    end
    Set_Property(@Window:'.PUB_CREATE_NCR', 'ENABLED', NCRButton)
    
return


FillNCREditTable:
    
    RDSNo = Get_Property(@Window:'.RDS_NO', 'TEXT')
    NCRCtrl = @Window:'.OLE_NCR_EDT'
    InWfrIDs = Get_Property(@Window, '@WFRIDS')
    
    NCRCtrlArray = ''
    NCRNos       = ''
    RDSNCRs      = Xlate('WO_WFR', InWfrIDs, 'RDS_NCR_NO', 'X')
    WMONCRs      = Xlate('WO_WFR', InWfrIDs, 'WMO_NCR_NO', 'X')
    NCRNos       = SRP_Array('Join', RDSNCRs, WMONCRs, 'OR', @VM)
    NCRNos       = SRP_Array('Clean', NCRNos, 'Trim', @VM)
    If NCRNos NE '' then
        For each NCRNo in NCRNos using @VM setting nPos
            Database_Services('ActivateRecord', 'NCR', NCRNo)
            If Error_Services('NoError') then
                NCRCtrlArray<COL$NCR_NO, nPos>          = NCRNo
                NCRCtrlArray<COL$NCR_STATUS, nPos>      = {STATUS}
                NCRCtrlArray<COL$NCR_REJ_QTY, nPos>     = {REJ_CNT}
                NCRCtrlArray<COL$NCR_RESP, nPos>        = {LOSS_BY}
                NCRCtrlArray<COL$NCR_STAGE, nPos>       = {LOSS_STAGE}
                NCRCtrlArray<COL$NCR_LOSS_DESC, nPos>   = {LOSS_DESC}
                NCRCtrlArray<COL$NCR_LOSS_COMM, nPos>   = {LOSS_COMMENTS}
                NCRCtrlArray<COL$NCR_FIN_SIG, nPos>     = OConv({AUTH_SHIP_SIG}, '[XLATE_CONV,LSL_USERS*FIRST_LAST]')
                NCRCtrlArray<COL$NCR_FIN_SIG_DTM, nPos> = OConv({AUTH_SHIP_SIG_DTM}, 'DT')
            end else
                NCRCtrlArray<COL$NCR_NO, nPos>          = NCRNo
                NCRCtrlArray<COL$NCR_STATUS, nPos>      = 'Error'
                NCRCtrlArray<COL$NCR_REJ_QTY, nPos>     = 'Error'
                NCRCtrlArray<COL$NCR_RESP, nPos>        = 'Error'
                NCRCtrlArray<COL$NCR_STAGE, nPos>       = 'Error'
                NCRCtrlArray<COL$NCR_LOSS_DESC, nPos>   = 'Error'
                NCRCtrlArray<COL$NCR_LOSS_COMM, nPos>   = 'Error'
                NCRCtrlArray<COL$NCR_FIN_SIG, nPos>     = 'Error'
                NCRCtrlArray<COL$NCR_FIN_SIG_DTM, nPos> = 'Error'
            end
        Next NCRNo
    end else        
        // No NCRs associated with this inbound cassette, so clear the NCR table.
        NCRDimArray = Get_Property(@Window, '@NCRDIMARRAY')
        NumRows = NCRDimArray<2>
        For nPos = 1 to NumRows
            NCRCtrlArray<COL$NCR_NO, nPos>          = ''
            NCRCtrlArray<COL$NCR_STATUS, nPos>      = ''
            NCRCtrlArray<COL$NCR_REJ_QTY, nPos>     = ''
            NCRCtrlArray<COL$NCR_RESP, nPos>        = ''
            NCRCtrlArray<COL$NCR_STAGE, nPos>       = ''
            NCRCtrlArray<COL$NCR_LOSS_DESC, nPos>   = ''
            NCRCtrlArray<COL$NCR_LOSS_COMM, nPos>   = ''
            NCRCtrlArray<COL$NCR_FIN_SIG, nPos>     = ''
            NCRCtrlArray<COL$NCR_FIN_SIG_DTM, nPos> = ''
        Next nPos
    end
    
    Set_Property(NCRCtrl, "OLE.ARRAY", NCRCtrlArray)
    
return


DismissPopup:
    
    PopupCtrl       = @Window : '.OLE_POPUP'
    PopupVisible    = Get_Property(PopupCtrl, 'OLE.Visible')
    If PopupVisible EQ True$ then
        Send_Message(PopupCtrl, 'OLE.Close')
    end
    
return


DisplayPopup:
    
    Set_Property('SYSTEM', 'CURSOR', 'H')
    BackColor   = Get_Property(@Window, 'BACKCOLOR')
    ForeColor   = Get_Property(@Window, 'FORECOLOR')
    CursorXPos  = Field(Point, ',', 1, 1)
    CursorYPos  = Field(Point, ',', 2, 1)
    FormSize    = SRP_Get_Window_Rect(@Window)
    FormXPos    = FormSize<1>
    FormYPos    = FormSize<2>
    CtrlSize    = Get_Property(CtrlEntID, 'SIZE')
    CtrlXPos    = CtrlSize<1>
    CtrlYPos    = CtrlSize<2>
    PopupWidth  = 160
    PopupHeight = 60
    XPadding    = 10
    YPadding    = 10
    XOffset     = 10
    YOffset     = 55
    PopupXPos   = FormXPos + CtrlXPos + CursorXPos + XOffset
    PopupYPos   = FormYPos + CtrlYPos + CursorYPos + YOffset
    StatusBy    = ''
    StatusDTM   = ''
    RDSNo       = Get_Property(@Window:'.RDS_NO', 'TEXT')
    ReactRunRec = Database_Services('ReadDataRow', 'REACT_RUN', RDSNo)
    StageDesc   = Get_Property(CtrlEntID, 'OLE.CellText[1; ':Row:']')
    StageID     = Gan_Services('GetStageID', StageDesc)
    Begin Case
        Case CtrlEntID _EQC @Window:'.OLE_REACTOR_EDT'
            // Cassette Level
            RunStageKey = RDSNo:'*':StageID
            RunStageRec = Database_Services('ReadDataRow', 'RUN_STAGE', RunStageKey)    
            StageStatus = RunStageRec<RUN_STAGE_STATUS$>
            
            Begin Case
                Case StageStatus _EQC 'COMP' or StageStatus _EQC 'SKIP'            
                    StatusBy  = RunStageRec<RUN_STAGE_COMP_BY$>
                    StatusDTM = RunStageRec<RUN_STAGE_COMP_DTM$>                   
                Case StageStatus _EQC 'START'
                    InvActions = RunStageRec<RUN_STAGE_SPEC_INV_ACTION$>
                    Locate 'START' in InvActions using @VM setting vPos then
                        StatusBy  = RunStageRec<RUN_STAGE_SIA_COMP_BY$, vPos>
                        StatusDTM = RunStageRec<RUN_STAGE_SIA_COMP_DTM$, vPos>
                    end
            End Case
            
            
        Case CtrlEntID _EQC @Window:'.OLE_METROLOGY_EDT'
            // Wafer level
            ScribeHeader = Get_Property(CtrlEntID, 'OLE.HeaderText[':Column+1:'; 1]')
            Scribe       = ScribeHeader[1, 'F ']
            Scribes      = Xlate('REACT_RUN', RDSNo, 'WFR_SCRIBES', 'X')
            WfrIDs       = ReactRunRec<REACT_RUN_IN_WFR_ID$>
            WfrID        = ''
            Locate Scribe in Scribes using @VM setting vPos then
                WfrID = WfrIDs<0, vPos>
            end
            Convert '*' to '.' in WfrID            
            RunStageWfrKey = RDSNo:'*':StageID:'*':WfrID
            If RowExists('RUN_STAGE_WFR', RunStageWfrKey) then
                RunStageWfrRec = Database_Services('ReadDataRow', 'RUN_STAGE_WFR', RunStageWfrKey)
            end else
                // This may be an old run that has a CAN stage instead of a CAN_PRE stage
                If StageID EQ 'CAN_PRE' then
                    RunStageWfrKey = RDSNo:'*CAN*':WfrID
                    If RowExists('RUN_STAGE_WFR', RunStageWfrKey) then
                        RunStageWfrRec = Database_Services('ReadDataRow', 'RUN_STAGE_WFR', RunStageWfrKey)
                    end
                end
            end
            
            StageStatus    = RunStageWfrRec<RUN_STAGE_WFR_STATUS$>
            Begin Case
                Case StageStatus _EQC 'COMP' or StageStatus _EQC 'SKIP' or StageStatus _EQC 'CHAR' or StageStatus _EQC 'DISP'                 
                    StatusBy  = RunStageWfrRec<RUN_STAGE_WFR_COMP_BY$>
                    StatusDTM = RunStageWfrRec<RUN_STAGE_WFR_COMP_DTM$>                               
                Case StageStatus _EQC 'START'
                    InvActions = RunStageWfrRec<RUN_STAGE_WFR_SPEC_INV_ACTION$>
                    Locate 'START' in InvActions using @VM setting vPos then
                        StatusBy  = RunStageWfrRec<RUN_STAGE_WFR_SIA_COMP_BY$, vPos>
                        StatusDTM = RunStageWfrRec<RUN_STAGE_WFR_SIA_COMP_DTM$, vPos>
                    end                    
            End Case
    End Case
    If (StatusBy NE '') and (StatusDTM NE '') then
        HoverData   = ''
        HoverData  := OConv(StatusBy, '[XLATE_CONV,LSL_USERS*FIRST_LAST]') : @FM
        HoverData  := OConv(StatusDTM, 'DT')
        NumLines    = DCount(HoverData, @FM)
        ItemList    = ''
        If HoverData NE '' then
            For Each Item in HoverData using @FM setting ItemCount            
                ItemList<ItemCount,SRP_POPUP.RECTANGLE,1> = XPadding                        ; // X Position of item     
                ItemList<ItemCount,SRP_POPUP.RECTANGLE,2> = (20 * (ItemCount - 1) )         ; // Y Position of item      
                ItemList<ItemCount,SRP_POPUP.RECTANGLE,3> = PopupWidth - (2 * XPadding)     ; // Width           
                ItemList<ItemCount,SRP_POPUP.RECTANGLE,4> = PopupHeight - (2 * YPadding)    ; // Height
                ItemList<ItemCount,SRP_POPUP.CAPTION>     = Item
                ItemList<ItemCount,SRP_POPUP.COLORS>      = Forecolor
                ItemList<ItemCount,SRP_POPUP.FONT>        = '' : @SVM : '' : @SVM : '700' : @SVM : '0' : @SVM : '0'
                ItemList<ItemCount,SRP_POPUP.ALIGNMENT>   = 'Left' : @SVM : 'Center'       
            Next Item
        end
        
        Set_Property(PopupCtrl, 'OLE.Theme', 'Custom')
        Set_Property(PopupCtrl, 'OLE.Opacity', 255)
        Set_Property(PopupCtrl, 'OLE.Animation', 'N')
        Set_Property(PopupCtrl, 'OLE.Background', 'Vertical(Gradient(' : Backcolor : ', ' : Backcolor : '), Border(' : Backcolor : ' L=20))' : @FM : 'None' : @FM : 'None')
        Set_Property(PopupCtrl, 'OLE.ItemList', ItemList)
        Set_Property(PopupCtrl, 'OLE.ShowDelay', 1000)
        Set_Property(PopupCtrl, 'OLE.Size', 0 : @FM : 0 : @FM : PopupWidth : @FM : PopupHeight)   
        Send_Message(PopupCtrl, 'OLE.ShowAt', PopupXPos, PopupYPos)
    end
    Set_Property('SYSTEM', 'CURSOR', 'A')
    
return


DisplayMetPopup:
    
    Set_Property('SYSTEM', 'CURSOR', 'H')
    BackColor   = Get_Property(@Window, 'BACKCOLOR')
    ForeColor   = Get_Property(@Window, 'FORECOLOR')
    CursorXPos  = Field(Point, ',', 1, 1)
    CursorYPos  = Field(Point, ',', 2, 1)
    FormSize    = SRP_Get_Window_Rect(@Window)
    FormXPos    = FormSize<1>
    FormYPos    = FormSize<2>
    CtrlSize    = Get_Property(CtrlEntID, 'SIZE')
    CtrlXPos    = CtrlSize<1>
    CtrlYPos    = CtrlSize<2>
    PopupWidth  = 130
    
    XPadding    = 10
    YPadding    = 10
    XOffset     = 10
    YOffset     = 55
    PopupXPos   = FormXPos + CtrlXPos + CursorXPos + XOffset
    PopupYPos   = FormYPos + CtrlYPos + CursorYPos + YOffset
    StatusBy    = ''
    StatusDTM   = ''
    RDSNo       = Get_Property(@Window:'.RDS_NO', 'TEXT')
    ReactRunRec = Database_Services('ReadDataRow', 'REACT_RUN', RDSNo)
    
    TabIndex    = Get_Property(@Window:'.OLE_TAB', 'OLE.SelectedTab')
    Stage       = Get_Property(@Window:'.OLE_TAB', 'OLE.TabCaption[':TabIndex:']')
    
    WfrIndex    = Col - 3
    InWfrIDs    = Get_Property(@Window, '@WFRIDS')
    WfrID       = InWfrIDs<0, WfrIndex>
    Convert '*' to '.' in WfrID
    RunStageWfrKey  = RDSNo:'*':Stage:'*':WfrID
    RunStageWfrRec  = Database_Services('ReadDataRow', 'RUN_STAGE_WFR', RunStageWfrKey)
    ParamValues     = RunStageWfrRec<RUN_STAGE_WFR_MET_PARAM_VALUES$>
    OutOfSpec       = RunStageWfrRec<RUN_STAGE_WFR_PARAM_OUT_OF_SPEC$>
    RowParamValues  = ParamValues<0, Row>
    RowOutOfSpec    = OutOfSpec<0, Row>
    ColorArray      = ''
    Convert @SVM to @FM in RowParamValues
    HoverData   = 'Index | Value'
    For each Value in RowParamValues setting Index
        HoverData := @FM:Index:'          | ':Value
        If RowOutOfSpec<0, 0, Index> EQ True$ then
            ColorArray<Index> = 'Red'
        end else
            ColorArray<Index> = 'None'
        end
    Next Value
    
    NumLines    = DCount(HoverData, @FM)
    PopupHeight = (25 * (NumLines) )
    ItemList    = ''
    If HoverData NE '' then
        For Each Item in HoverData using @FM setting ItemCount            
            ItemList<ItemCount,SRP_POPUP.RECTANGLE,1> = XPadding                        ; // X Position of item     
            ItemList<ItemCount,SRP_POPUP.RECTANGLE,2> = ( 25 * (ItemCount - 1) )        ; // Y Position of item      
            ItemList<ItemCount,SRP_POPUP.RECTANGLE,3> = PopupWidth - (2 * XPadding)     ; // Width           
            ItemList<ItemCount,SRP_POPUP.RECTANGLE,4> = 25                              ; // Height
            ItemList<ItemCount,SRP_POPUP.CAPTION>     = Item
            ItemList<ItemCount,SRP_POPUP.COLORS>      = ColorArray<ItemCount - 1>
            ItemList<ItemCount,SRP_POPUP.FONT>        = '' : @SVM : '' : @SVM : '700' : @SVM : '0' : @SVM : '0'
            ItemList<ItemCount,SRP_POPUP.ALIGNMENT>   = 'Left' : @SVM : 'Center'       
        Next Item
    end
    
    Set_Property(PopupCtrl, 'OLE.Theme', 'Custom')
    Set_Property(PopupCtrl, 'OLE.Opacity', 255)
    Set_Property(PopupCtrl, 'OLE.Animation', 'N')
    Set_Property(PopupCtrl, 'OLE.Background', 'Vertical(Gradient(' : Backcolor : ', ' : Backcolor : '), Border(' : Backcolor : ' L=20))' : @FM : 'None' : @FM : 'None')
    Set_Property(PopupCtrl, 'OLE.ItemList', ItemList)
    Set_Property(PopupCtrl, 'OLE.ShowDelay', 1000)
    Set_Property(PopupCtrl, 'OLE.Size', 0 : @FM : 0 : @FM : PopupWidth : @FM : PopupHeight)   
    Send_Message(PopupCtrl, 'OLE.ShowAt', PopupXPos, PopupYPos)
    
    Set_Property('SYSTEM', 'CURSOR', 'A')
    
return


DisplayStageDisPopup:
    
    Set_Property('SYSTEM', 'CURSOR', 'H')
    BackColor   = Get_Property(@Window, 'BACKCOLOR')
    ForeColor   = Get_Property(@Window, 'FORECOLOR')
    CursorXPos  = Field(Point, ',', 1, 1)
    CursorYPos  = Field(Point, ',', 2, 1)
    FormSize    = SRP_Get_Window_Rect(@Window)
    FormXPos    = FormSize<1>
    FormYPos    = FormSize<2>
    CtrlSize    = Get_Property(CtrlEntID, 'SIZE')
    CtrlXPos    = CtrlSize<1>
    CtrlYPos    = CtrlSize<2>
    PopupWidth  = 160
    PopupHeight = 60
    XPadding    = 10
    YPadding    = 10
    XOffset     = 10
    YOffset     = 55
    PopupXPos   = FormXPos + CtrlXPos + CursorXPos + XOffset
    PopupYPos   = FormYPos + CtrlYPos + CursorYPos + YOffset
    StatusBy    = ''
    StatusDTM   = ''
    RDSNo       = Get_Property(@Window:'.RDS_NO', 'TEXT')
    ReactRunRec = Database_Services('ReadDataRow', 'REACT_RUN', RDSNo)
*    WfrStages   =  <REACT_RUN_WFR_STAGE$>
    Locate StageID in WfrStages using @VM setting StageIndex then
        DisabledBy  = ReactRunRec<REACT_RUN_MISSING_DATA_VALID_USER$, StageIndex>
        DisabledDTM = ReactRunRec<REACT_RUN_MISSING_DATA_VALID_DTM$, StageIndex>
        If (DisabledBy NE '') and (DisabledDTM NE '') then
            HoverData   = ''
            HoverData  := OConv(DisabledBy, '[XLATE_CONV,LSL_USERS*FIRST_LAST]') : @FM
            HoverData  := OConv(DisabledDTM, 'DT')
            NumLines    = DCount(HoverData, @FM)
            ItemList    = ''
            If HoverData NE '' then
                For Each Item in HoverData using @FM setting ItemCount            
                    ItemList<ItemCount,SRP_POPUP.RECTANGLE,1> = XPadding                        ; // X Position of item     
                    ItemList<ItemCount,SRP_POPUP.RECTANGLE,2> = (20 * (ItemCount - 1) )         ; // Y Position of item      
                    ItemList<ItemCount,SRP_POPUP.RECTANGLE,3> = PopupWidth - (2 * XPadding)     ; // Width           
                    ItemList<ItemCount,SRP_POPUP.RECTANGLE,4> = PopupHeight - (2 * YPadding)    ; // Height
                    ItemList<ItemCount,SRP_POPUP.CAPTION>     = Item
                    ItemList<ItemCount,SRP_POPUP.COLORS>      = Forecolor
                    ItemList<ItemCount,SRP_POPUP.FONT>        = '' : @SVM : '' : @SVM : '700' : @SVM : '0' : @SVM : '0'
                    ItemList<ItemCount,SRP_POPUP.ALIGNMENT>   = 'Left' : @SVM : 'Center'       
                Next Item
            end
            
            Set_Property(PopupCtrl, 'OLE.Theme', 'Custom')
            Set_Property(PopupCtrl, 'OLE.Opacity', 255)
            Set_Property(PopupCtrl, 'OLE.Animation', 'N')
            Set_Property(PopupCtrl, 'OLE.Background', 'Vertical(Gradient(' : Backcolor : ', ' : Backcolor : '), Border(' : Backcolor : ' L=20))' : @FM : 'None' : @FM : 'None')
            Set_Property(PopupCtrl, 'OLE.ItemList', ItemList)
            Set_Property(PopupCtrl, 'OLE.ShowDelay', 1000)
            Set_Property(PopupCtrl, 'OLE.Size', 0 : @FM : 0 : @FM : PopupWidth : @FM : PopupHeight)   
            Send_Message(PopupCtrl, 'OLE.ShowAt', PopupXPos, PopupYPos)
        end
    end   
    Set_Property('SYSTEM', 'CURSOR', 'A')
    
return


VerifyRecipe:    
    
    GaNRunID    = Get_Property(@Window:'.CMB_GAN_RUN_ID', 'TEXT')
    If GaNRunID NE '' then
        GaNRecipe   = Get_Property(@Window:'.GAN_RECIPE', 'TEXT')
        Convert @Lower_Case to @Upper_Case in GaNRunID
        SchedRecipe = Xlate('GAN_SCHEDULE', GaNRunID, 'RECIPE', 'X')
        If GaNRecipe NE '' then            
            If SchedRecipe _EQC GaNRecipe then
                // If the recipes match, then color the recipe ID bright green, otherwise
                // color it bright red and block the Run Configuration "Complete" event.
                Set_Property(@Window:'.GAN_RECIPE', 'BACKCOLOR', BGREEN$)
                Set_Property(@Window, '@RECIPEMISMATCH', False$)
            end else
                Set_Property(@Window:'.GAN_RECIPE', 'BACKCOLOR', BRED$)
                Set_Property(@Window, '@RECIPEMISMATCH', True$)
            end
        end
    end
    
return


EnableRunIDComboBox:
    
    RDSNo = Get_Property(@Window:'.RDS_NO', 'TEXT')
    EtchKey = RDSNo:'*ETCH'
    EtchStatus = Xlate('RUN_STAGE', EtchKey, 'STATUS', 'X')
    If EtchStatus _EQC 'COMP' then
        Set_Property(@Window:'.CMB_GAN_RUN_ID', 'ENABLED', True$)
    end else
        Set_Property(@Window:'.CMB_GAN_RUN_ID', 'ENABLED', False$)
    end
    
return


FillCommentsTable:
    
    RDSNo = Get_Property(@Window:'.RDS_NO', 'TEXT')
    CassComments = Xlate('REACT_RUN', RDSNo, 'CASS_COMMENTS', 'X')
    Set_Property(@Window:'.EDB_CASS_COMMENTS', 'TEXT', CassComments)
    Set_Property(@Window, '@COMMENTS', CassComments)
    
return


EnableCloseRDSButton:
    
    RDSNo         = Get_Property(@Window:'.RDS_NO', 'TEXT')
    ReactRunRec   = Database_Services('ReadDataRow', 'REACT_RUN', RDSNo)
    DispComp      = ReactRunRec<REACT_RUN_DISP_COMPLETE$>
    DispCtrl      = @Window:'.PUB_CLOSE_RDS'
    
    If DispComp NE True$ then
        Set_Property(DispCtrl, 'ENABLED', True$)
    end else
        Set_Property(DispCtrl, 'ENABLED', False$)
    end
    
return


UpdateRDSStatus:
    
    RDSNo         = Get_Property(@Window:'.RDS_NO', 'TEXT')
    ReactRunRec   = Database_Services('ReadDataRow', 'REACT_RUN', RDSNo)
    DispComp      = ReactRunRec<REACT_RUN_DISP_COMPLETE$>
    If DispComp EQ True$ then
        Set_Property(@Window:'.LBL_RDS_STATUS', 'TEXT', 'CLOSED')
        Set_Property(@Window:'.LBL_RDS_STATUS', 'FORECOLOR', BRED$)
    end else
        Set_Property(@Window:'.LBL_RDS_STATUS', 'TEXT', 'OPEN')
        Set_Property(@Window:'.LBL_RDS_STATUS', 'FORECOLOR', BGREEN$)
    end
    
return


EnableLotAbortButton:
    
    RDSNo   = Get_Property(@Window:'.RDS_NO', 'TEXT')
    GrowthKey = RDSNo:'*GROWTH'
    GrowthStatus = Xlate('RUN_STAGE', GrowthKey, 'STATUS', 'X')
    // Need to check each wafer's current stage. If all wafers are at disposition, then
    // there is no need to enable the "Lot Abort" button.
    LotAbortAllowed = False$
    WfrIDs = Xlate('REACT_RUN', RDSNo, 'IN_WFR_ID', 'X')
    For each WfrID in WfrIDs using @VM setting vPos
        CurrStage = Gan_Services('GetCurrStage', WfrID)
        If (CurrStage _NEC 'DISP') and (CurrStage _NEC 'G_PACK') and (CurrStage _NEC 'RETAIN') then
            LotAbortAllowed = True$
        end
    Next WfrID
    If (GrowthStatus _EQC 'COMP') and (LotAbortAllowed EQ True$) then
        Set_Property(@Window:'.PUB_LOT_ABORT', 'ENABLED', True$)
    end else
        Set_Property(@Window:'.PUB_LOT_ABORT', 'ENABLED', False$)
    end
    
return


EnableImportMetDataButton:
    
    RDSNo          = Get_Property(@Window:'.RDS_NO', 'TEXT')
    UserAuthorized = Memberof(@User4, 'GAN_WIP_SUPERVISOR')
    RDSClosed      = Xlate('REACT_RUN', RDSNo, 'DISP_COMPLETE', 'X')
    Enabled = ( (RDSClosed NE True$) and (UserAuthorized EQ True$) )
    Set_Property(@Window:'.PUB_IMPORT_MET_DATA', 'ENABLED', Enabled)
    
return


ResetColorArrays:
    
    PSNo = Get_Property('PROD_SPEC.PROD_SPEC_ID', 'TEXT')
    PartNo = Get_Property(@Window, '@CURR_PART_NO')
    GaNParamStages = Get_Property(@Window, '@GAN_PARAM_STAGES')
    CellColorArray = ''
    For each Stage in GaNParamStages using @VM setting TabIndex       
        GaNParamConfigKey = PSNo:'*':PartNo:'*':Stage
        GaNParamConfigRec = Database_Services('ReadDataRow', 'GAN_PARAM_CONFIG', GaNParamConfigKey)
        ParamNames        = GaNParamConfigRec<GAN_PARAM_CONFIG.PARAM_NAME$>
        For each ParamName in ParamNames using @VM setting RowPos                             
            CellColorArray<TabIndex, RowPos, 1> = 'None'
            CellColorArray<TabIndex, RowPos, 2> = 'None'
            CellColorArray<TabIndex, RowPos, 3> = 'None'
            CellColorArray<TabIndex, RowPos, 4> = 'None'
            CellColorArray<TabIndex, RowPos, 5> = 'None'            
        Next ParamName                               
    Next Stage
    Set_Property(@Window, '@COLOR_ARRAY', CellColorArray)
    
return


SetupTabCtrl:
    
    GaNParamStages = Xlate('APP_INFO', 'GAN_PARAM_STAGES_DEMO', '', 'X')
    TabCtrl = @Window:'.OLE_TAB'
    NumTabs = DCount(GaNParamStages, @VM)
    Set_Property(TabCtrl, "OLE.TabCount", NumTabs)
    Convert @VM to ',' in GaNParamStages
    Convert '_' to ' ' in GaNParamStages
    Set_Property(TabCtrl, "OLE.CaptionList", GaNParamStages)
    FontArray = 'Segoe UI':@SVM:9:@SVM:700
    Set_Property(TabCtrl, "OLE.Font", FontArray)
    Set_Property(TabCtrl, "OLE.SelectFont", FontArray)
    
    // Qualify OLE events that we want to intercept
    Qualifier = ''
    Qualifier<1> = 1
    Qualifier<4> = 0 ; * process synchronously 
    Send_Message(TabCtrl, 'QUALIFY_EVENT', 'OLE.SelChanged', Qualifier)
    
return


SetupDispStageCtrl:
    
    DispStageCtrl      = @Window:'.OLE_DISP_STAGE_EDT'
    ScribeHeaderTitles = Get_Property(@Window, '@SCRIBE_HEADER_TITLES')
    HeaderRowTitles    = 'LSL':@VM:'Target':@VM:'USL':@VM:ScribeHeaderTitles
    DispRows           = 6
    DispCols           = 11
    DispStageDimArray  = DispCols:@FM:DispRows
    Set_Property(DispStageCtrl, "OLE.Dimension", DispStageDimArray)
*    DispStageList        = ''
*    For Row = 1 to DispRows
*        For Col = 1 to DispCols
*            DispStageList<Row, Col> = ' '
*        Next Col
*    Next Row
*    Set_Property(DispStageCtrl, "OLE.LIST", DispStageList)
    Set_Property(DispStageCtrl, "OLE.TitleList", HeaderRowTitles)
    
    HeaderFontArray   = 'Segoe UI':@SVM:8:@SVM:700
    Set_Property(DispStageCtrl, "OLE.HeaderFont[All; All]", HeaderFontArray)
    HeaderColArray = 181:@FM:True$:@FM:False$:@FM:False$
    Set_Property(DispStageCtrl, "OLE.HeaderColumn[1]", HeaderColArray)
    
    Set_Property(DispStageCtrl, "OLE.HeaderText[1; 1]", "Metrology Limits")
    
    
    // Disable resizing of columns as there is no need for this on this form
    StageColSize = Get_Property(DispStageCtrl, "OLE.DataColumn[1]")
    StageColSize<1> = 55
    StageColSize<3> = False$
    Set_Property(DispStageCtrl, "OLE.DataColumn[1-3]", StageColSize)
    StageColSize<1> = 96
    Set_Property(DispStageCtrl, "OLE.DataColumn[4-11]", StageColSize)
    Set_Property(DispStageCtrl, "OLE.CellProtection[All; All]", 'None')
    
    // Qualify OLE events that we want to intercept
    Qualifier = ''
    Qualifier<1> = 1
    Qualifier<4> = 0 ; * process synchronously (i.e. immediately)
    Send_Message(DispStageCtrl, 'QUALIFY_EVENT', 'OLE.OnClick', Qualifier)
    Send_Message(DispStageCtrl, 'QUALIFY_EVENT', 'OLE.OnHeaderClick', Qualifier)
    Send_Message(DispStageCtrl, 'QUALIFY_EVENT', 'OLE.OnContextMenuClick', Qualifier)
    
return


ReadCurrParams:
    
    *    RDSNo               = Get_Property(@Window:'.RDS_NO', 'TEXT')
    *    ReactRunRec         = Database_Services('ReadDataRow', 'REACT_RUN', RDSNo)
    *    ValidationDisFlags  = ReactRunRec<REACT_RUN_MISSING_DATA_VALID_DISABLED$>
    *    MetStageCtrl        = @Window:'.OLE_METROLOGY_EDT'
    *    MetStageList        = Get_Property(MetStageCtrl, "OLE.ColumnData[1]")
    *    Reactor             = 'R':Get_Property(@Window, '@REACTOR')
    *    RunNo               = Get_Property(@Window:'.CMB_GAN_RUN_ID', 'TEXT')
    *    Scribes             = Get_Property(@Window, '@SCRIBES')
    *    InWfrIDs            = Get_Property(@Window, '@WFRIDS')
    *    
    *    PSNo = Get_Property(@Window, '@PS_NO')
    *    If PSNo NE '' then
    *        GaNParamStages = Xlate('APP_INFO', 'GAN_PARAM_STAGES', '', 'X')   
    *        GaNParamKeys   = Xlate('REACT_RUN', RDSNo, 'GAN_PARAM_KEYS', 'X')
    *        ParameterList  = ''
    *        ParamNameList  = ''
    *        MetNameList    = ''
    *        CellColorArray = ''
    *        ParamOutOfSpec = ''
    *        
    *        GaNParamKeysPrime = SRP_Array('Rotate', GaNParamKeys, @VM, '*')
    *        ConfigGaNParamStages = GaNParamKeysPrime<0, 2>
    *        Set_Property(@Window, '@GAN_PARAM_STAGES', GaNParamStages)
    *        Convert '*' to @VM in ConfigGaNParamStages
    *        
    *        For each GaNParamKey in GaNParamKeys using @VM
    * 
    *            MetType = Field(GaNParamKey, '*', 2)
    *            Locate MetType in GaNParamStages using @VM setting TabPos then
    * 
    *                StageID     = MetType
    *                StageDesc   = GaN_Services('GetStageDesc', MetType)          
    *                ToolType    = MetType
    *                
    *                GaNParamRec = Database_Services('ReadDataRow', 'GAN_PARAMS', GaNParamKey)
    *                PartNo      = Field(GaNParamKey, '*', 1)               
    *                ParamNames  = GaNParamRec<GAN_PARAMS.PARAM_NAME$>
    *                MetNames    = GaNParamRec<GAN_PARAMS.MET_NAME$>
    *                
    *                Locate StageDesc in MetStageList using @VM setting StageRowPos then
    *                    Tool = Get_Property(@Window : '.OLE_METROLOGY_EDT', 'OLE.CellText[2; ':StageRowPos:']')
    *                end
    *                
    *                MetParameter    = ''
    *                ParamValues     = ''
    *                MetData         = ''
    *                
    *                For each WfrID in InWfrIDs using @VM setting WaferIndex
    *                    
    *                    Convert '*' to '.' in WfrID
    *                    Begin Case                   
    *                        Case StageID EQ 'UV_PRE'
    *                            // Check if UV stage exists
    *                            UVStageWfrKey = RDSNo:'*UV*':WfrID
    *                            If RowExists('RUN_STAGE_WFR', UVStageWfrKey) then
    *                                // Display this on the UV_PRE line
    *                                RunStageWfrKey = UVStageWfrKey
    *                            end else
    *                                RunStageWfrKey = RDSNo:'*':StageID:'*':WfrID
    *                            end
    *                        Case StageID EQ 'CAN_PRE'
    *                            // Check if CAN stage exists
    *                            CanStageWfrKey = RDSNo:'*CAN*':WfrID
    *                            If RowExists('RUN_STAGE_WFR', CanStageWfrKey) then
    *                                // Display this on the CAN_PRE line
    *                                RunStageWfrKey = CanStageWfrKey
    *                            end else
    *                                RunStageWfrKey = RDSNo:'*':StageID:'*':WfrID
    *                            end    
    *                        Case Otherwise$
    *                            RunStageWfrKey = RDSNo:'*':StageID:'*':WfrID                           
    *                    End Case 
    *                    If RowExists('RUN_STAGE_WFR', RunStageWfrKey) then
    *                        RunStageWfrRec       = Database_Services('ReadDataRow', 'RUN_STAGE_WFR', RunStageWfrKey)
    *                        TheseParamValues     = RunStageWfrRec<RUN_STAGE_WFR_MET_PARAM_VALUES$>
    *                        TheseOutOfSpecValues = RunStageWfrRec<RUN_STAGE_WFR_PARAM_OUT_OF_SPEC$>                        
    *                        If Index(TheseParamValues, @SVM, 1) GT 0 then
    *                            For each FlagSet in TheseOutOfSpecValues using @VM setting ParamIndex
    *                                ValueSet = TheseParamValues<0, ParamIndex>
    *                                NumVals  = DCount(ValueSet, @SVM)
    *                                If NumVals GT 1 then
    *                                    ParamValues<WaferIndex, ParamIndex> = 'Multi'
    *                                    OutOfSpec = ( Sum(TheseOutOfSpecValues<1, ParamIndex>) > 0 )                                    
    *                                end else
    *                                    ParamValues<WaferIndex, ParamIndex> = ValueSet
    *                                    OutOfSpec = TheseOutOfSpecValues<1, ParamIndex>
    *                                end
    *                                ParamOutOfSpec<WaferIndex, ParamIndex> = OutOfSpec
    *                            Next FlagSet
    *                        end else
    *                            ParamValues<WaferIndex>    = TheseParamValues
    *                            ParamOutOfSpec<WaferIndex> = TheseOutOfSpecValues
    *                        end
    *                    end else
    *                        ParamValues<WaferIndex> = ''
    *                        ParamOutOfSpec<WaferIndex> = ''
    *                    end
    *                Next WfrID
    *                
    *                ParamValues    = SRP_Array('Rotate', ParamValues, @FM, @VM)
    *                ParamOutOfSpec = SRP_Array('Rotate', ParamOutOfSpec, @FM, @VM)
    *                
    *                Convert @VM to @SVM in ParamValues
    *                Convert @VM to @SVM in ParamOutOfSpec
    *                Convert @FM to @VM in ParamOutOfSpec
    * 
    *                ParamOutOfSpec = SRP_Array('Rotate', ParamOutOfSpec, @VM, @SVM)
    *                For each WfrID in InWfrIDs using @VM setting WaferIndex
    *                    ValidDisabled  = ValidationDisFlags<0, WaferIndex>
    *                    WfrParamOutOfSpec = ParamOutOfSpec<0, WaferIndex>         
    *                    If ValidDisabled EQ True$ then
    *                        Swap '-1' with 'SlateBlue L=75' in WfrParamOutOfSpec
    *                        Swap 1    with 'SlateBlue L=75' in WfrParamOutOfSpec
    *                    end else
    *                        Swap '-1' with 'Yellow'   in WfrParamOutOfSpec
    *                    end
    *                    ParamOutOfSpec<0, WaferIndex> = WfrParamOutOfSpec       
    *                Next WfrID
    *                ParamOutOfSpec = SRP_Array('Rotate', ParamOutOfSpec, @VM, @SVM)
    *                
    *                Swap 1 with 'Red'      in ParamOutOfSpec
    *                Swap 0 with 'None'     in ParamOutOfSpec
    *                
    *                CellColorArray<TabPos> = ParamOutOfSpec                      
    *                For each ParamName in ParamNames using @VM setting RowPos
    *                    
    *                    MetName = MetNames<0, RowPos>                    
    *                    MetNameList<TabPos, RowPos>      = ParamName
    *                    ParamNameList<TabPos, RowPos>    = MetName
    *                    ParameterList<TabPos, RowPos, 1> = GaNParamRec<GAN_PARAMS.LSL$, RowPos>
    *                    ParameterList<TabPos, RowPos, 2> = GaNParamRec<GAN_PARAMS.TARGET$, RowPos>
    *                    ParameterList<TabPos, RowPos, 3> = GaNParamRec<GAN_PARAMS.USL$, RowPos>
    *                    If ParamValues NE '' then ParameterList<TabPos, RowPos, 4> = ParamValues<RowPos>                    
    *                Next ParamName
    *                
    *            end     
    *        Next GaNParamKey
    *        
    *        Set_Property(@Window, '@NAME_LIST', ParamNameList)
    *        Set_Property(@Window, '@VALUE_LIST', ParameterList)
    *        Set_Property(@Window, '@ORIG_VALUE_LIST', ParameterList)
    *        Set_Property(@Window, '@ORIG_MET_LIST', MetNameList)
    *        Set_Property(@Window, '@COLOR_ARRAY', CellColorArray)
    *        
    *    end
    
return


FillDispStageCtrl:
    
    DispStageCtrl = @Window:'.OLE_DISP_STAGE_EDT'
    TabCtrl       = @Window:'.OLE_TAB'
    TabIndex      = Get_Property(TabCtrl, 'OLE.SelectedTab')
    HeaderTitles  = '' ; //Get_Property(@Window, '@NAME_LIST')<TabIndex>
    ParameterList = '' ; //Get_Property(@Window, '@VALUE_LIST')<TabIndex>   
    NumCols       = 11   
    NumRows       = 6
    
    
*    DispStageDimArray = NumCols:@FM:NumRows
*    Set_Property(DispStageCtrl, "OLE.Dimension", DispStageDimArray)
*    DispStageList     = ''
*    For Row = 1 to NumRows
*        For Col = 1 to NumCols
*            DispStageList<Row, Col> = ' '
*        Next Col
*    Next Row
*    Set_Property(DispStageCtrl, "OLE.LIST", DispStageList)
    
    
*    DispStageDimArray = NumCols:@FM:NumRows
*    Set_Property(DispStageCtrl, "OLE.Dimension", DispStageDimArray)
*    Convert @VM to @FM in ParameterList
*    Convert @SVM to @VM in ParameterList
*    Set_Property(@Window:'.OLE_DISP_STAGE_EDT', 'OLE.LIST', ParameterList)
    
*    Convert @VM to @FM in HeaderTitles
*    Convert @SVM to @VM in HeaderTitles
    HeaderTitles    = 'Limit 1'
    HeaderTitles<2> = 'Limit 2'
    HeaderTitles<3> = 'Limit 3'
    HeaderTitles<4> = 'Limit 4'
    HeaderTitles<5> = 'Limit 5'
    HeaderTitles<6> = 'Limit 6'
    For each HeaderTitle in HeaderTitles using @FM setting RowIndex
        Set_Property(DispStageCtrl, "OLE.HeaderText[1; ":RowIndex + 1:"]", HeaderTitle)
    Next HeaderTitle
    
    Set_Property(DispStageCtrl, "OLE.HeaderAlignment[1; 2-":NumRows + 1:"]", 'C':@FM:'L':@FM:'L')
    Set_Property(DispStageCtrl, "OLE.CellAlignment[All; All]", 'C':@FM:'R':@FM:'L')
    Set_Property(DispStageCtrl, "OLE.HeaderAlignment[All; 1]", 'C':@FM:'C':@FM:'L')
    
    // Color headers
    Set_Property(DispStageCtrl, "OLE.HeaderColors[All; 1]", @FM:"{200, 200, 200}")
    // Color limit columns
    Set_Property(DispStageCtrl, "OLE.CellColors[1-3; All]", @FM:"{240, 240, 240}")
    // Bold limit text
    BoldFontArray   = 'Segoe UI':@SVM:8:@SVM:700
    Set_Property(DispStageCtrl, "OLE.CellFont[1-3; All]", BoldFontArray)
    
    GoSub ColorCells   
    
return


ColorCells:
    
    TabIndex       = Get_Property(@Window:'.OLE_TAB', 'OLE.SelectedTab')
    CellColorArray = Get_Property(@Window, '@COLOR_ARRAY')<TabIndex>
    DispStageCtrl  = @Window:'.OLE_DISP_STAGE_EDT'
    DimArray       = Get_Property(DispStageCtrl, "OLE.Dimension")
    NumCols        = DimArray<1>
    NumRows        = DimArray<2>
    For Row = 1 to NumRows
        For Col = 1 to NumCols
            CellColor = CellColorArray<0, Row, Col>
            If CellColor EQ '' then CellColor = 'None'
            Set_Property(DispStageCtrl, 'OLE.CellColors[':Col+3:';':Row:']', @FM:CellColor)
        Next Col
    Next Row
    
return


ColorTabs:
    
    TabCtrl        = @Window:'.OLE_TAB'
    RDSNo          = Get_Property(@Window:'.RDS_NO', 'TEXT')
    ReactRunRec    = Database_Services('ReadDataRow', 'REACT_RUN', RDSNo)
    GaNParamStages = Get_Property(@Window, '@GAN_PARAM_STAGES')
    CellColorArray = Get_Property(@Window, '@COLOR_ARRAY')
    WfrStages      = ReactRunRec<REACT_RUN_WFR_STAGE$>    
    For each Stage in GaNParamStages using @VM setting TabIndex
        ThisCellColorArray = CellColorArray<TabIndex>
        GoSub ColorTab
    Next Stage
    
return


EnableTabs:
    
    SelTabIndex    = Get_Property(@Window:".OLE_TAB", "OLE.SelectedTab")
    GaNParamStages = Get_Property(@Window, '@GAN_PARAM_STAGES')
    NameArray      = Get_Property(@Window, '@NAME_LIST')
    For each Stage in GaNParamStages using @VM setting TabIndex
        ThisNameArray = NameArray<TabIndex>
        GoSub EnableTab
    Next Stage
    
    SelTabVisible = Get_Property(@Window:'.OLE_TAB', 'OLE.TabVisible[':SelTabIndex:']')
    If SelTabVisible EQ False$ then
        For TabIndex = 1 to 12
            TabVisible = Get_Property(@Window:'.OLE_TAB', 'OLE.TabVisible[':TabIndex:']')        
        Until TabVisible EQ True$
        Next TabIndex
        If TabVisible EQ True$ then Set_Property(@Window:".OLE_TAB", "OLE.SelectedTab", TabIndex)
    end
    
return


EnableTab:
    
    If ThisNameArray EQ '' then
        Set_Property(@Window:'.OLE_TAB', 'OLE.TabVisible[':TabIndex:']', False$)
    end else
        Set_Property(@Window:'.OLE_TAB', 'OLE.TabVisible[':TabIndex:']', True$) 
    end
    
return


ColorTab:
    
    GaNMetStages  = Database_Services('ReadDataRow', 'APP_INFO', 'GAN_MET_STAGES')
    Locate Stage in GaNMetStages using @FM setting sPos then
        PostSplit = (sPos GT 6)
    end else
        PostSplit = False$
    end
    
    WfrChar       = (Sum(ReactRunRec<REACT_RUN_CHAR_WFR_FLAG$>) GT 0)
    NumRows       = DCount(ThisCellColorArray, @VM)
    NumCols       = DCount(ThisCellColorArray, @SVM)    
    MetFailed     = False$
    MetMissing    = False$
    ValidDisabled = False$
    
    For Row = 1 to NumRows        
        For Col = 1 to NumCols
            CellColor = ThisCellColorArray<0, Row, Col> 
            If CellColor EQ 'Red' then
                MetFailed = True$
            end
            If CellColor EQ 'Yellow' then
                MetMissing = True$
            end
            If CellColor EQ 'SlateBlue L=75' then
                ValidDisabled = True$
            end
        Until MetFailed EQ True$
        Next Col
    Until MetFailed EQ True$
    Next Row
    
    Begin Case
        Case MetFailed EQ True$
            Colors = ""
            Colors<1, 2> = "Vertical(Gradient(Red L=80, Red L=90), Border(Red))"
            Colors<2, 2> = "Vertical(Gradient(Red L=90, Red L=95), Border(Red))"
            Colors<3, 2> = "Vertical(Gradient(Red L=85, Red L=95), Border(Red))"
            Colors<4, 1> = "Gray"
            Colors<4, 2> = "Vertical(Gradient(Gray L=80, Gray L=90), Border(Gray))"
            Colors<5>    = "Vertical(Gradient(Red L=95, Red L=80), Border(Red))"
            Set_Property(TabCtrl, "OLE.TabColors[":TabIndex:"]", Colors)
            
        Case MetMissing EQ True$
            Colors = ""
            Colors<1, 2> = "Vertical(Gradient(Yellow L=80, Yellow L=90), Border(Yellow))"
            Colors<2, 2> = "Vertical(Gradient(Yellow L=90, Yellow L=95), Border(Yellow))"
            Colors<3, 2> = "Vertical(Gradient(Yellow L=85, Yellow L=95), Border(Yellow))"
            Colors<4, 1> = "Gray"
            Colors<4, 2> = "Vertical(Gradient(Gray L=80, Gray L=90), Border(Gray))"
            Colors<5>    = "Vertical(Gradient(Yellow L=95, Yellow L=80), Border(Yellow))"
            Set_Property(TabCtrl, "OLE.TabColors[":TabIndex:"]", Colors)
            
        Case ValidDisabled EQ True$
            Colors = ""
            Colors<1, 2> = "Vertical(Gradient(Blue L=80, Blue L=90), Border(Blue))"
            Colors<2, 2> = "Vertical(Gradient(Blue L=90, Blue L=95), Border(Blue))"
            Colors<3, 2> = "Vertical(Gradient(Blue L=85, Blue L=95), Border(Blue))"
            Colors<4, 1> = "Gray"
            Colors<4, 2> = "Vertical(Gradient(Gray L=80, Gray L=90), Border(Gray))"
            Colors<5>    = "Vertical(Gradient(Blue L=95, Blue L=80), Border(Blue))"
            Set_Property(TabCtrl, "OLE.TabColors[":TabIndex:"]", Colors)
            
        Case ( ( (PostSplit EQ True$) and (WfrChar EQ False$) ) or (NumRows EQ 0) )
            Null
            
        Case Otherwise$
            Colors = ""
            Colors<1, 2> = "Vertical(Gradient(Green L=80, Green L=90), Border(Green))"
            Colors<2, 2> = "Vertical(Gradient(Green L=90, Green L=95), Border(Green))"
            Colors<3, 2> = "Vertical(Gradient(Green L=85, Green L=95), Border(Green))"
            Colors<4, 1> = "Gray"
            Colors<4, 2> = "Vertical(Gradient(Gray L=80, Gray L=90), Border(Gray))"
            Colors<5>    = "Vertical(Gradient(Green L=95, Green L=80), Border(Green))"
            Set_Property(TabCtrl, "OLE.TabColors[":TabIndex:"]", Colors)
    End Case
    
return


SetupDispEDT:
    
    DispCtrl = @Window:'.OLE_DISP_EDT'         
    // Disable resizing of the header row and header column
    // Resize header column to fit contents
    HeaderRowArray = Get_Property(DispCtrl, "OLE.HeaderRow[1]")
    HeaderColArray = Get_Property(DispCtrl, "OLE.HeaderColumn[1]")
    HeaderRowArray<3> = False$
    HeaderColArray<1> = 80
    HeaderColArray<3> = False$
    Set_Property(DispCtrl, "OLE.HeaderColumn[1]", HeaderColArray)
    Set_Property(DispCtrl, "OLE.HeaderRow[1]", HeaderRowArray)
    // Disable resizing of columns as there is no need for this on this form
    StageColSize = Get_Property(DispCtrl, "OLE.DataColumn[1]")
    StageColSize<3> = False$
    Set_Property(DispCtrl, "OLE.DataColumn[All]", StageColSize)
    WfrColSize = Get_Property(DispCtrl, "OLE.DataColumn[1]")
    // Set column widths  
    WfrColSize<1> = 30
    Set_Property(DispCtrl, "OLE.DataColumn[":COL$DISP_SLOT:"]", WfrColSize)
    WfrColSize<1> = 79
    Set_Property(DispCtrl, "OLE.DataColumn[":COL$DISP_WFR_ID:"-":COL$DISP_SCRIBE:"]", WfrColSize)
    WfrColSize<1> = 50
    Set_Property(DispCtrl, "OLE.DataColumn[":COL$DISP_GRADE:"]", WfrColSize)
    WfrColSize<1> = 244
    Set_Property(DispCtrl, "OLE.DataColumn[":COL$DISP_REASON:"]", WfrColSize)   
    WfrColSize<1> = 69
    Set_Property(DispCtrl, "OLE.DataColumn[":COL$DISP_RDS_NCR:"-":COL$DISP_WMO_NCR:"]", WfrColSize)
    WfrColSize<1> = 81
    Set_Property(DispCtrl, "OLE.DataColumn[":COL$DISP_SHIP_ID:"]", WfrColSize)
    WfrColSize<1> = 70
    Set_Property(DispCtrl, "OLE.DataColumn[":COL$DISP_RETAIN_BOX:"-":COL$DISP_RETAIN_SLOT:"]", WfrColSize)
    WfrColSize<4> = True$ ; // Set this column autosize property to true
    Set_Property(DispCtrl, "OLE.DataColumn[":COL$DISP_ROOT_CAUSE:"]", WfrColSize)   
    // Disable resizing of rows as there is no need for this on this form
    RowSizeProps = Get_Property(DispCtrl, "OLE.DataRow[1]")
    RowSizeProps<3> = False$
    Set_Property(DispCtrl, "OLE.DataRow[All]", RowSizeProps)
    // Disable scrollbars
    Set_Property(DispCtrl, "OLE.ScrollBarsVisible", 'N':@FM:'N')              
    // Color headers
    Set_Property(DispCtrl, "OLE.HeaderColors[All; 1]", @FM:"{200, 200, 200}")
    // Set edit mode of cells if and when we enable them
    EditArray    = 'E'
    EditArray<2> = 'O'
    Set_Property(DispCtrl, "OLE.CellEditMode[All; All]", EditArray)
    // Disable editing of all cells
    Set_Property(DispCtrl, "OLE.CellProtection[All; All]", 'None')
    // Do not allow scrolling past the bottom right cell.
    // This prevents scrolling when tabbing out of the bottom right cell.
    Set_Property(DispCtrl, "OLE.FreezePos", COL$DISP_RETAIN_SLOT:@FM:8)															   
    
return


Abort:
    
    Utility('DESTROY', @Window)
    
return


PopulateControls:
    
    RDSNo = 123456
    WONo  = 123456
    PSNo  = 1234
    Set_Property(@Window:'.RDS_NO', 'TEXT', RDSNo)
    Set_Property(@Window:'.WO_NO', 'TEXT', WONo)
    Set_Property(@Window:'.PS_NO', 'TEXT', PSNo)
    
    Set_Property(@Window, '@RDSNO', RDSNo)
    Def = ""
    Def<MCAPTION$>   = "Loading..."
    Def<MTYPE$>      = "G"
    Def<MEXTENT$>    = 100 ; // 100%
    Def<MTEXTWIDTH$> = 400
    Def<MCOL$>       = -2        ;* message h-pos in pixels, or -2 (center screen, the default), -1 (center parent)
    Def<MROW$>       = -2        ;* message v-pos in pixels
    MsgUp  = Msg(@Window, Def)   
    
    Set_Property(@Window, 'REDRAW', False$)
    Set_Property(@Window:'.OLE_REACTOR_EDT'     , "OLE.Redraw", False$)
    Set_Property(@Window:'.OLE_METROLOGY_EDT'   , "OLE.Redraw", False$)
    Set_Property(@Window:'.OLE_DISP_EDT'        , "OLE.Redraw", False$)
    Set_Property(@Window:'.OLE_DISP_STAGE_EDT'  , "OLE.Redraw", False$)
    Set_Property(@Window:'.OLE_NCR_EDT'         , "OLE.Redraw", False$)
    
    RunPriorities = '':@FM:'P1':@FM:'P2':@FM:'P3'
    Set_Property(@Window:'.COMBO_PRIORITY', 'LIST', RunPriorities)
    
    If RDSNo Not(Num(RDSNo)) then
        * update the gauge
        Msg(@Window, MsgUp, 10, MSGINSTUPDATE$)
        // Check if run info scribes have been updated
        InWfrIDs    = ''
        Scribes     = ''
        For WfrIndex = 1 to 8
            InWfrIDs<0, WfrIndex> = '123456*1*':WfrIndex
            Scribes<0, WfrIndex>  = 'Scribe0':WfrIndex
        Next WfrIndex
        RunPriority       = 1
        Set_Property(@Window:'.COMBO_PRIORITY', 'TEXT', RunPriority)
        GaNRunID          = '9900001abcde'
        * update the gauge
        Msg(@Window, MsgUp, 20, MSGINSTUPDATE$)
        SPCWaferTrackPart = 'WTPart01'
        Set_Property(@Window:'.EDL_WAFER_TRACK_PART', 'TEXT', SPCWaferTrackPart)
        Reactor           = 99
        Set_Property(@Window, '@REACTOR', Reactor)
        * update the gauge
        Msg(@Window, MsgUp, 30, MSGINSTUPDATE$)
        Convert @Upper.Case to @Lower.Case in GaNRunID
        Set_Property(@Window : '.CMB_GAN_RUN_ID', 'LIST', GaNRunID)
        Set_Property(@Window : '.CMB_GAN_RUN_ID', 'SELPOS', 1)
        * update the gauge
        Msg(@Window, MsgUp, 50, MSGINSTUPDATE$)
        GaNEtchIDs        = '9900000etch'
        Convert @VM to @FM in GaNEtchIDs
        NumEtchIDs     = DCount(GaNEtchIDs, @FM)
        Set_Property(@Window : '.CMB_GAN_ETCH_ID', 'LIST', GaNEtchIDs)
        // Select the last external etch ID to display by default
        Set_Property(@Window : '.CMB_GAN_ETCH_ID', 'SELPOS', NumEtchIDs)
        GaNEtchRecipes = 'EtchRecipe1234'
        LastEtchRecipe = GaNEtchRecipes<0, NumEtchIDs>
        Set_Property(@Window : '.ETCH_RECIPE', 'TEXT', LastEtchRecipe)
        
        GoSub Setup_OLE_Controls
        // Need to check if any wafers have made it to disposition. If so, then check the Disposition Report
        // for any updates.
        * update the gauge
        Msg(@Window, MsgUp, 60, MSGINSTUPDATE$)
*        WfrIDs = ReactRunRec<REACT_RUN_IN_WFR_ID$>
*        If WfrIDs NE '' then
*            For each WfrID in WfrIDs using @VM setting vPos
*                MetDone = GaN_Services('GetMetrologyStatus', WfrID)
*                If MetDone EQ True$ then
*                    Set_Property(@Window:'.PUB_UPDATE_DISP', 'ENABLED', True$)
*                end
*            Until MetDone EQ True$
*            Next WfrID
*        end
        GoSub VerifyRecipe
        * update the gauge
        Msg(@Window, MsgUp, 70, MSGINSTUPDATE$)
        GoSub FillDispEditTable
        * update the gauge
        Msg(@Window, MsgUp, 80, MSGINSTUPDATE$)
        GoSub FillNCREditTable
        * update the gauge
        Msg(@Window, MsgUp, 90, MSGINSTUPDATE$)
        GoSub FillCommentsTable
    end             
    GoSub EnableRunIDComboBox
    GoSub EnableCloseRDSButton
    GoSub UpdateRDSStatus
    GoSub EnableLotAbortButton
    GoSub EnableImportMetDataButton
    GoSub FillDispStageCtrl
    * update the gauge
    Msg(@Window, MsgUp, 100, MSGINSTUPDATE$)
    Msg(@Window, MsgUp)         ;* take down the gauge
    
    Set_Property(@Window, 'REDRAW', True$)
    Set_Property(@Window:'.OLE_REACTOR_EDT'     , "OLE.Redraw", True$)
    Set_Property(@Window:'.OLE_METROLOGY_EDT'   , "OLE.Redraw", True$)
    Set_Property(@Window:'.OLE_DISP_EDT'        , "OLE.Redraw", True$)
    Set_Property(@Window:'.OLE_DISP_STAGE_EDT'  , "OLE.Redraw", True$)
    Set_Property(@Window:'.OLE_NCR_EDT'         , "OLE.Redraw", True$) 
    
return

