#14.01.02-21.11: check to make sure we have the correct version of python

#TODO we want a MUCH more elegant method to check python version.
#TODO: since "sweep" is "cycle", make all one or the other.

#14.01.05-23.57: added a try/except library import to prevent PyQt4-absense crases
#14.01.12-22.59: extreme modification to licensing and key generation methods
#politely renamed _STRUCTURE EDITOR.py to structureEditor.py and created batch file launch script which sets environment paths cleanly and provides a "press any key" catch in case of crashing.
print("importing libraries...")
try:
  #import chkReq # ENSURE WE HAVE THE RIGHT PYTHON VERSION
  import sys
  import traceback
  import shutil
  import threading
  import reports
  from experiment import *
  import registration
  import ui_st
  from PyQt4 import QtCore, QtGui
  from PIL import Image
  from PIL import ImageDraw
  from linescan import *  #this is bad practice
  import SAGformats
except Exception as err:
  print(traceback.format_exc())
  print("\n"*3)
  print(" >>> Ensure your system paths allow access to all required libraries.")
  input("\npress ENTER to continue...")
print("all libraries imported successfully.")

debugLevel=1 # set to 1 to only show important things

# DONT EDIT BELOW THIS #
LS=LineScan(None) #load this for text editor convenience
LSC=LineScanCompare() #load this for text editor convenience
DONTDOIT=False # set this to True to prevent GUI update (and events)
COPYSTUFF={} # used for large-scale copy/paste procedures
versionPrimary=3 #this is only modified by hand.
versionSecondary=56 #modified by script only
versionDate="2013-01-25" #modified by script only
#14.01.04-12.34: version number automatically incrimented during automatic build
version = versionPrimary+float(versionSecondary/100.0)
ST={"version":version} # primary dictionary of structure editor configuration
currentFolderList=None #auto-updated
browserSelected="" #most recently highlighted browser item

# CONSTANTS
styleClear='font: 7pt "MS Shell Dlg 2"; '
styleGreen=styleClear+'background-color: rgb(0, 170, 127);'
styleRed=styleClear+'background-color: rgb(255, 85, 127);'
styleYellow=styleClear+'background-color: rgb(255, 255, 127);'


def debug(msg=None,level=3):
  """update gui debug log. level 1 shows on statusbar. level 0 pops up window."""
  if msg==None:
    msg=""
    level=1
  print(" >",msg)
  if level<=debugLevel:
    uist.lblBotMsg.setText(msg.replace("\n"," - "))
    if msg=='':
      uist.lblBotMsg.setStyleSheet(styleClear)
    else:
      uist.lblBotMsg.setStyleSheet(styleYellow)
    app.processEvents()
  if level<=0:
    QtGui.QMessageBox.about(None,"DEBUG WARNING - LEVEL 1",msg)

def forLE(s):
  """format something for a lineEdit."""
  if type(s)==str:
    if s in LS.config.keys():
      s=LS.config[s]
    else:
      return "None"
  if s==None:
    return ""
  if type(s)==list:
    return str(s)[1:-1]

def fromLE(s):
  """format something for a lineEdit."""
  x=None
  try:
    x=eval(s)
  except(wha):
    pass
  return x


### EXPERIMENT DESIGN ###
#14.01.13-22.52: created entire section for experiment design and linescan comparison across folders
def LSC_updateGui():
  uist.teExperimentCode.clear()
  uist.listExperiments.clear()

  # button
  if not uist.listStruct.currentItem(): s=False
  else: s=uist.listStruct.currentItem().text()
  if LS and 'path' in LS.__dict__:
    if LSC.inthere(LS.path,s):
      uist.btnExp.setChecked(True)
    else:
      uist.btnExp.setChecked(False)


  # textbox
  uist.teExperimentCode.setPlainText(LSC.scan2txt())

  # listbox
  for item in LSC.scans[::-1]:
    uist.listExperiments.insertItem(0,os.path.basename(item[0]))

def LSC_expClicked():
  if not uist.listStruct.currentItem():
    s=False
  else:
    s=uist.listStruct.currentItem().text()
  if not LSC.inthere(LS.path,s):
    LSC.addScan(LS.path,s)
    debug("adding path/structure to experiment list")
  else:
    LSC.delScan(LS.path,s)
    debug("removed path/structure from experiment list")
  LSC_updateGui()

def LSC_save():
  fname = QtGui.QFileDialog.getSaveFileName(directory='./experiments/',filter='*.sag')
  debug("saving experiment to "+fname)
  LSC.scan2txt(fname)

def LSC_load():
  fname=QtGui.QFileDialog.getOpenFileName(directory='./experiments/',filter='*.sag')
  f=open(fname)
  s=f.read()
  f.close()
  LSC.txt2scan(s)
  LSC_updateGui()

def LSC_clear():
  LSC.scans=[]
  LSC_updateGui()

def LSC_del():
  LSC.delScanByIndex(uist.listExperiments.currentRow())
  LSC_updateGui()

def LSC_pull():
  LSC.txt2scan(uist.teExperimentCode.toPlainText())
  LSC_updateGui()

def LSC_launch():
  #14.04.19-16.15: added R, G, dG, and dGR to charts generated by experiment.
  debug("PROCESSING EXPERIMENT ...",1)
  reports.reportCompareLS(LSC.scans,"G",False)
  reports.reportCompareLS(LSC.scans,"R",False)
  reports.reportCompareLS(LSC.scans,"dG",False)
  reports.reportCompareLS(LSC.scans,"dGR",False)
  debug()
  pylab.show()


### LINESCAN GUI ACTIONS ###


def LSpopulategui():
  """populate the GUI from linescan details."""
  #14.01.02-21.11: gui population now involves flagging
  if not LS: return
  debug("LSpopulategui()")

  # PAGE INFO


  uist.btnPageConfig.setEnabled(True)
  uist.btnPageExperiment.setEnabled(True)
  uist.btnPageLS.setEnabled(True)
  uist.btnPageLSreport.setEnabled(True)
  uist.btnPageXML.setEnabled(True)

  global DONTDOIT
  DONTDOIT=True

  #14.01.06-22.35: automatically generate 0-10ms baseline if none defined.
  #uist.lineBL.setText(str(LS.config["guiBaseline"]))
  #print("SETTINGTP:",forLE(LS.config["guiBaseline"]))

  #14.01.06-22.35: added messagebar details from XML data (PMT gain, pockels, etc.)
  uist.lblBotDim.setText("%dpx (%dms) by %dpx (%duM)"%(LS.config["imgX"],
                         int(LS.config["framePeriod"]*1000),
                         LS.config["imgY"],
                         int(LS.config["imgY"]*LS.config["umPerPx"])))

  uist.lblBotPockel.setText("Pockels: %d"%LS.config['laserPower_0'])
  uist.lblBotPmt.setText("PMT R=%d G=%d"%(LS.config['pmtGain_0'],
                                          LS.config['pmtGain_1']))

  # CONFIGURATION
  #uist.gbConfiguration.setEnabled(True)
  if os.path.exists(LS.path+"/SAG/flagged"):
    uist.btnConfigFlag.setText("FLAGGED")
    uist.btnConfigFlag.setChecked(True)

  if os.path.exists(LS.path+"/SAG/hidden"):
    uist.btnConfigHide.setText("HIDDEN")
    uist.btnConfigHide.setChecked(True)

  LSC_updateGui()

  uist.btnConfigClear.setStyleSheet(styleClear)

  # LINESCAN EDITOR
  uist.lblRef.setVisible(True)
  uist.lblPK.setVisible(True)
  uist.lblOL.setVisible(True)
  uist.lblLS.setVisible(True)
  uist.cbStretch.setChecked(True)

  # LINESCAN GB
  uist.gbLinescan.setEnabled(True)

  # CYCLES
  uist.listCycles.clear()
  cycles=LS.config["guiValidSweeps"][::-1]
  for i in range(len(cycles)):
    cycle=cycles[i]
    uist.listCycles.insertItem(0,"%02d"%cycle)
    if cycle in LS.config["guiSelectedSweeps"]:
      uist.listCycles.setItemSelected(uist.listCycles.item(0),True)
    #if cycle in LS.config["guiSelectedSweeps"]:
      #print("SELECTING:",i)
      #uist.listCycles.setItemSelected(uist.listCycles.item(-i),True)

  # NOTES
  uist.gbNotes.setEnabled(True)
  uist.teNotes.appendPlainText(LS.config["notes"].replace("|","\n"))
  uist.teNotes.moveCursor(QtGui.QTextCursor.Start)

  # STRUCTURE
  uist.gbStructure.setEnabled(True)
  uist.lineStructure.setEnabled(True)

  uist.vs1.setMaximum(LS.config["imgY"])
  uist.vs2.setMaximum(LS.config["imgY"])

  #uist.vs1.setValue(LS.config["imgY"])
  #uist.vs2.setValue(LS.config["imgY"]-5)

  uist.lineStructure.setText("")

  LSstructureListFromConf()

  uist.lineStructure.setText("")
  uist.lblStrA.setText("A=")
  uist.lblStrB.setText("B=")
  uist.lblStrW.setText("W=")

  # CYCLES COLUMN
  uist.gbCycles.setEnabled(True)

  # TIME DOMAIN

  uist.btnTimeUpdate.setStyleSheet('font: 7pt "MS Shell Dlg 2";')

  uist.gbTime.setEnabled(True)
  uist.lineBL.setText(forLE("guiBaseline"))
  uist.lineEV.setText(forLE("guiEvents"))
  uist.lineMS.setText(forLE("guiMeasure"))



  uist.sbGaussTime.setValue(int(LS.config["guiGaussTime"]))
  uist.sbGaussSpace.setValue(int(LS.config["guiGaussSpace"]))

  # CALIBRATION
  #TODO: impliment calibration values

  # PREVIEW
  uist.gbPreview.setEnabled(True)

  # GRAPH
  uist.lblGraph.setVisible(True)

  ### LETS DO THIS ###

  refpath=LS.path+"/References/"+LS.config["ref"]
  uist.lblRef.setPixmap(QtGui.QPixmap(refpath))

  if not uist.listStruct.selectedItems():
    uist.listStruct.setCurrentRow(0)

  LSupdateLS()
  LSupdateOL()
  LSupdateGraph()

  checkIfConfigChanged()

  DONTDOIT=False


