Exemple #1
0
    def __init__(self, master, instName, **kargs):

        RO.Wdg.InputContFrame.__init__(self, master, **kargs)

        self.cannotPauseText = ""
        self.normalPauseText = ""

        self.tuiModel = TUI.TUIModel.getModel()
        self.expModel = ExposeModel.getModel(instName)

        row = 0

        self.expStatusWdg = ExposeStatusWdg.ExposeStatusWdg(
            self,
            instName,
        )
        self.expStatusWdg.grid(row=0, column=0, sticky="ew")
        row += 1

        Tkinter.Frame(
            self,
            #           relief="ridge", # doesn't do anything; why not?
            #           border=2,       # doesn't do anything; why not?
            bg="black",
        ).grid(row=row, column=0, sticky="ew")
        row += 1

        #         self.imageDispWdg = RO.Wdg.GrayImageDispWdg.GrayImageWdg(
        #             master = self,
        #         )
        #         self.imageDispWdg.grid(row=row, column=0, sticky="news")
        #         self.grid_rowconfigure(row, weight=1)
        #         self.grid_columnconfigure(0, weight=1)
        #         row += 1
        #
        #         Tkinter.Frame(self,
        # #           relief="ridge", # doesn't do anything; why not?
        # #           border=2,       # doesn't do anything; why not?
        #             bg = "black",
        #         ).grid(row=row, column=0, sticky="ew")
        #         row += 1

        self.expInputWdg = ExposeInputWdg.ExposeInputWdg(
            self,
            instName,
            #           relief="ridge",
            #           border=1,
        )
        self.expInputWdg.grid(row=row, column=0, sticky="ew")
        row += 1

        self._stateTracker = self.expInputWdg.getStateTracker()
        self.getStateTracker = self.expInputWdg.getStateTracker

        self.statusBar = RO.Wdg.StatusBar(
            self,
            dispatcher=self.tuiModel.dispatcher,
            prefs=self.tuiModel.prefs,
            playCmdSounds=True,
        )
        self.statusBar.grid(row=row, column=0, sticky="ew")
        row += 1

        butFrame = Tkinter.Frame(self)

        self.startWdg = RO.Wdg.Button(
            master=butFrame,
            text="Start",
            command=self.doExpose,
            helpURL=_HelpPrefix + "StartButton",
        )
        self.startWdg.pack(side="left")

        def makeStopWdg(name, doShow=True, canDoExp=True):
            """Creates and packs a stop button;
            Inputs:
            - name      one of pause, stop or abort (lowercase!)
            - doShow    show this widget?
            - canDoExp  if false, can only handle sequence (for help string)
            """
            helpText = {
                ("pause", True): "Pause or resume the exposure",
                ("pause", False): "Pause or resume the exposure sequence",
                ("stop", True): "Stop the exposure and save the data",
                ("stop", False): "Finish the exposure and then stop",
                ("abort", True): "Stop the exposure and discard the data",
                ("abort", False): "Finish the expsure and discard the data",
            }[(name, canDoExp)]

            if canDoExp:
                wdgText = name.capitalize()
            else:
                wdgText = "%s Seq" % (name.capitalize())

            wdg = RO.Wdg.Button(
                master=butFrame,
                text=wdgText,
                helpText=helpText,
                helpURL=_HelpPrefix + "%sButton" % (name, ),
            )
            if name == "pause":
                self.normalPauseText = helpText
                self.pauseWdgPauseText = wdgText
                if canDoExp:
                    self.pauseWdgResumeText = "Resume"
                    wdg["width"] = 6
                else:
                    self.pauseWdgResumeText = "Resume Seq"
                    wdg["width"] = 10

            wdg["command"] = RO.Alg.GenericCallback(
                self.doStop,
                wdg,
            )
            if doShow:
                wdg.pack(side="left")
            return wdg

        instInfo = self.expModel.instInfo
        self.pauseWdg = makeStopWdg(
            "pause", instInfo.canPauseExp or instInfo.canPauseSeq,
            instInfo.canPauseExp)
        self.stopWdg = makeStopWdg("stop", instInfo.canStopExp
                                   or instInfo.canStopSeq, instInfo.canStopExp)
        self.abortWdg = makeStopWdg("abort", instInfo.canAbortExp,
                                    instInfo.canAbortExp)

        self.configWdg = RO.Wdg.Button(
            master=butFrame,
            text="Config...",
            command=self.doConfig,
            helpText="Open the %s configure window" % self.expModel.instName,
            helpURL=_HelpPrefix + "ConfigButton",
        )
        self.configWdg.pack(side="right")

        butFrame.grid(row=row, column=0, sticky="ew")
        row += 1

        self.expModel.seqState.addIndexedCallback(self._seqStatusCallback, 5)