def LSupdateTimes():
  """someone pushed the update button for baseline and stuff."""
  debug("LSupdateTimes()")
  #14.01.06-22.35: use gui to invent baseline if none entered
  try:
    b1,b2=eval('['+uist.lineBL.text()+']')
    #c=b1+b2+5
  except:
    uist.lineBL.setText("0,10")
  LS.configSet('guiBaseline',eval('['+uist.lineBL.text()+']'))
  LS.configSet('guiEvents',eval('['+uist.lineEV.text()+']'))
  LS.configSet('guiMeasure',eval('['+uist.lineMS.text()+']'))
  LSpopulategui()

def LSupdateBlurs(event=None):
  """change something in a time/space domain, so re-gauss()."""
  if not LS: return
  if DONTDOIT: return
  debug("LSupdateBlurs()")
  if not 'imProj' in LS.__dict__:
    return

  #14.01.06-22.35: fixed bug that caused selected structure to become unselected when adjusting gaussian

  if uist.listStruct.selectedItems():
    sel=uist.listStruct.currentRow() #uist.listStruct.setCurrentRow(0)

  LS.configSet('guiGaussSpace',uist.sbGaussSpace.text())
  LS.configSet('guiGaussTime',uist.sbGaussTime.text())
  LS.gauss(True)
  LSpopulategui()

  uist.listStruct.setCurrentRow(sel)

def LSblank(msg="[EMPTY]"):
  """blank out the graph."""
  im=Image.new("RGBA",(450,300),color=(0,0,0,0))
  dr=ImageDraw.Draw(im)
  sX,sY=dr.textsize(msg)
  dr.text((450/2-sX/2,300/2-sY/2),msg,fill=(0,0,0,255))
  data = im.tostring()
  qim = QtGui.QImage(data, im.size[0], im.size[1], QtGui.QImage.Format_ARGB32)
  pix = QtGui.QPixmap.fromImage(qim)
  uist.lblGraph.setPixmap(pix)

def LSupdateGraph(event=None):
  """draw current linescan graph into big plot area."""

  debug("LSupdateGraph()")

  if not uist.listStruct.selectedItems():
    LSblank("NO STRUCTURES DEFINED")
    return

  if not uist.listCycles.selectedItems():
    LSblank("NO CYCLES SELECTED")
    return

  if uist.vs1.value()<=uist.vs2.value():
    uist.vs1.setValue(uist.vs2.value()+1)
    return

  LS.intensity() # DO THIS BEFORE DOING ANYTHING ELSE TO BE SURE WE ARE WORKING WITH RECENT DATA

  SP=ScottPlot()
  SP.hspans.append(LS.config["guiBaseline"])

  #14.01.05-23.57: implimented LS editor view indicating average/peak of selected linescan in the measured range.
  if uist.listStruct.currentItem():
    if type(LS.config["guiMeasure"])==list and len(LS.config["guiMeasure"])==2:
      sel=uist.listStruct.currentItem().text()
      AV="%.04f +/- %.04f"%(LS.structures[sel]["dGRavA"],LS.structures[sel]["dGRavS"])
      PK="%.04f +/- %.04f"%(LS.structures[sel]["dGRpkA"],LS.structures[sel]["dGRpkS"])
      #14.01.05-23.57: shaded the "measure" region of graps as light green
      SP.hspans.append(LS.config["guiMeasure"]+["x"]+[(222,255,222,255)])
    else:
      AV="?"
      PK="?"
    uist.lineAV.setText(AV)
    uist.linePK.setText(PK)



  SP.vlines=LS.config["guiEvents"][:]
  #14.01.05-23.57: made vertical event markers red
  for i in range(len(SP.vlines)):
    SP.vlines[i]=[SP.vlines[i]]+[(100,100,255,255)]

  mode=uist.cbPrv.currentText()
  selected=uist.listStruct.selectedItems()[0].text()

  if uist.cbPrvMax.isChecked():
    SP.axis[3]=float(uist.linePrvMax.text())
  if uist.cbPrvMin.isChecked():
    SP.axis[2]=float(uist.linePrvMin.text())

  if mode==("(dG)/R"):
    SP.hlines=[0]
    title=os.path.basename(LS.path)+" - "+mode+" - %s selected"%(selected)
    if uist.btnPrvSweeps.isChecked():
      # PLOT ALL SWEEPS OF SELECTED STRUCTURE, BOLDING THE AVERAGE
      for structure in LS.structures.keys():
        if uist.listStruct.selectedItems():
          if structure==selected:
            SP.plot(LS.structures[structure]['dGR'],xs=LS.Xs,lc='b',lw=1)
            SP.plot(np.average(LS.structures[structure]['dGR'],axis=0),xs=LS.Xs,lc='k',lw=2)
    else:
      # PLOT ALL STRUCTURES, BOLDING THE SELECTED ONE
      for structure in LS.structures.keys():
        if uist.listStruct.selectedItems():
          if structure==selected:
            #BOLD
            SP.plot(np.average(LS.structures[structure]['dGR'],axis=0),xs=LS.Xs,lc='ll',lw=2)
            SP.plot(np.average(LS.structures[structure]['dGR'],axis=0),xs=LS.Xs,lc='k',lw=1)
          else:
            #REGULAR in presense of selected
            SP.plot(np.average(LS.structures[structure]['dGR'],axis=0),xs=LS.Xs,lc='d',lw=1)
        else:
          #REGULAR with none selected
          SP.plot(np.average(LS.structures[structure]['dGR'],axis=0),xs=LS.Xs,lc='d',lw=1)

  elif mode==('raw PMT'):
    title="PMT VALUE - "+selected
    for structure in LS.structures.keys():
      if uist.listStruct.selectedItems():
        if structure==selected:
          lw=1
          if uist.btnPrvSweeps.isChecked():
            SP.plot(LS.structures[structure]['G'],xs=LS.Xs,lc='lg',lw=lw)
            SP.plot(LS.structures[structure]['R'],xs=LS.Xs,lc='lr',lw=lw)
            lw=2
          SP.plot(np.average(LS.structures[structure]['G'],axis=0),xs=LS.Xs,lc='g',lw=lw)
          SP.plot(np.average(LS.structures[structure]['R'],axis=0),xs=LS.Xs,lc='r',lw=lw)

  elif mode==('delta PMT'):
    SP.hlines=[0]
    title="delta PMT - "+selected
    for structure in LS.structures.keys():
      if uist.listStruct.selectedItems():
        if structure==selected:
          lw=1
          if uist.btnPrvSweeps.isChecked():
            SP.plot(LS.structures[structure]['dG'],xs=LS.Xs,lc='lg',lw=lw)
            SP.plot(LS.structures[structure]['dR'],xs=LS.Xs,lc='lr',lw=lw)
            lw=2
          SP.plot(np.average(LS.structures[structure]['dG'],axis=0),xs=LS.Xs,lc='g',lw=lw)
          SP.plot(np.average(LS.structures[structure]['dR'],axis=0),xs=LS.Xs,lc='r',lw=lw)

  else:
    print("UNKNOWN PLOT MODE")

  SP.renderAll(450,300,title=title,xlabel="EXPERIMENT TIME (MS)",trans=True)
  im = SP.imF
  data = im.tostring()
  qim = QtGui.QImage(data, im.size[0], im.size[1], QtGui.QImage.Format_ARGB32)
  pix = QtGui.QPixmap.fromImage(qim)
  uist.lblGraph.setPixmap(pix)