Exemple #2
0
#!/usr/bin/env python
"""Data for testing various DIS exposure widgets

To do:
- change timestamps to valid values

History:
2003-10-22 ROwen    Modified data to match new hub.
"""
import TUI.TUIModel
import ExposeModel

tuiModel = TUI.TUIModel.getModel(True)
dispatcher = tuiModel.dispatcher
progID = tuiModel.getProgID()
expModel = ExposeModel.getModel("DIS")
cmdr = tuiModel.getCmdr()

MainDataSet = {
    "disFiles": (cmdr, "tycho.apo.nmsu.edu", "/export/images/",
                 progID.upper() + "/", "", "test0005b.fits", "test0005r.fits"),
    "disNextPath": (cmdr, "", "test", "0006", ".fits"),
}

# each element of animDataSet is a full set of data to be dispatched,
# hence each element is a list of keyvar, value tuples
AnimDataSet = (
    {
        "disSeqState": (cmdr, "object", "6.0", "1", "1", "running"),
        "disExpState": (cmdr, "flushing", "2003...", "0", "0"),
    },
    def __init__(self,
        master,
        instName,
        helpURL = None,
    **kargs):
        Tkinter.Frame.__init__(self, master, **kargs)
        if helpURL is None:
            helpURL = _HelpURL

        self.expModel = ExposeModel.getModel(instName)
        self.tuiModel = self.expModel.tuiModel
        self.wasExposing = None # was last exposure state integrating or resume? True, False or None if unknown
        self.wasFailed = None # was last exposure state failed or failing? True, False or None if unknown
        self.minExposureBeginsSoundTime = 0
        gr = RO.Wdg.Gridder(master=self, sticky="w")

        self.seqStateWdg = RO.Wdg.StrLabel(
            master = self,
            helpText = "Status of exposure sequence",
            helpURL = helpURL,
            anchor="w",
            width = _DataWidth,
        )
        gr.gridWdg("Seq Status", self.seqStateWdg, sticky="ew")
        
        stateFrame = Tkinter.Frame(self)
        self.expStateWdg = RO.Wdg.StrLabel(
            master = stateFrame,
            helpText = "Status of current exposure",
            helpURL = helpURL,
            anchor="w",
            width = 11
        )
        self.expStateWdg.pack(side="left")
        self.expTimer = RO.Wdg.TimeBar(
            master = stateFrame,
            valueFormat = "%3.1f sec",
            isHorizontal = True,
            autoStop = True,
            helpText = "Status of current exposure",
            helpURL = helpURL,
        )
        gr.gridWdg("Exp Status", stateFrame, sticky="ew")

        self.userWdg = RO.Wdg.StrLabel(
            master = self,
            helpText = "Who is taking this exposure",
            helpURL = helpURL,
            anchor="w",
            width = _DataWidth,
        )
        gr.gridWdg("User", self.userWdg, sticky="ew")

        self.commentWdg = RO.Wdg.StrLabel(
            master = self,
            helpText = "User's comment, if any",
            helpURL = helpURL,
            anchor="w",
            width = _DataWidth,
        )
        gr.gridWdg("Comment", self.commentWdg, sticky="ew")
        self.expModel.comment.addROWdg(self.commentWdg)

        self.fileNameWdgs = []
        for camName in self.expModel.instInfo.camNames:
            if camName:
                helpSuffix = " from %s camera" % (camName.lower())
                labelStr = "%s File" % (camName.capitalize())
            else:
                helpSuffix = ""
                labelStr = "File"

            wdg = RO.Wdg.StrLabel(
                master = self,
                helpText = "File for current exposure" + helpSuffix,
                helpURL = helpURL,
                anchor = "w",
                width = _DataWidth,
            )
            self.fileNameWdgs.append(wdg)

            gr.gridWdg(labelStr, wdg, sticky="ew")
        
        self.columnconfigure(1, weight=1)

        self.expModel.newFiles.addCallback(self._updNewFiles)
        self.expModel.expState.addCallback(self._updExpState)
        self.expModel.seqState.addCallback(self._updSeqState)
Exemple #4
0
    def __init__(self,
        master,
        instName,
    **kargs):

        RO.Wdg.InputContFrame.__init__(self, master, **kargs)
        
        self.cannotPauseText = ""
        self.normalPauseText = ""
        
        self.tuiModel = TUI.TUIModel.getModel()
        self.expModel = ExposeModel.getModel(instName)
        
        row = 0

        self.expStatusWdg = ExposeStatusWdg.ExposeStatusWdg(
            self,
            instName,
        )
        self.expStatusWdg.grid(row=0, column=0, sticky="ew")
        row += 1
        
        Tkinter.Frame(self,
#           relief="ridge", # doesn't do anything; why not?
#           border=2,       # doesn't do anything; why not?
            bg = "black",
        ).grid(row=row, column=0, sticky="ew")
        row += 1

#         self.imageDispWdg = RO.Wdg.GrayImageDispWdg.GrayImageWdg(
#             master = self,
#         )
#         self.imageDispWdg.grid(row=row, column=0, sticky="news")
#         self.grid_rowconfigure(row, weight=1)
#         self.grid_columnconfigure(0, weight=1)
#         row += 1
# 
#         Tkinter.Frame(self,
# #           relief="ridge", # doesn't do anything; why not?
# #           border=2,       # doesn't do anything; why not?
#             bg = "black",
#         ).grid(row=row, column=0, sticky="ew")
#         row += 1

        self.expInputWdg = ExposeInputWdg.ExposeInputWdg(
            self,
            instName,
#           relief="ridge",
#           border=1,
        )
        self.expInputWdg.grid(row=row, column=0, sticky="ew")
        row += 1
        
        self._stateTracker = self.expInputWdg.getStateTracker()
        self.getStateTracker = self.expInputWdg.getStateTracker

        self.statusBar = RO.Wdg.StatusBar(self,
            dispatcher = self.tuiModel.dispatcher,
            prefs = self.tuiModel.prefs,
            playCmdSounds = True,
        )
        self.statusBar.grid(row=row, column=0, sticky="ew")
        row += 1
        
        butFrame = Tkinter.Frame(self)

        self.startWdg = RO.Wdg.Button(
            master = butFrame,
            text = "Start",
            command = self.doExpose,
            helpURL = _HelpPrefix + "StartButton",
        )
        self.startWdg.pack(side="left")
        
        def makeStopWdg(name, doShow=True, canDoExp=True):
            """Creates and packs a stop button;
            Inputs:
            - name      one of pause, stop or abort (lowercase!)
            - doShow    show this widget?
            - canDoExp  if false, can only handle sequence (for help string)
            """
            helpText = {
                ("pause", True):  "Pause or resume the exposure",
                ("pause", False): "Pause or resume the exposure sequence",
                ("stop",  True):  "Stop the exposure and save the data",
                ("stop",  False): "Finish the exposure and then stop",
                ("abort", True):  "Stop the exposure and discard the data",
                ("abort", False): "Finish the expsure and discard the data",
            }[(name, canDoExp)]
            
            if canDoExp:
                wdgText = name.capitalize()
            else:
                wdgText = "%s Seq" % (name.capitalize())
            
            wdg = RO.Wdg.Button(
                master = butFrame,
                text = wdgText,
                helpText = helpText,
                helpURL = _HelpPrefix + "%sButton" % (name,),
            )
            if name == "pause":
                self.normalPauseText = helpText
                self.pauseWdgPauseText = wdgText
                if canDoExp:
                    self.pauseWdgResumeText = "Resume"
                    wdg["width"] = 6
                else:
                    self.pauseWdgResumeText = "Resume Seq"
                    wdg["width"] = 10
                
            wdg["command"] = RO.Alg.GenericCallback(
                self.doStop,
                wdg,
            )
            if doShow:
                wdg.pack(side="left")
            return wdg

        instInfo = self.expModel.instInfo
        self.pauseWdg = makeStopWdg("pause", instInfo.canPauseExp or instInfo.canPauseSeq, instInfo.canPauseExp)
        self.stopWdg = makeStopWdg("stop", instInfo.canStopExp or instInfo.canStopSeq, instInfo.canStopExp)
        self.abortWdg = makeStopWdg("abort", instInfo.canAbortExp, instInfo.canAbortExp)

        self.configWdg = RO.Wdg.Button(
            master = butFrame,
            text = "Config...",
            command = self.doConfig,
            helpText = "Open the %s configure window" % self.expModel.instName,
            helpURL = _HelpPrefix + "ConfigButton",
        )
        self.configWdg.pack(side="right")

        butFrame.grid(row=row, column=0, sticky="ew")
        row += 1
        
        self.expModel.seqState.addIndexedCallback(self._seqStatusCallback, 5)
Exemple #5
0
#!/usr/bin/env python
"""Data for testing various DIS exposure widgets

To do:
- change timestamps to valid values

History:
2003-10-22 ROwen    Modified data to match new hub.
"""
import TUI.TUIModel
import ExposeModel

tuiModel = TUI.TUIModel.getModel(True)
dispatcher = tuiModel.dispatcher
progID = tuiModel.getProgID()
expModel = ExposeModel.getModel("DIS")
cmdr = tuiModel.getCmdr()

MainDataSet = {
    "disFiles": (cmdr, "tycho.apo.nmsu.edu","/export/images/",progID.upper() + "/","","test0005b.fits","test0005r.fits"),
    "disNextPath": (cmdr, "","test","0006",".fits"),
}

# each element of animDataSet is a full set of data to be dispatched,
# hence each element is a list of keyvar, value tuples
AnimDataSet = (
    {
        "disSeqState": (cmdr, "object", "6.0", "1", "1", "running"),
        "disExpState": (cmdr, "flushing", "2003...", "0", "0"),
    },
    {
Exemple #6
0
    def __init__(self,
        master,
        instName,
        expTypes = None, # override default
        helpURL = None,
    **kargs):
        #print "ExposeInputWdg(%r, %r, %r)" % (master, instName, expTypes)

        Tkinter.Frame.__init__(self, master, **kargs)
        if helpURL == None:
            helpURL = _HelpURL
        
        self.entryError = None
        self.wdgAreSetUp = False        
        self.expModel = ExposeModel.getModel(instName)
        self.WindowCat = "window"
        self.currUnbWindow = [0, 0, 0, 0]
        self.updatingBin = False
        self.binsMatch = True
        self._stateTracker = RO.Wdg.StateTracker(logFunc = self.expModel.tuiModel.logFunc)
        
        gr = RO.Wdg.Gridder(master=self, sticky="w")
        self.gridder = gr

        downloadCtrlFrame = Tkinter.Frame(self)
        
        Tkinter.Label(downloadCtrlFrame, text="Every").pack(side="left")
        self.getEveryWdg = RO.Wdg.IntEntry (
            master = downloadCtrlFrame,
            var = self.expModel.getEveryVarCont.var,
            width = 3,
            helpURL = helpURL,
            helpText = "Download every Nth image (0=none; -1=skip excess)",
        )
        self.getEveryWdg.pack(side="left")

        self.viewImageWdg = RO.Wdg.Checkbutton (
            master = downloadCtrlFrame,
            text = "View Image",
            var = self.expModel.viewImageVarCont.var,
            helpURL = helpURL,
            helpText = "View downloaded images in ds9?",
        )
        self.viewImageWdg.pack(side="left")
        self.getEveryWdg.addCallback(self.autoGetToggled, callNow=True)

        self.prefsTL = self.expModel.tuiModel.tlSet.getToplevel("TUI.Preferences")
        if self.prefsTL:
            showPrefsBtn = RO.Wdg.Button(
                master = downloadCtrlFrame,
                text = "More...",
                callFunc = self.showExposurePrefs,
                helpText = "show global exposure prefs",
                helpURL = helpURL,
            )
            showPrefsBtn.pack(side="left")
        #else:
            #prefsWdg = RO.Wdg.StrLabel(
                #master = self,
                #text = "Prefs",
            #)
        
        gr.gridWdg("Download", downloadCtrlFrame, colSpan=5, sticky="w")

        typeFrame = Tkinter.Frame(self)
        if expTypes != None:
            expTypes = RO.SeqUtil.asSequence(expTypes)
        else:
            expTypes = self.expModel.instInfo.expTypes
        expTypeLabels = [name.capitalize() for name in expTypes]
        
        self.typeWdgSet = RO.Wdg.RadiobuttonSet (
            master = typeFrame,
            textList = expTypeLabels,
            valueList = expTypes,
            defValue = expTypes[0],
            command = self._handleType,
            side = "left",
            helpText = "Type of exposure",
            helpURL = helpURL,
        )
        if len(expTypes) > 1:
            gr.gridWdg("Type", typeFrame, colSpan=5, sticky="w")
        
        timeFrame = Tkinter.Frame(self)

        timeUnitsVar = Tkinter.StringVar()
        self.timeWdg = RO.Wdg.DMSEntry (
            master = timeFrame,
            minValue = self.expModel.instInfo.minExpTime,
            maxValue = self.expModel.instInfo.maxExpTime,
            isRelative = True,
            isHours = True,
            unitsVar = timeUnitsVar,
            width = 10,
            minMenu = "Minimum",
            maxMenu = "Maximum",
            helpText = "Exposure time",
            helpURL = helpURL,
        )
        self.timeWdg.pack(side="left")
        timeUnitsWdg = RO.Wdg.StrLabel(
            master = timeFrame,
            textvariable = timeUnitsVar,
            helpText = "Units of exposure time",
            helpURL = helpURL,
        )
        timeUnitsWdg.pack(side="left")
        wdgSet = gr.gridWdg("Time", timeFrame, colSpan=5)
        self.timeWdgSet = [wdgSet.wdgSet[0], self.timeWdg, timeUnitsWdg]
        
        self.numExpWdg = RO.Wdg.IntEntry(
            master = self,
            defValue = 1,
            minValue = 1,
            maxValue = self.expModel.instInfo.maxNumExp,
            defMenu = "Minimum",
            helpText = "Number of exposures in the sequence",
            helpURL = helpURL,
        )
        gr.gridWdg("#Exp", self.numExpWdg)
        self.grid_columnconfigure(5, weight=1)
        
        self.camWdgs = []
        camNames = self.expModel.instInfo.camNames
        if len(camNames) > 1:
            cnFrame = Tkinter.Frame(self)
            for camName in camNames:
                wdg = RO.Wdg.Checkbutton(
                    master = cnFrame,
                    text = camName.capitalize(),
                    callFunc = self._camSelect,
                    defValue = True,
                    helpText = "Save data from %s camera" % (camName.lower()),
                    helpURL = helpURL,
                )
                self.camWdgs.append(wdg)
                wdg.pack(side="left")
            gr.gridWdg("Cameras", cnFrame, colSpan=5, sticky="w")

        self.binWdgSet = []
        binWdgFrame = Tkinter.Frame(self)
        if self.expModel.instInfo.numBin > 0:
            if self.expModel.instInfo.numBin == 1:
                helpStrList = ("bin factor (x = y)", )
            elif self.expModel.instInfo.numBin == 2:
                helpStrList = ("x bin factor", "y bin factor")
            else:
                raise RuntimeError("Invalid expModel.instInfo.numBin=%s" % (self.expModel.instInfo.numBin,))
            for ind, helpStr in enumerate(helpStrList):
                binWdg = RO.Wdg.IntEntry(
                    master = binWdgFrame,
                    defValue = self.expModel.instInfo.defBin[ind],
                    minValue = 1,
                    callFunc = self._updBinFactor,
                    width = 4,
                    defMenu = "Default",
                    minMenu = "Minimum",
                    helpText = helpStr,
                    helpURL = helpURL,
                )
                self.binWdgSet.append(binWdg)
                binWdg.pack(side="left")
            gr.gridWdg("Bin Factor", binWdgFrame, colSpan=5)

        self.windowWdgSet = []
        minWindow = 1
        self.overscanWdgSet = []
        if self.expModel.instInfo.canWindow:
            self.showWindowBtn = RO.Wdg.Checkbutton(
                master = self,
                text = "Image Size",
                helpText = "Show image size controls?",
                helpURL = helpURL,
            )
            self._stateTracker.trackCheckbutton("showWindow", self.showWindowBtn)
            self.imageSizeWdg = RO.Wdg.StrLabel(
                master = self,
                helpText = "image size: x (+overscan) by y (+overscan) (binned pixels)",
                helpURL = helpURL,
            )
            gr.gridWdg(self.showWindowBtn, self.imageSizeWdg, colSpan=5)
            gr.addShowHideControl(self.WindowCat, self.showWindowBtn)
            
            windowWdgFrame = Tkinter.Frame(self)
            maxWindowList = [minWindow + self.expModel.instInfo.imSize[ind] - 1 for ind in (0, 1, 0, 1)]
            for ind, helpStr in enumerate(("x begin", "y begin", "x end", "y end")):
                if ind < 2:
                    defValue = minWindow
                else:
                    defValue = maxWindowList[ind]
                windowWdg = RO.Wdg.IntEntry(
                    master = windowWdgFrame,
                    minValue = minWindow,
                    maxValue = maxWindowList[ind],
                    defValue = defValue,
                    defMenu = "Default",
                    callFunc = self._updWindow,
                    helpText = helpStr + " (binned pixels)",
                    helpURL = helpURL,
                )
                self.windowWdgSet.append(windowWdg)
                windowWdg.pack(side = "left")
            self.fullWindowWdg = RO.Wdg.Button(
                master = windowWdgFrame,
                text = "Full",
                callFunc = self._doFullWindow,
                helpText = "Set full window",
                helpURL = helpURL,
            )
            self.fullWindowWdg.pack(side="left")
            gr.gridWdg("Window", windowWdgFrame, colSpan=5, cat=self.WindowCat)
            
            if self.expModel.instInfo.defOverscan:
                overscanWdgFrame = Tkinter.Frame(self)
                for ii, helpStr in enumerate(("x overscan", "y overscan")):
                    overscanWdg = RO.Wdg.IntEntry(
                        master = overscanWdgFrame,
                        minValue = 0,
                        defValue = self.expModel.instInfo.defOverscan[ii],
                        defMenu = "Current",
                        width = 4,
                        callFunc = self._updImageSize,
                        helpText = helpStr + " (binned pixels)",
                        helpURL = helpURL,
                    )
                    self.overscanWdgSet.append(overscanWdg)
                    overscanWdg.pack(side="left")
                gr.gridWdg("Overscan", overscanWdgFrame, colSpan=5, cat=self.WindowCat)
            self._updWindow()
        
        self.fileNameWdg = RO.Wdg.StrEntry(
            master = self,
            helpText = "File name or subdirectory/name",
            helpURL = helpURL,
            partialPattern = r"^[-_./a-zA-Z0-9]*$",
        )
        gr.gridWdg("File Name", self.fileNameWdg, colSpan=5, sticky="ew")
                
        self.commentWdg = RO.Wdg.StrEntry(
            master = self,
            helpText = "Comment (saved in the FITS header)",
            helpURL = helpURL,
        )
        gr.gridWdg("Comment", self.commentWdg, colSpan=5, sticky="ew")

        gr.allGridded()

        self.wdgAreSetUp = True
Exemple #7
0
    def __init__(self,
        master,
        instName,
        expTypes = None, # override default
        helpURL = None,
    **kargs):
        #print "ExposeInputWdg(%r, %r, %r)" % (master, instName, expTypes)

        Tkinter.Frame.__init__(self, master, **kargs)
        if helpURL is None:
            helpURL = _HelpURL
        
        self.entryError = None
        self.wdgAreSetUp = False        
        self.expModel = ExposeModel.getModel(instName)
        self.WindowCat = "window"
        self.currUnbWindow = [0, 0, 0, 0]
        self.updatingBin = False
        self.binsMatch = True
        self._stateTracker = RO.Wdg.StateTracker(logFunc = self.expModel.tuiModel.logFunc)
        
        gr = RO.Wdg.Gridder(master=self, sticky="w")
        self.gridder = gr

        downloadCtrlFrame = Tkinter.Frame(self)
        
        Tkinter.Label(downloadCtrlFrame, text="Every").pack(side="left")
        self.getEveryWdg = RO.Wdg.IntEntry (
            master = downloadCtrlFrame,
            var = self.expModel.getEveryVarCont.var,
            width = 3,
            helpURL = helpURL,
            helpText = "Download every Nth image (0=none; -1=skip excess)",
        )
        self.getEveryWdg.pack(side="left")

        self.viewImageWdg = RO.Wdg.Checkbutton (
            master = downloadCtrlFrame,
            text = "View Image",
            var = self.expModel.viewImageVarCont.var,
            helpURL = helpURL,
            helpText = "View downloaded images in ds9?",
        )
        self.viewImageWdg.pack(side="left")
        self.getEveryWdg.addCallback(self.autoGetToggled, callNow=True)

        self.prefsTL = self.expModel.tuiModel.tlSet.getToplevel("TUI.Preferences")
        if self.prefsTL:
            showPrefsBtn = RO.Wdg.Button(
                master = downloadCtrlFrame,
                text = "More...",
                callFunc = self.showExposurePrefs,
                helpText = "show global exposure prefs",
                helpURL = helpURL,
            )
            showPrefsBtn.pack(side="left")
        #else:
            #prefsWdg = RO.Wdg.StrLabel(
                #master = self,
                #text = "Prefs",
            #)
        
        gr.gridWdg("Download", downloadCtrlFrame, colSpan=5, sticky="w")

        typeFrame = Tkinter.Frame(self)
        if expTypes is not None:
            expTypes = RO.SeqUtil.asSequence(expTypes)
        else:
            expTypes = self.expModel.instInfo.expTypes
        expTypeLabels = [name.capitalize() for name in expTypes]
        
        self.typeWdgSet = RO.Wdg.RadiobuttonSet (
            master = typeFrame,
            textList = expTypeLabels,
            valueList = expTypes,
            defValue = expTypes[0],
            command = self._handleType,
            side = "left",
            helpText = "Type of exposure",
            helpURL = helpURL,
        )
        if len(expTypes) > 1:
            gr.gridWdg("Type", typeFrame, colSpan=5, sticky="w")
        
        timeFrame = Tkinter.Frame(self)

        timeUnitsVar = Tkinter.StringVar()
        self.timeWdg = RO.Wdg.DMSEntry (
            master = timeFrame,
            minValue = self.expModel.instInfo.minExpTime,
            maxValue = self.expModel.instInfo.maxExpTime,
            isRelative = True,
            isHours = True,
            unitsVar = timeUnitsVar,
            width = 10,
            minMenu = "Minimum",
            maxMenu = "Maximum",
            helpText = "Exposure time",
            helpURL = helpURL,
        )
        self.timeWdg.pack(side="left")
        timeUnitsWdg = RO.Wdg.StrLabel(
            master = timeFrame,
            textvariable = timeUnitsVar,
            helpText = "Units of exposure time",
            helpURL = helpURL,
        )
        timeUnitsWdg.pack(side="left")
        wdgSet = gr.gridWdg("Time", timeFrame, colSpan=5)
        self.timeWdgSet = [wdgSet.wdgSet[0], self.timeWdg, timeUnitsWdg]
        
        self.numExpWdg = RO.Wdg.IntEntry(
            master = self,
            defValue = 1,
            minValue = 1,
            maxValue = self.expModel.instInfo.maxNumExp,
            defMenu = "Minimum",
            helpText = "Number of exposures in the sequence",
            helpURL = helpURL,
        )
        gr.gridWdg("#Exp", self.numExpWdg)
        self.grid_columnconfigure(5, weight=1)
        
        self.camWdgs = []
        camNames = self.expModel.instInfo.camNames
        if len(camNames) > 1:
            cnFrame = Tkinter.Frame(self)
            for camName in camNames:
                wdg = RO.Wdg.Checkbutton(
                    master = cnFrame,
                    text = camName.capitalize(),
                    callFunc = self._camSelect,
                    defValue = True,
                    helpText = "Save data from %s camera" % (camName.lower()),
                    helpURL = helpURL,
                )
                self.camWdgs.append(wdg)
                wdg.pack(side="left")
            gr.gridWdg("Cameras", cnFrame, colSpan=5, sticky="w")

        self.binWdgSet = []
        binWdgFrame = Tkinter.Frame(self)
        if self.expModel.instInfo.numBin > 0:
            if self.expModel.instInfo.numBin == 1:
                helpStrList = ("bin factor (x = y)", )
            elif self.expModel.instInfo.numBin == 2:
                helpStrList = ("x bin factor", "y bin factor")
            else:
                raise RuntimeError("Invalid expModel.instInfo.numBin=%s" % (self.expModel.instInfo.numBin,))
            for ind, helpStr in enumerate(helpStrList):
                binWdg = RO.Wdg.IntEntry(
                    master = binWdgFrame,
                    defValue = self.expModel.instInfo.defBin[ind],
                    minValue = 1,
                    callFunc = self._updBinFactor,
                    width = 4,
                    defMenu = "Default",
                    minMenu = "Minimum",
                    helpText = helpStr,
                    helpURL = helpURL,
                )
                self.binWdgSet.append(binWdg)
                binWdg.pack(side="left")
            gr.gridWdg("Bin Factor", binWdgFrame, colSpan=5)

        self.windowWdgSet = []
        minWindow = 1
        self.overscanWdgSet = []
        if self.expModel.instInfo.canWindow:
            self.showWindowBtn = RO.Wdg.Checkbutton(
                master = self,
                text = "Image Size",
                helpText = "Show image size controls?",
                helpURL = helpURL,
            )
            self._stateTracker.trackCheckbutton("showWindow", self.showWindowBtn)
            self.imageSizeWdg = RO.Wdg.StrLabel(
                master = self,
                helpText = "image size: x (+overscan) by y (+overscan) (binned pixels)",
                helpURL = helpURL,
            )
            gr.gridWdg(self.showWindowBtn, self.imageSizeWdg, colSpan=5)
            gr.addShowHideControl(self.WindowCat, self.showWindowBtn)
            
            windowWdgFrame = Tkinter.Frame(self)
            maxWindowList = [minWindow + self.expModel.instInfo.imSize[ind] - 1 for ind in (0, 1, 0, 1)]
            for ind, helpStr in enumerate(("x begin", "y begin", "x end", "y end")):
                if ind < 2:
                    defValue = minWindow
                else:
                    defValue = maxWindowList[ind]
                windowWdg = RO.Wdg.IntEntry(
                    master = windowWdgFrame,
                    minValue = minWindow,
                    maxValue = maxWindowList[ind],
                    defValue = defValue,
                    defMenu = "Default",
                    callFunc = self._updWindow,
                    helpText = helpStr + " (binned pixels)",
                    helpURL = helpURL,
                )
                self.windowWdgSet.append(windowWdg)
                windowWdg.pack(side = "left")
            self.fullWindowWdg = RO.Wdg.Button(
                master = windowWdgFrame,
                text = "Full",
                callFunc = self._doFullWindow,
                helpText = "Set full window",
                helpURL = helpURL,
            )
            self.fullWindowWdg.pack(side="left")
            gr.gridWdg("Window", windowWdgFrame, colSpan=5, cat=self.WindowCat)
            
            if self.expModel.instInfo.defOverscan:
                overscanWdgFrame = Tkinter.Frame(self)
                for ii, helpStr in enumerate(("x overscan", "y overscan")):
                    overscanWdg = RO.Wdg.IntEntry(
                        master = overscanWdgFrame,
                        minValue = 0,
                        defValue = self.expModel.instInfo.defOverscan[ii],
                        defMenu = "Current",
                        width = 4,
                        callFunc = self._updImageSize,
                        helpText = helpStr + " (binned pixels)",
                        helpURL = helpURL,
                    )
                    self.overscanWdgSet.append(overscanWdg)
                    overscanWdg.pack(side="left")
                gr.gridWdg("Overscan", overscanWdgFrame, colSpan=5, cat=self.WindowCat)
            self._updWindow()
        
        self.fileNameWdg = RO.Wdg.StrEntry(
            master = self,
            helpText = "File name or subdirectory/name",
            helpURL = helpURL,
            partialPattern = r"^[-_./a-zA-Z0-9]*$",
        )
        gr.gridWdg("File Name", self.fileNameWdg, colSpan=5, sticky="ew")
                
        self.commentWdg = RO.Wdg.StrEntry(
            master = self,
            helpText = "Comment (saved in the FITS header)",
            helpURL = helpURL,
        )
        gr.gridWdg("Comment", self.commentWdg, colSpan=5, sticky="ew")

        gr.allGridded()

        self.wdgAreSetUp = True