def LSupdateLS():
  """apply gauss 2d image."""
  #14.01.02-21.11: implimented channel selection on LS structure editor
  #TODO: impliment more color modes
  if not LS: return
  debug("LSupdateLS()")
  mode=uist.cbLS.currentText()
  #proj=None #leave None if you don't care how it's rendered
  if not 'imProj' in LS.__dict__ or LS.imProj==None:
    return
  if mode=="G":
    proj=LS.imProj[1]/16.0
  elif mode=="R":
    proj=LS.imProj[0]/16.0
  elif mode=="dG/R":
    print("PROJECTING SPECIAL")
    proj=LS.imProjDGR
  else:
    proj=LS.imProj[1]

  # SET LABEL
  #im=Image.fromarray((proj/16).astype(np.uint8))
  if uist.cbStretch.isChecked()==True:
    proj=npContrast(proj)
  im=Image.fromarray(proj.astype(np.uint8))
  #im=imLinescanPrep(im) #DONT DO THIS HERE
  im=im.convert("RGBA")
  data = im.tostring()
  qim = QtGui.QImage(data, im.size[0], im.size[1], QtGui.QImage.Format_ARGB32)
  pix = QtGui.QPixmap.fromImage(qim)
  uist.lblLS.setPixmap(pix)
  checkIfConfigChanged()

def LSstructureValueChanged():
  """call this if the SLIDER value is changed."""


  debug("LSstructureValueChanged()")

  if not uist.listStruct.selectedItems():
    return # just in case no structures are listed
  selected=uist.listStruct.selectedItems()[0].text()
  v1=uist.vs1.value()
  v2=uist.vs2.value()
  structures=LS.config["structures"]
  for i in range(len(structures)):
    if structures[i][2]==selected:
      structures[i][0]=LS.config["imgY"]-v1
      structures[i][1]=LS.config["imgY"]-v2
      uist.lblStrA.setText("A=%d"%(v1))
      uist.lblStrB.setText("B=%d"%(v2))
      uist.lblStrW.setText("W=%d"%(v1-v2))
  LS.config["structures"]
  LSupdateOL()
  #LSupdateGraph() #THIS IS TOO SLOW!

def LSselectedStructureChanged():
  """Call this when your selected structure OR selected changes."""
  debug("LSselectedStructureChanged()")

  if not uist.listStruct.selectedItems():
    uist.vs2.setEnabled(False)
    uist.vs1.setEnabled(False)
    LSupdateOL()
    LSupdateGraph()
    return # just in case no structures are listed

  uist.vs2.setEnabled(True)
  uist.vs1.setEnabled(True)
  for k in LS.config["structures"]:
    if uist.listStruct.selectedItems()[0].text()==k[2]:
        uist.vs1.valueChanged.disconnect()
        uist.vs1.setValue(LS.config["imgY"]-k[0])
        uist.vs2.setValue(LS.config["imgY"]-k[1])
        uist.vs1.valueChanged.connect(LSstructureValueChanged)
        uist.lblStrA.setText("A=%d"%(k[0]))
        uist.lblStrB.setText("B=%d"%(k[1]))
        uist.lblStrW.setText("W=%d"%(k[1]-k[0]))
        uist.lineStructure.setText(k[2])

  LSC_updateGui()

  LSupdateOL()
  LSupdateGraph()
  #LSselectedStructureChanged()

def LSupdateOL():
  """apply linescan details."""
  #14.01.03-16.39: added vertical lines on LS perview for baseline and events
  if not LS: return
  debug("LSupdateOL()")
  #print("UPDATING PLOT")
  im=Image.new("RGBA",(200,200),(0,0,0,0))
  dr=ImageDraw.Draw(im)
  multY=200.0/LS.config["imgY"] # ar*mult = px
  #multX=200.0/LS.config["imgX"] # ar*mult = px
  #14.01.13-15.39: updated overlay (multX) code to properly range baseline/event pixel bounds.
  multX=200.0/(LS.config["framePeriod"]*1000.0)
  for k in LS.config["structures"]:
    color=(0,255,0,100)
    if uist.listStruct.selectedItems():
      if uist.listStruct.selectedItems()[0].text()==k[2]:
        color=(0,255,0,200)
    dr.line((0,multY*k[0],200,multY*k[0]),fill=color)
    dr.line((0,multY*k[1],200,multY*k[1]),fill=color)

  for k in LS.config["guiBaseline"]:
    dr.line((multX*k,0,multX*k,200),fill=(255,100,100,100))
  for k in LS.config["guiEvents"]:
    dr.line((multX*k,0,multX*k,200),fill=(100,100,255,100))
  checkIfConfigChanged()

  # SET LABEL
  #im=Image.fromarray((proj/16).astype(np.uint8))
  #im=im.convert("RGBA")
  data = im.tostring()
  qim = QtGui.QImage(data, im.size[0], im.size[1], QtGui.QImage.Format_ARGB32)
  pix = QtGui.QPixmap.fromImage(qim)
  uist.lblOL.setPixmap(pix)

  # PEAKS GRAPH
  if (uist.listStruct.selectedItems()):
    selectedStructure=uist.listStruct.selectedItems()[0].text()
  else:
    selectedStructure="nothing"
  im=LS.peaksGraph(selectedStructure)
  data = im.tostring()
  qim = QtGui.QImage(data, im.size[0], im.size[1], QtGui.QImage.Format_ARGB32)
  pix = QtGui.QPixmap.fromImage(qim)
  uist.lblPK.setPixmap(pix)

def LSlaunchRef(event=None):
  """launch the reference image with explorer.exe."""

  debug("LSlaunchRef()")
  debug("launching reference image",1)
  refpath=LS.path+"/References/"+LS.config["ref"]
  launchThreaded(refpath)

def LSstructureRemove():
  """remove the selected structure.
  IMPORTANT: any time structures are modified, FORGET THE PICKLE!
  """
  debug("LSstructureRemove()")
  if not uist.listStruct.selectedItems():
    return
  keep=[]
  for structure in LS.config["structures"]:
    if structure[2]==uist.listStruct.selectedItems()[0].text():
      pass
    else:
      keep.append(structure)
  LS.config["structures"]=keep
  theI=uist.listStruct.currentRow()-1
  if theI<0:
    theI=0
  LSstructureListFromConf()
  uist.listStruct.setCurrentRow(theI)
  if not uist.listStruct.selectedItems():
    #14.01.02-21.11: clear structure list after last structure is deleted
    LSupdateGraph()
  LSupdateOL()# always required because peaks are drawn no matter what

def LSstructureInsert():
  """insert a new structure.
  IMPORTANT: any time structures are modified, FORGET THE PICKLE!
  """

  debug("LSstructureInsert()")
  #print(LS.config["structures"])
  structures=LS.config["structures"]
  s=chr(97+len(LS.config["structures"]))
  structures.append([15,20,s])
  LS.config["structures"]=structures
  LSstructureListFromConf()
  uist.listStruct.setCurrentRow(len(LS.config["structures"])-1)


def LSstructureListFromConf():
  """populate structure list from conf."""
  uist.listStruct.clear()
  if len(LS.config["structures"])==0:
    return
  debug("LSstructureListFromConf()")
  for item in LS.config["structures"][::-1]:
    uist.listStruct.insertItem(0,item[2])
  #app.processEvents()

def LSstructFromLine(self=None):
  """update selected structure's name to be that in the line."""
  debug("LSstructFromLine()")
  #print("SELECTED:",uist.listStruct.currentRow())
#  if not uist.listStruct.selectedItems():
#    return # just in case no structures are listed
  i=uist.listStruct.currentRow()
  structures=LS.config["structures"]
  structures[i][2]=uist.lineStructure.text()
  LS.config["structures"]=structures
  LSstructureListFromConf()

def LSsaveEverything():
  """save everything!"""
  global LSconfig
  debug("LSsaveEverything()")
  debug("saving ...",1)
  LS.saveEverything()
  LSconfig=str(LS.config)
  checkIfConfigChanged()
  browserSelectedRefresh()
  uist.listBrowser.setFocus()
  debug()


def LSdeleteSettings():
  """Launch dialogue window, if agree delete all ./SAG/ contents."""
  #14.01.02-21.11: added function to clear LS settings (delete ./SAG folder)
  #selectedPath=workingPathFolders[uist.listBrowser.currentRow()][1]

  selectedPath=workingPathFolders[uist.listBrowser.currentRow()][1]

  selectedPath+="/SAG"
  selectedPath=selectedPath.replace('\\', '/')
  msg = "Are you sure you want to delete these settings?\n\n"
  msg+= "This will DELETE the following folder:\n\n"
  msg+=selectedPath.replace("/","/\n  ")
  reply = QtGui.QMessageBox.question(None, 'Message', msg,
              QtGui.QMessageBox.Yes, QtGui.QMessageBox.No)
  if reply == QtGui.QMessageBox.Yes:
    shutil.rmtree(selectedPath) #os.remove only works when directory is empty
    debug("CLEARED SETTINGS",1)
    browserSelectionChanged()
  else:
    debug("CLEAR - not performed",1)

def LSrevert():
  """reload currently selected linescan data."""
  global DONTDOIT
  DONTDOIT=True
  browserSelectionChanged()
  browserSelectedRefresh()
  DONTDOIT=False

def LSupdateCycles():
  """different combination of cycles selected."""
  #14.01.02-21.11: allowed graph update on selectionModel CHANGE event
  if DONTDOIT: return
  if LS==None: return
  debug("LSupdateCycles()")
  cycles=[]
  for item in list(uist.listCycles.selectedItems()):
    cycles.append(int(item.text()))
  print("CYCLES:",cycles)
  LS.config["guiSelectedSweeps"]=cycles
  LS.gauss(True)
  LSupdateLS()
  LSupdateGraph()
  #LSpopulategui()

def LScycleAll():
  """select all cycles."""
  LS.config["guiSelectedSweeps"]=LS.config["guiValidSweeps"]
  LSpopulategui()
  LS.gauss(True)
  LSupdateLS()
  LSupdateGraph()

def LScycleNone():
  """select all cycles."""
  LS.config["guiSelectedSweeps"]=[]
  LSpopulategui()
  LS.gauss(True)
  LSupdateLS()
  LSupdateGraph()

def LScycleSelectionMode():
  """Determine if more than 1 cycle can be selected."""
  #14.01.02-21.11: added action when selection mode button pressed
  if uist.listCycles.selectionMode()==QtGui.QAbstractItemView.SingleSelection:
    # SET TO MULTI-SELECTION
    debug("setting to multiple selection")
    uist.listCycles.setSelectionMode(QtGui.QAbstractItemView.MultiSelection)
  else:
    # SET TO SINGLE SELECTION
    debug("setting to single selection")
    uist.listCycles.setSelectionMode(QtGui.QAbstractItemView.SingleSelection)
    uist.listCycles.setItemSelected(uist.listCycles.item(0),True)

def LSmodechange():
  """automatically set limit suggestions."""
  mode=uist.cbPrv.currentText()
  if 'raw' in mode or 'delta' in mode:
    uist.linePrvMax.setText("4096")
    uist.linePrvMin.setText("0")
  else:
    uist.linePrvMax.setText("1.5")
    uist.linePrvMin.setText("-.5")
  LSupdateLS()

def LSnotesModified():
  """update config, make sure we know things need to be saved."""
  if not LS: return
  LS.config["notes"]=uist.teNotes.toPlainText().replace("\n","|")
  uist.lblBotStatus.setStyleSheet(styleRed)
  uist.lblBotStatus.setText("UNSAVED")
  uist.btnConfigSave.setStyleSheet(styleRed)

def LSupdateNeeded():
  """sets the UPDATE button to red. hitting SAVE or RELOAD refreshes it."""
  #14.01.04-12.04: made the 'update' button turn red if unapplied modifications exist
  if not LS: return
  uist.btnTimeUpdate.setStyleSheet('font: 7pt "MS Shell Dlg 2"; background-color: rgb(255, 85, 127);')

### BROWSER ###

def browserStore():
  if not currentFolderList:
    debug("browserStore() but no currentFolderList")
    return
  folder=os.path.abspath(ST["workingPath"])
  try:
    pickle.dump(currentFolderList,open(folder+"/index.pkl","wb"))
    debug('generated "%s/index.pkl" for faster folder recall in the future.'%os.path.basename(folder),1)
  except:
    debug("couldn't save pickle")
  uist.btnBrowserStore.setChecked(True)
  return

def browserSelectedRefresh():
  """redetermine the title of the currently selected browser item."""
  #14.01.04-18.59: allow directory XML data caching so folder data is only loaded once
  debug("browserSelectedRefresh()")
  global currentFolderList
  selText=uist.listBrowser.currentItem().text()
  for i in range(len(currentFolderList)):
    if not currentFolderList[i][2]==selText:
      continue
    else:
      print(currentFolderList[i])
      currentFolderList[i]=listFolderScans(currentFolderList[i][1],justOne=True)[0]
  selectedBefore=uist.listBrowser.currentRow()
  setPath()
  uist.listBrowser.setCurrentItem(uist.listBrowser.item(selectedBefore))

def clearBrowser():
  """reset file browser browser to empty state."""
  uist.listBrowser.clear()

def cbBrAll():

  debug("cbBrAll()")
  if uist.cbBrAll.isChecked():
    uist.cbBrS.setEnabled(False)
    uist.cbBrL.setEnabled(False)
    uist.cbBrT.setEnabled(False)
    uist.cbBrZ.setEnabled(False)
    uist.cbBrA.setEnabled(False)
  else:
    uist.cbBrS.setEnabled(True)
    uist.cbBrL.setEnabled(True)
    uist.cbBrT.setEnabled(True)
    uist.cbBrZ.setEnabled(True)
    uist.cbBrA.setEnabled(True)
  setPath()

def clickSetPath():
  """when the set path buttin is pressed."""
  folder=QtGui.QFileDialog.getExistingDirectory()
  setPath(folder)

def reloadPathForce():
  """take a lot of time and force re-read of folder info."""
  #14.01.14-18.53: added button to save 'index.pkl' to speed-up linescan folder loading
  global currentFolderList
  currentFolderList=None
  pklToKill=os.path.abspath(ST["workingPath"])+"/index.pkl"
  if os.path.exists(pklToKill):
    debug("deleting "+pklToKill)
    os.remove(pklToKill)
  setPath(False,True)

def reloadPath(folder=False):
  """re-read folder info."""
  global currentFolderList
  if uist.lblBlock.isVisible():
    a,b=pull()
    if isLive(a,b):
      uist.lblBlock.setVisible(False)
    else:
      return
  currentFolderList=None
  setPath(folder)

def setPath(folder=False,force=False):
  """set current working directory UPDATE BROWSER."""
  print("setPath()")
  debug("setting path to: "+str(folder))
  global currentFolderList
  #uist.listBrowser.setEnabled(True)
  if not type(folder)==str:
    folder=False #should be a path or False
  else:
    #14.01.05-23.57: corrected error that prevented Set Path button from refreshing list
    currentFolderList=None
  global workingPathFolders,ST #TODO: get rid of ST

  uist.listBrowser.setEnabled(False)
  uist.listBrowser.clear()
  uist.listBrowser.insertItem(0,"   ... LOADING ...")
  app.processEvents()

  if not folder:
    if not "workingPath" in ST.keys(): ST["workingPath"]="./"
    folder=os.path.abspath(ST["workingPath"])
  folder=os.path.abspath(folder)
  ST["workingPath"]=folder

  workingPathFolders=[["","","../"+os.path.basename(folder)+"/"]]

#  if uist.cbAtLeast.isChecked():
#    atLeast=uist.sbAtLeast.value()
#  else:
#    atLeast=0 #minimum length

  if not currentFolderList:
    print("WHERE:",folder+"/index.pkl")
    if os.path.exists(folder+"/index.pkl") and force==False:
      debug("loading index.pkl")
      currentFolderList=pickle.load(open(folder+"/index.pkl","rb"))
      uist.btnBrowserStore.setChecked(True)
    else:
      currentFolderList=listFolderScans(folder,0,app,debug)
      uist.btnBrowserStore.setChecked(False)

#    currentFolderList=[]
#    for item in listFolderScans(folder,0,app,debug):
#      if len(item)<4 or item[3]==True or uist.cbBrH.isChecked()==True:
#        currentFolderList.append(item)


  savePklNeeded=False
  for i in range(len(currentFolderList)):
    item=currentFolderList[i]
    if item[0]=="/":
      workingPathFolders.append(item)
    elif uist.cbBrAll.isChecked():
      workingPathFolders.append(item)
    elif uist.cbBrS.isChecked() and item[0]=="S":
      workingPathFolders.append(item)
    elif uist.cbBrL.isChecked() and item[0]=="L":
      #14.01.05-23.57: allowed minimum scan count limit changes without refreshing folder
      savePklNeeded=True
      numscans=int(item[2].split("(")[1].split(")")[0])
      if uist.cbAtLeast.isChecked():
        if numscans>=uist.sbAtLeast.value():
          workingPathFolders.append(item)
      else:
        workingPathFolders.append(item)
    elif uist.cbBrT.isChecked() and item[0]=="T":
      workingPathFolders.append(item)
    elif uist.cbBrZ.isChecked() and item[0]=="Z":
      workingPathFolders.append(item)
    elif uist.cbBrA.isChecked() and item[0]=="A":
      workingPathFolders.append(item)

    #this might make it slower, but more responsive
    #app.processEvents()
  #14.01.14-23.33: if a browsed folder contains at least 1 linescan, automatically make a pickel.
  if savePklNeeded and not os.path.exists(folder+"/index.pkl"):
    debug("I see linescans. I'm going to decide to pickle this folder.")
    browserStore()
  debug()

  uist.listBrowser.clear()
  for i in range(len(workingPathFolders)):
    #print(i,workingPathFolders[i])
    #tip: don't filter out hidden folders here.
    #if len(workingPathFolders[i])<4 or workingPathFolders[i][3]==True or uist.cbBrH.isChecked()==True:
    #if not " H " in workingPathFolders[i][2]+" ":
    if " H " in workingPathFolders[i][2]+" ":
      short=workingPathFolders[i][2].split(" ",4)[:-1]
      short=" ".join(short)+" "
      uist.listBrowser.insertItem(i,short)
    else:
      uist.listBrowser.insertItem(i,workingPathFolders[i][2])
  uist.listBrowser.setEnabled(True)

  if not uist.listBrowser.currentItem():
    browserSelectionRecall()
  uist.listBrowser.setFocus()

def browserLaunch(event=None):
  """THREADEDLY launch the selected item."""
  debug("launching file browser",1)
  if uist.listBrowser.currentRow()==0:
    cmd=ST["workingPath"]
  else:
    cmd=workingPathFolders[uist.listBrowser.currentRow()][1]
  cmd='explorer.exe "'+cmd+'"'
  threading.Thread(target=execute,args=(cmd,)).start()


def browserSelectionRemember():
  """store (into a global) the shorthand name of the selected item."""
  global browserSelected
  if uist.listBrowser.currentItem():
    if uist.listBrowser.currentRow()==0:
      return
    browserSelected=uist.listBrowser.currentItem().text()
    debug("remembering selection: "+browserSelected)

def browserSelectionRecall():
  """try to re-highlight the previously selected item."""
  #14.01.13-15.39: implimented selection recall function to prevent losing selected scan while changing file display options
  for i in range(uist.listBrowser.count()):
    if uist.listBrowser.item(i).text()==browserSelected:
      debug("re-selecting: "+browserSelected)
      #uist.listBrowser.setItemSelected(uist.listBrowser.item(i),True)
      uist.listBrowser.setCurrentItem(uist.listBrowser.item(i))

def browserSelectionChanged():
  """This is executed when a new folder is selected in the browser.
  first, it clearsSettings()
  then it determines folder type and executes its function.
    if it's a LS, it fires-up a LS class
  """
  if uist.listBrowser.currentItem()==None:
    return
  browserSelectionRemember()
  global LS,LSconfig,browserSelected
  selectedPath=workingPathFolders[uist.listBrowser.currentRow()][1]
  clearSettings()
  if uist.listBrowser.currentItem()==None: return
  if " L " in uist.listBrowser.currentItem().text():
    #TODO: improve exception catcher to report fail details
    try:
      uist.stackedWidget.setCurrentIndex(0)
      debug("loading linescan ...",1)
      LS=LineScan(selectedPath,version)
      #LS.version=version
      #14.01.04-12.04: implimented config file version checking.
      needRed=False
      if LS.config["version"]<version:
        msg="Config file is old! (version %.02f) Resave to update!"%LS.config["version"]
        LS.config["version"]=version
        debug(msg,1)
        needRed=True
      if 'config' in LS.__dict__:
        LSconfig=str(LS.config)
      LS.config["version"]=version
      LS.project()
      LSpopulategui()
      debug()
      if needRed==True:
        LSnotesModified() #easy way to red the save button
      uist.gbConfiguration.setEnabled(True)
    except:
      msg="SEEMS TO HAVE CRASHED! Perhaps 'clear' and retry?"
      suggestClear()
      debug(msg,1)
      #debug(dictSave(LS.config),4)
  elif " Z " in uist.listBrowser.currentItem().text():
    clearSettings()
    pageZseries(selectedPath)
  elif " T " in uist.listBrowser.currentItem().text():
    clearSettings()
    pageTseries(selectedPath)
  else:
    clearSettings()

def checkIfConfigChanged():
  """see if unsaved confguration changes exist."""
  #14.01.03-16.39: added functionality to the "modified" status bar

  uist.lblBotStatus.setStyleSheet(styleClear)
  uist.lblBotStatus.setText("")
  if not 'LSconfig' in globals():
    return
  if not LSconfig:
    return
  if LSconfig == str(LS.config):
    uist.lblBotStatus.setStyleSheet(styleGreen)
    uist.lblBotStatus.setText("current")
    uist.btnConfigSave.setStyleSheet(styleClear)
    uist.btnTimeUpdate.setStyleSheet(styleClear)
  else:
    uist.lblBotStatus.setStyleSheet(styleRed)
    uist.lblBotStatus.setText("UNSAVED")
    uist.btnConfigSave.setStyleSheet(styleRed)


def browserDC():
  """item in the browser is double-clicked."""
  if uist.listBrowser.currentRow()==0:
    lastSelected=os.path.basename(ST["workingPath"])
    print("LASTSELECTED:",lastSelected)
    ST["workingPath"]=os.path.dirname(ST["workingPath"])
    #setPath()
    reloadPath()
    #14.01.02-21.11: when browser "../" is clicked, previous folder is highlighted.
    for i in range(uist.listBrowser.count()):
      if uist.listBrowser.item(i).text().replace("/","")==lastSelected:
        uist.listBrowser.setItemSelected(uist.listBrowser.item(i),True)

    #for item in list(uist.listBrowser.selec()):
     # print(item.text())

  elif "/"==uist.listBrowser.currentItem().text()[0]:
    bn=uist.listBrowser.currentItem().text()
    ST["workingPath"]=os.path.join(ST["workingPath"]+bn)
    #QtCore.QTimer.singleShot(1,setPath)
    reloadPath()
  elif ".abf" in uist.listBrowser.currentItem().text():
    browserLaunch()
  elif ".tif" in uist.listBrowser.currentItem().text():
    browserLaunch()
  elif ".TIF" in uist.listBrowser.currentItem().text():
    browserLaunch()
  elif " L " in uist.listBrowser.currentItem().text():
    #14.01.02-21.11: double-clicking a linescan launches the folder
    browserLaunch()
  elif " T " in uist.listBrowser.currentItem().text():
    #14.01.02-21.11: double-clicking a time series launches the folder
    browserLaunch()
  elif " S " in uist.listBrowser.currentItem().text():
    #14.01.03-16.39: double-clicking a single image launches the folder
    browserLaunch()
  elif " Z " in uist.listBrowser.currentItem().text():
    #14.01.03-16.39: double-clicking a Z stack launches the folder
    browserLaunch()

def setStatus(msg):
  """controls the color/message of the little status square."""
  if msg=="UPDATED":
    uist.lblBotStatus.setStyleSheet(("font: 7pt \"MS Shell Dlg 2\";\n" "background-color: rgb(63, 232, 147);"))
  elif msg=="MODIFIED":
    uist.lblBotStatus.setStyleSheet(("font: 7pt \"MS Shell Dlg 2\";\n" "background-color: rgb(255, 85, 127);"))
  elif msg=="":
    uist.lblBotStatus.setStyleSheet(("font: 7pt \"MS Shell Dlg 2\";\n"))
  else:
    uist.lblBotStatus.setStyleSheet(("font: 7pt \"MS Shell Dlg 2\";\n" "background-color: rgb(0, 0, 255);"))
  uist.lblBotStatus.setText(msg)

def copyPath():
  """executed when the 'copy' button is pressed. Sets global COPYSTUFF.
  things that are copied are just baseline, events, and structures.
  """
  #14.01.04-12.04: implimented copy/paste functionality for linescan features
  global COPYSTUFF
  thingsToCopy=["guiBaseline","guiEvents","guiMeasure","structures"]
  for item in thingsToCopy:
    COPYSTUFF[item]=LS.config[item]
  COPYSTUFF["copiedFrom"]=os.path.basename(LS.path)
  debug("copied settings from %s"%(COPYSTUFF["copiedFrom"]),1)

def pastePath():
  """executed when the 'paste' button is pressed. Applies global COPYSTUFF."""
  thingsToCopy=["guiBaseline","guiEvents","guiMeasure","structures"]
  for item in thingsToCopy:
    LS.config[item]=COPYSTUFF[item]
  debug("pasted settings from [%s]"%(COPYSTUFF["copiedFrom"]),1)
  LSpopulategui()

def flagClicked():
  """the flag button clicked."""
  #14.01.02-21.11: made the FLAG button do something
  if uist.btnConfigFlag.isChecked():
    LS.flag()
    uist.btnConfigFlag.setText("FLAGGED")
    debug("FLAGGED "+LS.path)
  else:
    LS.unflag()
    uist.btnConfigFlag.setText("FLAG")
    debug("UNFLAGGED "+LS.path)
  browserSelectedRefresh()

def suggestClear():
  uist.btnConfigClear.setStyleSheet(styleYellow)

def hideClicked():
  """Toggle whether the selected folder is hidden"""
  #14.01.13-15.39: added "hide" options which allow shortening of browser path names.
  if os.path.exists(LS.path+"/SAG/hidden"):
    LS.unhide()
    global workingPathFolders
    t=workingPathFolders[uist.listBrowser.currentRow()][2]+" "
    t=t.replace(" H ",'')
    workingPathFolders[uist.listBrowser.currentRow()][2]=t
  else:
    LS.hide()
  browserSelectedRefresh()
  uist.listBrowser.setFocus()
  return

### REPORT ###

def reportGenerate():
  """generateReport()"""
  debug("GENERATING REPORT FOR SELECTED ITEM...",1)
  reports.reportSummaryLS(LS.path)
  debug()
  reportRefresh()

def reportRefresh():
  """load the report in the report browser."""
  uist.webView_report.setUrl(QtCore.QUrl(LS.path+"/SAG/html/index.html"))

def reportLaunch():
  """threadedly launch explorer with html site."""
  launchThreaded(LS.path+"/SAG/html/index.html")

### PAGE NAVIGATION ###

#PAGE LIST
# 0 - changelog
# 1 - LS editor
# 2 - LS report generator
# 3 - LS experiment designer
# 4 - DATA viewer


def pageLSedit():
  """set appropriate page."""
  uist.stackedWidget.setCurrentIndex(0)
  pass


def pageLSreport():
  """set appropriate page."""
  #14.01.05-23.57: started work on experiment design page
  uist.stackedWidget.setCurrentIndex(1)
  pass

def pageLSexperiment():
  """set appropriate page."""
  #14.01.05-23.57: started work on experiment design page
  uist.stackedWidget.setCurrentIndex(2)
  pass

def pageXML():
  """set appropriate page."""
  #14.01.05-23.57: added raw XML data viewer
  style="background-color: rgb(00, 33, 66); "
  style+='font: 75 8pt "Consolas"; '
  style+='color: rgb(255, 255, 255); '
  uist.teConfig.setStyleSheet(style)
  uist.stackedWidget.setCurrentIndex(3)
  fname=glob.glob(LS.path+"/*.xml")[0]
  f=open(fname)
  stuff=f.read()
  f.close()
  uist.teConfig.setPlainText(stuff)

def pageConfig():
  """set appropriate page."""
  #14.01.05-23.57: added current linescan configuration (.ini) data viewer
  style="background-color: rgb(00, 00, 00); "
  style+='font: 75 10pt "Consolas"; '
  style+='color: rgb(85, 255, 127); '
  uist.teConfig.setStyleSheet(style)
  uist.stackedWidget.setCurrentIndex(3)
  uist.teConfig.setPlainText(dictSave(LS.config))


def pageChangelog(event=None):
  """set appropriate page."""
  uist.stackedWidget.setCurrentIndex(4)

def pageZseriesProject():
  """project the current folder."""
  debug("Projecting... this could take a minute or two...",1)
  selectedPath=workingPathFolders[uist.listBrowser.currentRow()][1]
  ZS=SAGformats.ZSeries(selectedPath)
  del ZS
  pageZseries()
  debug()

def pageZseries(path=None):
  """set appropriate page."""
  #14.01.24-14.51: added a lot of code to allow for T-series projection viewing
  uist.stackedWidget.setCurrentIndex(5)
  uist.lblZa.clear()
  uist.lblZb.clear()
  uist.lblZc.clear()
  uist.lblZd.clear()

  if path==None:
    path=workingPathFolders[uist.listBrowser.currentRow()][1]

  if os.path.exists(path+"/SAG/CH1.png"):
    uist.lblZa.setPixmap(QtGui.QPixmap(path+"/SAG/CH1.png"))
  if os.path.exists(path+"/SAG/CH2.png"):
    uist.lblZc.setPixmap(QtGui.QPixmap(path+"/SAG/CH2.png"))

  if os.path.exists(path+"/SAG/CH1z.png"):
    uist.lblZb.setPixmap(QtGui.QPixmap(path+"/SAG/CH1z.png"))
  if os.path.exists(path+"/SAG/CH2z.png"):
    uist.lblZd.setPixmap(QtGui.QPixmap(path+"/SAG/CH2z.png"))

def pageTseriesSet():
  """the marker has been changed."""
  #14.01.24-14.51: added a lot of code to allow for T-series viewing
  path=Tfnames[uist.slideT.value()]
  qpx=QtGui.QPixmap(path)
  uist.lblT.setPixmap(qpx)
  uist.lblT2.setPixmap(qpx)

def pageTseriesGenerate():
  """create T series JPG files."""
  debug("converting T-series files ...",1)
  path=workingPathFolders[uist.listBrowser.currentRow()][1]
  if not os.path.exists(path+"/SAG/"):
    os.mkdir(path+"/SAG/")
  for fname in glob.glob(path+"/*Ch*.tif"):
    fout=os.path.split(fname)[0]+"/SAG/"+os.path.basename(fname).replace(".tif",".jpg")
    imFromLSArray(pylab.imread(fname),fout)

  for fname in glob.glob(path+"/SAG/*Ch1*.jpg"):
    fnameA=fname
    fnameB=fname.replace("Ch1","Ch2")
    fout=fnameA.replace("Ch1","Ch3")
    cmd='convert "%s" "%s" "%s" -channel RGB -combine "%s"'%(fnameA,fnameB,fnameA,fout)
    execute(cmd) #DONT THREAD THIS OUT BECAUSE IT NEEDS TO COMPLETE

  #14.01.24-14.51: create 'animaged.gif' any time a tseries is converted.
  pth=os.path.split(fname)[0]+"/"
  cmd='convert -delay 10 -loop 0 "%s*Ch1*.jpg" "%sch1.gif"'%(pth,pth)
  debug("creating animaged CH1 ...",1)
  threadCommand(cmd)
  cmd='convert -delay 10 -loop 0 "%s*Ch2*.jpg" "%sch2.gif"'%(pth,pth)
  debug("creating animaged CH2 ...",1)
  threadCommand(cmd)
  cmd='convert -delay 10 -loop 0 "%s*Ch3*.jpg" "%sch3.gif"'%(pth,pth)
  debug("creating animaged RGB ...",1)
  threadCommand(cmd)

  debug()

def pageTseriesPlay():
  #14.01.24-14.51: got T-series animation working.
  """continuously play video of animation."""
  if uist.btnTgen.isChecked():
    if uist.slideT.value()==uist.slideT.maximum():
      uist.slideT.setValue(0)
    else:
      uist.slideT.setValue(uist.slideT.value()+1)
    QtCore.QTimer.singleShot(50,pageTseriesPlay)

def pageTseries(path=None):
  """set appropriate page."""
  if path==None:
    path=workingPathFolders[uist.listBrowser.currentRow()][1]

  if len(glob.glob(path+"/SAG/*.jpg"))==0:
    pageTseriesGenerate()

  global Tfnames
  uist.stackedWidget.setCurrentIndex(6)
  Tfnames=sorted(glob.glob(path+"/SAG/*Ch3*.jpg")) #TODO: make this user selectable
  uist.slideT.setMaximum(len(Tfnames)-1)
  uist.slideT.valueChanged.connect(pageTseriesSet)
  uist.slideT.setValue(0)
  pageTseriesSet()



### BIG GUI ACTIONS ###

def launchReg(event=None):
  """ask user to enter registration information."""
  registration.activator_alone()
  registration.activator_website()

def clearEverything():
  """reset entire GUI to empty state."""
  clearBrowser()
  clearSettings()


def clearSettings():
  """reset commonly modified GUI settings to empty state."""
  global ST
  global LS
  LS=None
  global LSconfig
  LSconfig=None

  debug("clearSettings()")

  # PAGE INFO
  uist.btnPageConfig.setEnabled(False)
  uist.btnPageExperiment.setEnabled(True)
  uist.btnPageLS.setEnabled(False)
  uist.btnPageLSreport.setEnabled(False)
  uist.btnPageXML.setEnabled(False)
  #uist.lblProgram.linkActivated.connect(pageChangelog)
  uist.lblProgram.mouseDoubleClickEvent=pageChangelog

  uist.gbConfiguration.setEnabled(False)

  # MAIN FRAME
  uist.lblVersion.setText("v%.02f"%ST["version"])
  uist.lblVersion2.setText("v%.02f"%ST["version"])
  uist.lblBotDim.clear()
  uist.lblBotPmt.clear()
  uist.lblBotPockel.clear()
  #uist.lblBotStatus.clear()
  uist.lblBotMsg.clear()
  setStatus("")

  # BROWSER
  #uist.cbBrS.setChecked(False)
  #uist.cbBrL.setChecked(True)
  #uist.cbBrT.setChecked(False)
  #uist.cbBrZ.setChecked(False)
  #uist.cbBrA.setChecked(False)
  #uist.cbBrAll.setChecked(False)
  uist.btnExp.setChecked(False)
  uist.btnBrowserStore.setChecked(False)
  uist.btnBrowserStore.setCheckable(True)

  # CONFIGURATION
  #14.01.03-16.39: allowed 'configuration' groupbox to be always enabled (allowing deleting of corrupted or outdated /sag/ files which may cause crashing or incomplete loading)
  #uist.gbConfiguration.setEnabled(False)
  uist.btnConfigFlag.setCheckable(True)
  uist.btnConfigFlag.setChecked(False)
  uist.btnConfigFlag.setText("FLAG")
  uist.btnConfigHide.setChecked(False)
  uist.btnConfigHide.setText("HIDE")


  # NOTES
  uist.teNotes.clear()

  # LINESCAN EDITOR
  #uist.gbLinescan.setEnabled(False)
  uist.lblRef.setVisible(False)
  uist.lblRef.setScaledContents(True)
  uist.lblPK.setVisible(False)
  uist.lblPK.setScaledContents(True)
  uist.lblOL.setVisible(False)
  uist.lblOL.setScaledContents(True)
  uist.lblLS.setVisible(False)
  uist.lblLS.setScaledContents(True)

  # STRUCTURE
  uist.gbStructure.setEnabled(False)
  uist.listStruct.clear()
  uist.lineStructure.clear()
  uist.lblStrA.setText("A=")
  uist.lblStrB.setText("B=")
  uist.lblStrW.setText("W=")
  uist.lineStructure.setEnabled(False)
  # CYCLES COLUMN
  uist.gbCycles.setEnabled(False)
  uist.listCycles.clear()
  uist.sbGaussSpace.setValue(1)
  uist.sbGaussTime.setValue(1)
  #14.04.19-16.15: made default smoothing values 1 instead of 0

  # TIME DOMAIN
  uist.gbTime.setEnabled(False)
  uist.lineBL.clear()
  uist.lineEV.clear()
  uist.lineMS.clear()
  uist.lineAV.clear()
  uist.linePK.clear()

  # CALIBRATION
  uist.gbCalib.setEnabled(False)
  uist.sbRmax.setValue(0)
  uist.sbGmax.setValue(0)
  uist.gbCalib.setChecked(False)

  # PREVIEW
  uist.gbPreview.setEnabled(False)
  uist.cbPrvMax.setChecked(True)
  uist.cbPrvMin.setChecked(True)
  LSmodechange()


  # GRAPH
  uist.lblGraph.setVisible(False)
  uist.lblGraph.setStyleSheet("")




if __name__ == "__main__":
  ST=dictUpdate(ST,dictLoad("defaults.ini"))
  app = QtGui.QApplication(sys.argv)

  ### SET-UP WINDOWS

  # WINDOW st
  win_st = ui_st.QtGui.QMainWindow()
  uist = ui_st.Ui_win_st()
  uist.setupUi(win_st)

  ### CONNECTIONS ###

  ### PAGES
  #WHEN STARTING UP, BEGIN WITH CHANGELOG
  pageChangelog()
  uist.btnPageLS.clicked.connect(pageLSedit)
  uist.btnPageLSreport.clicked.connect(pageLSreport)
  uist.btnPageExperiment.clicked.connect(pageLSexperiment)
  uist.btnPageXML.clicked.connect(pageXML)
  uist.btnPageConfig.clicked.connect(pageConfig)


  ### PAGE EXPERIMENT
  uist.btnExpClear.clicked.connect(LSC_clear)
  uist.btnExpDel.clicked.connect(LSC_del)
  uist.btnExpLaunch.clicked.connect(LSC_launch)
  uist.btnExpLoad.clicked.connect(LSC_load)
  uist.btnExpPull.clicked.connect(LSC_pull)
  uist.btnExpPush.clicked.connect(LSC_updateGui)
  uist.btnExpSave.clicked.connect(LSC_save)
  LSC_updateGui()

  ### PAGE REPORTS

  uist.btnHTMLgen.clicked.connect(reportGenerate)
  uist.btnHTMLlaunch.clicked.connect(reportLaunch)
  uist.btnHTMLrefresh.clicked.connect(reportRefresh)

  ### PAGE Z SERIES
  uist.btnZproj.clicked.connect(pageZseriesProject)
  uist.lblZa.mouseDoubleClickEvent=browserLaunch
  uist.lblZb.mouseDoubleClickEvent=browserLaunch
  uist.lblZc.mouseDoubleClickEvent=browserLaunch
  uist.lblZd.mouseDoubleClickEvent=browserLaunch

  ### PAGE T SERIES
  uist.btnTgen.clicked.connect(pageTseriesPlay)






  ### BROWSER

  #changed: to speed up browsing, gave option to store .pkl of index
  uist.btnBrowserStore.clicked.connect(browserStore)
  uist.lblBlock.setGeometry(5,2,221,561)
  uist.listBrowser.doubleClicked.connect(browserDC)
  #uiplot.lblOL.mousePressEvent = getPos
  #uist.btnBrowserPath.mousePressEvent = setpath
  uist.btnBrowserPath.clicked.connect(clickSetPath)
  #uist.listBrowser.selectionChanged.connect(browserSelectionChanged)
  uist.listBrowser.selectionModel().selectionChanged.connect(browserSelectionChanged)

  #14.01.02-21.43: when program launches, configure to view only linescan files
  uist.cbBrAll.setChecked(False)
  uist.cbBrL.setChecked(True)


  uist.btnBrowserRefresh.clicked.connect(reloadPathForce)
  uist.btnBrowserLaunch.clicked.connect(browserLaunch)

  #its too slow to connect this
  uist.cbBrS.stateChanged.connect(setPath)
  uist.cbBrL.stateChanged.connect(setPath)
  uist.cbBrT.stateChanged.connect(setPath)
  uist.cbBrZ.stateChanged.connect(setPath)
  uist.cbBrA.stateChanged.connect(setPath)
  uist.cbBrH.stateChanged.connect(setPath)
  uist.cbBrAll.stateChanged.connect(cbBrAll)
  uist.cbAtLeast.clicked.connect(setPath)
  uist.sbAtLeast.valueChanged.connect(setPath)

  uist.btnConfigSave.clicked.connect(LSsaveEverything)
  uist.btnConfigClear.clicked.connect(LSdeleteSettings)
  uist.btnConfigRevert.clicked.connect(LSrevert)
  uist.btnConfigCopy.clicked.connect(copyPath)
  uist.btnConfigPaste.clicked.connect(pastePath)
  uist.btnConfigFlag.clicked.connect(flagClicked)
  uist.btnConfigHide.clicked.connect(hideClicked)

  ### SCANS
  uist.btnExp.clicked.connect(LSC_expClicked)

  ### NOTES
  #14.01.04-12.04: replaced experiment label with a textbox for notes.
  uist.teNotes.textChanged.connect(LSnotesModified)
  uist.gbNotes.setEnabled(False)

  ### LINESCAN VIEWER
  uist.lblRef.mouseDoubleClickEvent=LSlaunchRef
  uist.cbPrv.currentIndexChanged.connect(LSmodechange)
  uist.cbStretch.clicked.connect(LSupdateLS)
  #14.01.02-21.43: linescan image is updated with channel dropdown is CHANGEd
  uist.cbLS.currentIndexChanged.connect(LSupdateLS)

  ### CYCLES
  uist.listCycles.selectionModel().selectionChanged.connect(LSupdateCycles)
  uist.btnCycleAll.clicked.connect(LScycleAll)
  uist.btnCycleNone.clicked.connect(LScycleNone)
  uist.btnCycle1.clicked.connect(LScycleSelectionMode)
  #uist.btn

  ### STRUCTURE EDITOR
  uist.vs1.valueChanged.connect(LSstructureValueChanged)
  uist.vs2.valueChanged.connect(LSstructureValueChanged)
  uist.vs1.mouseReleaseEvent=LSupdateGraph
  uist.vs1.keyReleaseEvent=LSupdateGraph
  uist.vs2.mouseReleaseEvent=LSupdateGraph
  uist.vs2.keyReleaseEvent=LSupdateGraph
  uist.btnStDel.clicked.connect(LSstructureRemove)
  uist.btnStIns.clicked.connect(LSstructureInsert)
  uist.listStruct.selectionModel().selectionChanged.connect(LSselectedStructureChanged)
  uist.btnStrRename.clicked.connect(LSstructFromLine)

  ### TIME WINDOW

  uist.lineEV.textChanged.connect(LSupdateNeeded)
  uist.lineBL.textChanged.connect(LSupdateNeeded)
  uist.lineMS.textChanged.connect(LSupdateNeeded)

  uist.btnTimeUpdate.clicked.connect(LSupdateTimes)
  #uist.sbGaussSpace.mouseReleaseEvent=LSupdateBlurs
  #uist.sbGaussTime.mouseReleaseEvent=LSupdateBlurs
  uist.sbGaussSpace.valueChanged.connect(LSupdateBlurs)
  uist.sbGaussTime.valueChanged.connect(LSupdateBlurs)

  ### PREVIEW WINDOW
  uist.btnPrvSweeps.clicked.connect(LSupdateGraph)
  uist.cbPrv.currentIndexChanged.connect(LSupdateGraph)
  uist.cbPrvMin.clicked.connect(LSupdateGraph)
  uist.cbPrvMax.clicked.connect(LSupdateGraph)

  ### LINESCAN GB
  uist.gbLinescan.setEnabled(False)

  ### INIT ###
  clearEverything()
  y="|:DI-CP|||:DERIUQER|NOITARTSIGER".replace("|","\n")
  a,b,c=pull()+[getGrape()]
  uist.lblBlock.setText(y[::-1]+c+'\n'*8)
  uist.lblRegKey.setText(b)
  uist.lblRegName.setText(a)
  uist.lblRegPCID.setText(c)
  f=open('./license.txt')
  lic=f.read()
  f.close()
  uist.teLicense.setPlainText(lic)
  uist.lblDistDate.setText(versionDate)
  uist.lblBlock.mousePressEvent=launchReg
  #registration.activator_alone()


  ### DISPLAY WINDOWS
  win_st.show()
  #14.01.04-12.04: forced window to pop-up to front of stacked windows upon launch.
  win_st.raise_()

  #14.01.03-16.39: allow path in defaults.ini to be a list of paths. The first valid one that exists() will be used.
  gotopath='./'
  for fpath in ST["browserPath"]:
    if os.path.exists(fpath):
      gotopath=fpath
      break
  reloadPath(gotopath)

  #WAIT UNTIL QT RETURNS EXIT CODE
  #sys.exit(app.exec_())
  app.exec()

  print("EXITING.")