Пример #1
1
    def initUI(self):
        self.parent.title("Buttons")
        self.style = Style()
        self.style.theme_use("default")

        frame = Frame(self, relief=GROOVE, borderwidth=5)
        frame.pack(fill=BOTH, expand=1)
        self.pack(fill = BOTH, expand = 1)

        self.imageLabel = Label(frame, image = "")
        self.imageLabel.pack(fill=BOTH, expand=1)

        closeButton = Button(self, text="Close")
        closeButton.pack(side=RIGHT)
        okButton = Button(self, text="OK")
        okButton.pack(side=RIGHT)

        options = [item for item in dir(cv2.cv) if item.startswith("CV_CAP_PROP")]
        option = OptionMenu(self, self.key, *options)
        self.key.set(options[0])
        option.pack(side="left")

        spin = Spinbox(self, from_=0, to=1, increment=0.05)
        self.val = spin.get()
        spin.pack(side="left")
Пример #2
0
class Application(Frame):
    MAXWORDLEN = 20
    DEFAULTWORDLEN = 3
    MANDATORY1stCHAR=0

    def __init__(self, master=None):
        Frame.__init__(self, master, padx=3, pady=3)
        self.dictionaryfile = None
        self.menubar = Menu()
        self.__createWidgets()
        self.menubar.add_cascade(label='File', menu=self.__File)
        self.menubar.add_cascade(label='Options', menu=self.__Options)
        self.menubar.add_command(label='About', command=self.__about)
        self.__params.grid(row=0, column=0, sticky=W)
        self.__res_pane = Frame()
        self.__res_pane.grid(row=2, column=0, sticky=E + W)
        self.__status = Label(anchor=W, relief=SUNKEN)
        self.__status.grid(row=3, column=0, sticky=E + W)
        self.osDictFile()
        self.matchobj = None
        if self.dictionaryfile is None:
            self.status('No dictionary defined!')
        master.config(menu=self.menubar)

    def __createWidgets(self):
        self.__params = Frame(padx=5, pady=5)
        Label(text='Letters: ', anchor=E).grid(row=0, column=0,
                                               sticky=E, in_=self.__params)
        self.__char_entry = Entry(width=10)
        self.__chk1st = Checkbutton(variable=self.MANDATORY1stCHAR, command=self.__CB)
        Label(text='First letter appears in every result ', anchor=W).grid(
            row=0, column=4, sticky=E, in_=self.__params)
        self.__char_entry.grid(row=0, column=1, columnspan=2,
                               sticky=W, in_=self.__params)
        self.__chk1st.grid(row=0, column=3, sticky=W, in_=self.__params)
        Label(text='Minimum length of result words: ', anchor=E).grid(
            row=1, column=0, sticky=E, in_=self.__params)
        self.__word_length_ctrl = Spinbox(from_=1, to=Application.MAXWORDLEN,
                                          width=2)
        self.__word_length_ctrl.delete(0, END)
        self.__word_length_ctrl.insert(0, Application. DEFAULTWORDLEN)
        self.__word_length_ctrl.grid(row=1, column=1, in_=self.__params,
                                     sticky=W)
        self.__go_button = Button(text='Go', command=self.__findWords)
        self.__go_button.grid(row=1, column=2, sticky=E, in_=self.__params)
        self.__Options = Menu()
        self.__Options.add_command(label='Choose dictionary',
                                           command=self.__choosedict)
        self.__File = Menu()
        self.__File.add_command(label='Export as ODT (Open document text)', command=self.__export)
        self.__char_entry.focus_set()
        self.__char_entry.bind("<Return>", self.__keyPressEnter)

    def __CB(self):
        self.MANDATORY1stCHAR = not self.MANDATORY1stCHAR

    def __choosedict(self):
        try:
            self.dictionaryfile = tkFileDialog.askopenfile(mode='r').name
            self.status('')
        except AttributeError:
            pass

    def osDictFile(self):
        if 'linux' in sys.platform:
            self.dictionaryfile = '/usr/share/dict/words'

    def __about(self):
        AboutDialog(self)

    def status(self, text):
        self.__status.config(text=text)
        self.__status.update_idletasks()

    def __findWords(self):
        self.__res_pane.grid_forget()
        chars = self.__char_entry.get()
        minlen = int(self.__word_length_ctrl.get())
        if len(chars) < minlen:
            tkMessageBox.showerror(title='Not enough letters',
                        message='''Not enough letters given\n
You must give at least as many letters as the minimum required word length''')
            return
        res = self.__getres(minlen, chars)
        self.__res_pane = ResultPane(res)
        self.__res_pane.grid(row=2, column=0, sticky=E + W)

    def __getres(self, minlen, chars):
        firstpass = True
        while True:
            try:
                self.matchobj = None
                if firstpass and self.dictionaryfile is None:
                    self.matchobj = Match(minlen=minlen, chars=chars,
                                      statushandler=self.status, mand1st=self.MANDATORY1stCHAR)
                    firstpass = False
                else:
                    self.matchobj = Match(minlen=minlen, chars=chars,
                                     dict=self.dictionaryfile,
                                     statushandler=self.status, mand1st=self.MANDATORY1stCHAR)
                res = self.matchobj.wordMatch()
                return res
            except IOError:
                ans = tkMessageBox.askyesno(title='No Dictionary',
                      message='''No dictionary file was found, would
 you like to choose a dictionary file? (No) aborts the application''')
                if ans:
                    self.__choosedict()
                else:
                    sys.exit()

    def __keyPressEnter(self, event):
        self.__findWords()

    def __export(self):
        options= {}
        options['defaultextension'] = '.odt'
        options['filetypes'] = [('all files', '.*'),
                                ('Open Document Text', '.odt')]
        options['initialdir'] = expanduser('~')
        options['initialfile'] = self.__char_entry.get()
        f = asksaveasfilename(**options)

        outfile = Doc(self.matchobj)

        outfile.write(unicode(f, "utf-8"))
Пример #3
0
class Extruder(LabelFrame):
	def __init__(self, root, prtr, settings, log, *arg):
		LabelFrame.__init__(self, root, *arg, text="Extruder")
		self.app = root
		self.printer = prtr
		self.settings = settings
		self.log = log

		self.bExtrude = Button(self, text="Extrude", width=10, command=self.doExtrude)
		self.bExtrude.grid(row=1, column=1, padx=2)
		
		self.spDistance = Spinbox(self, from_=1, to=MAXDIST, width=6, justify=RIGHT)
		self.spDistance.grid(row=1, column=2)
		self.spDistance.delete(0, END)
		self.spDistance.insert(0, STARTDIST)
		self.spDistance.bind("<FocusOut>", self.valDistance)
		self.spDistance.bind("<Leave>", self.valDistance)

		l = Label(self, text="mm", justify=LEFT)
		l.grid(row=1, column=3, sticky=W)

		self.bReverse = Button(self, text="Reverse", width=10, command=self.doReverse)
		self.bReverse.grid(row=2, column=1, padx=2)
		
		self.spSpeed = Spinbox(self, from_=1, to=MAXFEED, width=6, justify=RIGHT)
		self.spSpeed.grid(row=2, column=2)
		self.spSpeed.delete(0, END)
		self.spSpeed.insert(0, self.settings.efeed)
		self.spSpeed.bind("<FocusOut>", self.valSpeed)
		self.spSpeed.bind("<Leave>", self.valSpeed)

		l = Label(self, text="mm/min", justify=LEFT)
		l.grid(row=2, column=3, sticky=W)
		
	def valDistance(self, *arg):
		invalid = False
		try:
			y = float(self.spDistance.get())
		except:
			self.log.logMsg("Value for distance not a valid number")
			invalid = True
		else:
			if y <=0 or y >MAXDIST:
				self.log.logMsg("Value for Distance out of range (0-%d)" % MAXDIST)
				invalid = True
			
		if invalid:
			self.spDistance.delete(0, END)
			self.spDistance.insert(0, STARTDIST)

		return True
	
	def valSpeed(self, *arg):
		invalid = False
		try:
			x = int(self.spSpeed.get())
		except:
			self.log.logMsg("Value for E feed rate not a valid integer")
			invalid = True
		else:
			if x <=0 or x >MAXFEED:
				self.log.logMsg("Value for E feed rate out of range(0-%d)" % MAXFEED)
				invalid = True
			
		if invalid:
			self.spSpeed.delete(0, END)
			self.spSpeed.insert(0, "%d" % self.settings.efeed)
		else:
			if self.settings.efeed != x:
				self.settings.efeed = x
				self.settings.setModified()		
		return True
	
	def doExtrude(self):
		if self.app.printerAvailable(cmd="G91"):
			dist = self.spDistance.get()
			self.printer.send_now("G91")
			self.printer.send_now("G1 E%s F%s" % (dist, self.settings.efeed))
			self.printer.send_now("G90")
	
	def doReverse(self):
		if self.app.printerAvailable(cmd="G91"):
			dist = self.spDistance.get()
			self.printer.send_now("G91")
			self.printer.send_now("G1 E-%s F%s" % (dist, self.settings.efeed))
			self.printer.send_now("G90")
Пример #4
0
class RelyGUI(object):
    """ GUI for driving storage reliability simulations """

    #
    # enumerated values for menus and spin boxes
    #
    disk_type = None
    diskTypes = [       # menu of disk drive types
        "Enterprise", "Consumer", "Real"
    ]

    disk_nre = None
    nre_rates = [       # list of likely NRE rates ... correspond to above
        "1.0E-19", "1.0E-18", "1.0E-17", "1.0E-16", "1.0E-15", "1.0E-14",
        "1.0E-13"
    ]

    # default FIT rates for various classes of drives
    fit_map = {
        'Enterprise': "826",
        'Consumer': "1320",
        'Real': "7800"
    }

    # default NRE rates for various classes of drives
    nre_map = {
        'Enterprise': "1.0E-16",
        'Consumer': "1.0E-15",
        'Real': "1.0E-14"
    }

    raid_type = None
    raidTypes = [       # menu of RAID types
        "RAID-0", "RAID-1", "RAID-5", "RAID-6"
    ]

    raid_vols = None

    # default volume counts for various RAID configurations
    vol_map = {
        'RAID-0': 1,
        'RAID-1': 2,
        'RAID-5': 3,
        'RAID-6': 6,
    }

    nre_model = None
    nreTypes = [      # ways of modeling NREs
        "ignore", "error", "fail", "error+fail/2"
    ]

    raid_rplc = None
    replace_times = [   # list of likely drive replacement times (hours)
        0, 1, 2, 4, 6, 8, 10, 12, 18, 24
    ]

    rados_down = None
    markout_times = [  # list of likely OSD mark-down times (minutes)
        0, 1, 2, 3, 4, 5, 10, 15, 20, 30, 45, 60
    ]

    raid_speed = None
    rados_speed = None
    rebuild_speeds = [  # list of likely rebuild speeds (MB/s)
        1, 2, 5, 10, 15, 20, 25, 40, 50, 60, 80, 100, 120, 140, 160
    ]

    remote_latency = None
    async_latencies = [  # list of likely asynchronous replication latencies
        0, 1, 5, 10, 30, 60, 300, 600, 900, 1800, 3600,
        2 * 3600, 6 * 3600, 12 * 3600, 18 * 3600, 24 * 3600
    ]

    rados_fullness = None
    fullness = [    # list of likely volume fullness percentages
        50, 75, 80, 85, 90, 95, 100
    ]

    site_num = None
    site_count = [  # list of likely remote site numbers
        1, 2, 3, 4, 5, 6, 7, 8, 9, 10
    ]

    remote_speed = None
    remote_speeds = [   # list of likely remote recovery speeds (MB/s)
        1, 2, 5, 10, 20, 25, 40, 50, 60, 80, 100, 150,
        200, 300, 400, 500, 600, 800, 1000
    ]

    remote_fail = None
    site_destroy = [    # force majeure event frequency
        10, 100, 1000, 10000, 100000, "never"
    ]

    remote_rplc = None
    site_recover = [    # number of days to recover a destroyed facility
        1, 2, 4, 8, 12, 16, 20, 30, 40, 50, 60, 80,
        100, 150, 200, 250, 300, 365, "never"
    ]

    verbosities = [    # display verbosity
        "all",
        "parameters",
        "headings",
        "data only"
    ]

    verbosity = None
    period = None
    disk_size = None
    rados_pgs = None
    rados_cpys = None
    stripe_length = None

    # these we generate dynamically
    obj_size = None
    object_sizes = []
    min_obj_size = 1 * 1024 * 1024
    max_obj_size = 1 * 1024 * 1024 * 1024 * 1024
    step_obj_size = 4

    # GUI widget field widths
    ROWS = 20
    BORDER = 5
    short_wid = 2
    med_wid = 4
    long_wid = 6
    short_fmt = "%2d"
    med_fmt = "%4d"
    long_fmt = "%6d"

    # references to the input widget fields (I know ...)

    def do_disk(self):
        """ calculate disk reliability """
        self.getCfgInfo()
        self.doit(self.cfg, "disk")

    def do_raid(self):
        """ calculate raid reliability """
        self.getCfgInfo()
        self.doit(self.cfg, "raid")

    def do_rados(self):
        """ calculate RADOS reliability """
        self.getCfgInfo()
        self.doit(self.cfg, "rados")

    def do_sites(self):
        """ calculate Multi-Site RADOS reliability """
        self.getCfgInfo()
        self.doit(self.cfg, "multi")

    def diskchoice(self, value):
        """ change default FIT and NRE rates to match disk selection """
        self.disk_nre.delete(0, END)
        self.disk_nre.insert(0, self.nre_map[value])
        self.disk_fit.delete(0, END)
        self.disk_fit.insert(0, self.fit_map[value])
        self.disk_fit2.delete(0, END)
        self.disk_fit2.insert(0, self.fit_map[value])

    def raidchoice(self, value):
        """ change default # of volumes to match RAID levels """
        self.raid_vols.delete(0, END)
        self.raid_vols.insert(0, self.vol_map[value])

    def __init__(self, cfg, doit):
        """ create the GUI panel widgets
            cfg -- parameter values (input and output)
            doit -- method to call to run simulations
            """

        # gather the basic parameters
        self.cfg = cfg
        self.doit = doit

        self.root = Tk()
        self.root.title('Data Reliability Model')
        t = Frame(self.root, bd=2 * self.BORDER)
        # w.iconbitmap(default='inktank.ico')   # ? windows only ?

        # left stack (DISK)
        f = Frame(t, bd=self.BORDER, relief=RIDGE)
        r = 1
        Label(f, text="Disk Type").grid(row=r)
        self.disk_type = StringVar(f)
        self.disk_type.set(self.diskTypes[0])
        OptionMenu(f, self.disk_type, *self.diskTypes,
                   command=self.diskchoice).grid(row=r + 1)
        Label(f).grid(row=r + 2)
        r += 3
        Label(f, text="Size (GiB)").grid(row=r)
        self.disk_size = Entry(f, width=self.long_wid)
        self.disk_size.delete(0, END)
        self.disk_size.insert(0, self.long_fmt % (cfg.disk_size / GiB))
        self.disk_size.grid(row=r + 1)
        Label(f).grid(row=r + 2)
        r += 3
        Label(f, text="Primary FITs").grid(row=r)
        self.disk_fit = Entry(f, width=self.long_wid)
        self.disk_fit.grid(row=r + 1)
        Label(f).grid(row=r + 2)
        r += 3
        Label(f, text="Secondary FITs").grid(row=r)
        self.disk_fit2 = Entry(f, width=self.long_wid)
        self.disk_fit2.grid(row=r + 1)
        Label(f).grid(row=r + 2)
        r += 3
        Label(f, text="NRE rate").grid(row=r)
        self.disk_nre = Spinbox(f, width=self.long_wid, values=self.nre_rates)
        self.disk_nre.grid(row=r + 1)
        Label(f).grid(row=r + 2)
        r += 3
        while r < self.ROWS:
            Label(f).grid(row=r)
            r += 1
        Button(f, text="RELIABILITY", command=self.do_disk).grid(row=r)
        f.grid(column=1, row=1)
        self.diskchoice(self.diskTypes[0])  # set default disk type

        # second stack (RAID)
        f = Frame(t, bd=self.BORDER, relief=RIDGE)
        r = 1
        Label(f, text="RAID Type").grid(row=r)
        self.raid_type = StringVar(f)
        self.raid_type.set("RAID-1")
        OptionMenu(f, self.raid_type, *self.raidTypes,
                   command=self.raidchoice).grid(row=r + 1)
        Label(f).grid(row=r + 2)
        r += 3
        Label(f, text="Replace (hours)").grid(row=r)
        self.raid_rplc = Spinbox(f, width=self.short_wid,
                                 values=self.replace_times)
        self.raid_rplc.grid(row=r + 1)
        self.raid_rplc.delete(0, END)
        self.raid_rplc.insert(0, "%d" % cfg.raid_replace)
        Label(f).grid(row=r + 2)
        r += 3
        Label(f, text="Rebuild (MiB/s)").grid(row=r)
        self.raid_speed = Spinbox(f, width=self.med_wid,
                                  values=self.rebuild_speeds)
        self.raid_speed.grid(row=r + 1)
        self.raid_speed.delete(0, END)
        self.raid_speed.insert(0, "%d" % (cfg.raid_recover / MiB))
        Label(f).grid(row=r + 2)
        r += 3
        Label(f, text="Volumes").grid(row=r)
        self.raid_vols = Spinbox(f, from_=1, to=10, width=self.short_wid)
        self.raid_vols.grid(row=r + 1)
        Label(f).grid(row=r + 2)
        self.raidchoice("RAID-1")   # set default number of volumes
        r += 3
        while r < self.ROWS:
            Label(f).grid(row=r)
            r += 1
        Button(f, text="RELIABILITY", command=self.do_raid).grid(row=r)
        f.grid(column=2, row=1)

        # third stack (RADOS)
        f = Frame(t, bd=self.BORDER, relief=RIDGE)
        r = 1
        Label(f, text="RADOS copies").grid(row=r)
        self.rados_cpys = Spinbox(f, values=(1, 2, 3, 4, 5, 6),
                                  width=self.short_wid)
        self.rados_cpys.grid(row=r + 1)
        self.rados_cpys.delete(0, END)
        self.rados_cpys.insert(0, "%d" % cfg.rados_copies)
        Label(f).grid(row=r + 2)
        r += 3
        Label(f, text="Mark-out (min)").grid(row=r)
        self.rados_down = Spinbox(f, values=self.markout_times,
                                  width=self.short_wid)
        self.rados_down.grid(row=r + 1)
        self.rados_down.delete(0, END)
        self.rados_down.insert(0, "%d" % (cfg.rados_markout * 60))
        Label(f).grid(row=r + 2)
        r += 3
        Label(f, text="Recovery (MiB/s)").grid(row=r)
        self.rados_speed = Spinbox(f, width=self.med_wid,
                                   values=self.rebuild_speeds)
        self.rados_speed.grid(row=r + 1)
        self.rados_speed.delete(0, END)
        self.rados_speed.insert(0, "%d" % (cfg.rados_recover / MiB))
        Label(f).grid(row=r + 2)
        r += 3
        Label(f, text="Space Usage (%)").grid(row=r)
        self.rados_fullness = Spinbox(f, values=self.fullness,
                                      width=self.med_wid)
        self.rados_fullness.grid(row=r + 1)
        self.rados_fullness.delete(0, END)
        self.rados_fullness.insert(0, "%d" % (cfg.rados_fullness * 100))
        Label(f).grid(row=r + 2)
        r += 3
        Label(f, text="Declustering (pg)").grid(row=r)
        self.rados_pgs = Entry(f, width=self.med_wid)
        self.rados_pgs.delete(0, END)
        self.rados_pgs.insert(0, self.med_fmt % cfg.rados_decluster)
        self.rados_pgs.grid(row=r + 1)
        Label(f).grid(row=r + 2)
        r += 3
        Label(f, text="Stripe Length").grid(row=r)
        self.stripe_length = Entry(f, width=self.med_wid)
        self.stripe_length.delete(0, END)
        self.stripe_length.insert(0, self.med_fmt % cfg.stripe_length)
        self.stripe_length.grid(row=r + 1)
        Label(f).grid(row=r + 2)
        r += 3
        while r < self.ROWS:
            Label(f).grid(row=r)
            r += 1
        Button(f, text="RELIABILITY", command=self.do_rados).grid(row=r)
        f.grid(column=3, row=1)

        # fourth stack (remote site)
        r = 1
        f = Frame(t, bd=self.BORDER, relief=RIDGE)
        Label(f, text="RADOS Sites").grid(row=r)
        self.site_num = Spinbox(f, values=self.site_count,
                                width=self.short_wid)
        self.site_num.grid(row=r + 1)
        self.site_num.delete(0, END)
        self.site_num.insert(0, "%d" % cfg.remote_sites)
        Label(f).grid(row=r + 2)
        r += 3
        Label(f, text="Rep Latency (s)").grid(row=r)
        self.remote_latency = Spinbox(f, values=self.async_latencies,
                                      width=self.long_wid)
        self.remote_latency.grid(row=r + 1)
        self.remote_latency.delete(0, END)
        self.remote_latency.insert(0, "%d" % (cfg.remote_latency * 60 * 60))
        Label(f).grid(row=r + 2)
        r += 3
        Label(f, text="Recovery (MiB/s)").grid(row=r)
        self.remote_speed = Spinbox(f, values=self.remote_speeds,
                                    width=self.med_wid)
        self.remote_speed.grid(row=r + 1)
        self.remote_speed.delete(0, END)
        self.remote_speed.insert(0, "%d" % (cfg.remote_recover / MiB))
        Label(f).grid(row=r + 2)
        r += 3
        Label(f, text="Disaster (years)").grid(row=r)
        self.remote_fail = Spinbox(f, values=self.site_destroy,
                                   width=self.long_wid)
        self.remote_fail.grid(row=r + 1)
        self.remote_fail.delete(0, END)
        self.remote_fail.insert(0, "1000")
        # FIX - get this from cfg ... but translate from FITS
        Label(f).grid(column=2, row=r + 2)
        r += 3
        Label(f, text="Site Recover (days)").grid(row=r)
        self.remote_avail = Spinbox(f, values=self.site_recover,
                                    width=self.long_wid)
        self.remote_avail.grid(row=r + 1)
        self.remote_avail.delete(0, END)
        self.remote_avail.insert(0, "30")
        # FIX - get this from cfg ... but translate from FITS
        Label(f).grid(row=r + 2)
        r += 3
        while r < self.ROWS:
            Label(f).grid(row=r)
            r += 1
        Button(f, text="RELIABILITY", command=self.do_sites).grid(row=r)
        f.grid(column=4, row=1)

        # and the control panel
        r = 2
        c = 1
        Label(t).grid(column=c, row=r)
        Label(t, text="NRE model").grid(column=c, row=r + 1)
        self.nre_model = StringVar(t)
        self.nre_model.set(self.cfg.nre_model)
        OptionMenu(t, self.nre_model, *self.nreTypes).grid(column=c, row=r + 2)

        c = 2
        Label(t).grid(column=c, row=r)
        Label(t, text="Period (years)").grid(column=c, row=r + 1)
        self.period = Spinbox(t, from_=1, to=10, width=self.short_wid)
        self.period.grid(column=c, row=r + 2)

        c = 3
        Label(t).grid(column=c, row=r)
        Label(t, text="Object size").grid(column=c, row=r + 1)
        # generate object sizes dynamically from parameters
        os = self.min_obj_size
        while os <= self.max_obj_size:
            if os < MB:
                s = "%dKB" % (os / KB)
            elif os < GB:
                s = "%dMB" % (os / MB)
            elif os < TB:
                s = "%dGB" % (os / GB)
            else:
                s = "%dTB" % (os / TB)
            self.object_sizes.append(s)
            os *= self.step_obj_size
        self.obj_size = Spinbox(t, values=self.object_sizes,
                                width=self.long_wid)
        self.obj_size.grid(column=c, row=r + 2)
        self.obj_size.delete(0, END)
        self.obj_size.insert(0, self.object_sizes[0])

        c = 4
        Label(t).grid(column=c, row=r)
        Label(t, text="Verbosity").grid(column=c, row=r + 1)
        self.verbosity = StringVar(t)
        self.verbosity.set(cfg.verbose)
        OptionMenu(t, self.verbosity, *self.verbosities).grid(column=c,
                                                              row=r + 2)

        # and then finalize everything
        t.grid()

    def getCfgInfo(self):
        """ scrape configuration information out of the widgets """
        self.cfg.period = 365.25 * 24 * int(self.period.get())
        self.cfg.disk_type = self.disk_type.get()
        self.cfg.disk_size = int(self.disk_size.get()) * GiB
        self.cfg.disk_nre = float(self.disk_nre.get())
        self.cfg.disk_fit = int(self.disk_fit.get())
        self.cfg.disk_fit2 = int(self.disk_fit2.get())
        self.cfg.raid_vols = int(self.raid_vols.get())
        self.cfg.raid_type = self.raid_type.get()
        self.cfg.raid_replace = int(self.raid_rplc.get())
        self.cfg.raid_recover = int(self.raid_speed.get()) * MiB
        self.cfg.nre_model = self.nre_model.get()
        self.cfg.rados_copies = int(self.rados_cpys.get())
        self.cfg.rados_markout = float(self.rados_down.get()) / 60
        self.cfg.rados_recover = int(self.rados_speed.get()) * MiB
        self.cfg.rados_decluster = int(self.rados_pgs.get())
        self.cfg.stripe_length = int(self.stripe_length.get())
        self.cfg.rados_fullness = float(self.rados_fullness.get()) / 100
        self.cfg.remote_latency = float(self.remote_latency.get()) / (60 * 60)
        self.cfg.remote_sites = int(self.site_num.get())
        self.cfg.remote_recover = int(self.remote_speed.get()) * MiB
        self.cfg.verbose = self.verbosity.get()

        # these parameters can also have the value "never"
        v = self.remote_fail.get()
        self.cfg.majeure = 0 if v == "never" else \
            1000000000 / (float(self.remote_fail.get()) * 365.25 * 24)
        v = self.remote_avail.get()
        self.cfg.site_recover = 0 if v == "never" else \
            float(self.remote_avail.get()) * 24

        # a more complex process for the dynamically generated lists
        self.cfg.obj_size = self.min_obj_size
        i = 0
        while i < len(self.object_sizes) and \
                self.cfg.obj_size < self.max_obj_size:
            if self.obj_size.get() == self.object_sizes[i]:
                break
            self.cfg.obj_size *= self.step_obj_size
            i += 1

        # sanity checking on arguments with limits
        if self.cfg.stripe_length < 1:
            self.cfg.stripe_length = 1
        if self.cfg.stripe_length > self.cfg.rados_decluster:
            print("\nIGNORING stripe width (%d) > decluster (%d)\n" %
                  (self.cfg.stripe_length, self.cfg.rados_decluster))
            self.cfg.stripe_length = self.cfg.rados_decluster

    def mainloop(self):
        self.root.mainloop()
Пример #5
0
class ChargenColor:
    def __init__(self, parent):
        self.colorNegative = []
        self.colorNeutral = []
        self.colorPositive = []

        self.scaleNegative = 0.0
        self.scalePositive = 0.0

        self.cNegative = '#ff0000'
        self.cNeutral = '#000000'
        self.cPositive = '#0000ff'

        self.minNegativeLbl = Label(rootC, text='Min Found: -')
        self.maxPositiveLbl = Label(rootC, text='Max Found: -')

        self.scaleLbl = Label(rootC, text='Scale: - to -')

        self.sclSelectPositive = Spinbox(rootC)
        self.sclSelectPositive.insert(0, 0.0)
        self.sclSelectNegative = Spinbox(rootC)
        self.sclSelectNegative.insert(0, 0.0)

        self.buttonNegativeCharge = Button(
            rootC, text='Negative Charge Color', command=self.chooseNegativeCharge)
        self.buttonNeutralCharge = Button(
            rootC, text='Neutral Charge Color', command=self.chooseNeutralCharge)
        self.buttonPositiveCharge = Button(
            rootC, text='Positive Charge Color', command=self.choosePositiveCharge)
        self.buttonBG = Button(
            rootC, text='Background Color', command=self.chooseBackground)

        self.buttonUpdateColor = Button(
            rootC, text='Update', command=self.updateColor)

        self.title = Label(rootC, text="Select your colors")
        self.buttonClose = Button(rootC, text="Close", command=rootC.destroy)

        self.buttonBG.pack()
        self.title.pack()
        self.buttonNegativeCharge.pack()
        self.buttonNeutralCharge.pack()
        self.buttonPositiveCharge.pack()
        self.minNegativeLbl.pack()
        self.maxPositiveLbl.pack()
        self.scaleLbl.pack()
        self.sclSelectNegative.pack()
        self.sclSelectPositive.pack()
        self.buttonUpdateColor.pack()
        self.buttonClose.pack()

    def chooseNegativeCharge(self):
        self.colorNegative = askcolor(
            color=self.cNegative, title="Negative Charge Color")
        self.buttonNegativeCharge.config(fg=self.colorNegative[1])
        self.cNegative = self.colorNegative[1]

    def chooseNeutralCharge(self):
        self.colorNeutral = askcolor(
            color=self.cNeutral, title="Neutral Charge Color")
        self.buttonNeutralCharge.config(fg=self.colorNeutral[1])
        self.cNeutral = self.colorNeutral[1]

    def choosePositiveCharge(self):
        self.colorPositive = askcolor(
            color=self.cPositive, title="Positive Charge Color")
        self.buttonPositiveCharge.config(fg=self.colorPositive[1])
        self.cPositive = self.colorPositive[1]

    def chooseBackground(self):
        bgcolor = askcolor(
            color=self.cPositive, title="Positive Charge Color")
        cmd.set_color("bg_chargy_color", bgcolor[0])
        cmd.bg_color("bg_chargy_color")

    def updateColor(self):
        selection = 'all'
        stored.atoms_charge = []
        stored.atoms_colors = []
        cmd.map_new('chargyc_map', selection="(all)")

        if not self.colorNeutral:
            tkMessageBox.showerror("Error", "Set Neutral Color, Please")
            return
        if not self.colorNegative:
            tkMessageBox.showerror("Error", "Set Negative Color, Please")
            return
        if not self.colorPositive:
            tkMessageBox.showerror("Error", "Set Positive Color, Please")
            return

        cmd.iterate_state(1, '(' + selection + ')',
                          'stored.atoms_charge.append(partial_charge)')

        _i = 0
        minValue = None
        maxValue = None
        while _i < len(stored.atoms_charge):
            color = []
            if _i == 0:
                maxValue = stored.atoms_charge[_i]
                minValue = stored.atoms_charge[_i]

            if(stored.atoms_charge[_i] > maxValue):
                maxValue = stored.atoms_charge[_i]
            if stored.atoms_charge[_i] < minValue:
                minValue = stored.atoms_charge[_i]
            _i += 1

        self.minNegativeLbl["text"] = 'Min Found: ' + str(round(minValue, 3))
        self.maxPositiveLbl["text"] = 'Max Found: ' + str(round(maxValue, 3))

        if(self.scaleNegative == 0.0 and self.scalePositive == 0.0):
            self.scaleNegative = round(minValue, 3)
            self.scalePositive = round(maxValue, 3)
            self.sclSelectNegative.delete(0, "end")
            self.sclSelectPositive.delete(0, "end")
            self.sclSelectNegative.insert(0, round(minValue, 3))
            self.sclSelectPositive.insert(0, round(maxValue, 3))
        else:
            self.scaleNegative = float(self.sclSelectNegative.get())
            self.scalePositive = float(self.sclSelectPositive.get())
            minValue = float(self.sclSelectNegative.get())
            maxValue = float(self.sclSelectPositive.get())

        self.scaleLbl["text"] = 'Scale: ' + str(
            self.scaleNegative) + ' to ' + str(self.scalePositive)

        middleValue = 0
        if(maxValue < 0):
            maxValue = 0
        if(minValue > 0):
            minValue = 0

        _i = 0
        while _i < len(stored.atoms_charge):
            color = []
            cmd.set_color("neutral_color", self.colorNeutral[0])
            cmd.set_color("positive_color", self.colorPositive[0])
            cmd.set_color("negative_color", self.colorNegative[0])
            if(stored.atoms_charge[_i] >= middleValue):
                if(stored.atoms_charge[_i] == middleValue):
                    cmd.set_color(str(_i) + "_color", self.colorNeutral[0])
                else:
                    cmd.set_color(str(_i) + "_color", self.getColor(
                        self.colorNeutral[0], self.colorPositive[0], maxValue, stored.atoms_charge[_i] if stored.atoms_charge[_i] < maxValue else maxValue))
            else:
                cmd.set_color(str(_i) + "_color", self.getColor(
                    self.colorNeutral[0], self.colorNegative[0], abs(minValue), abs(stored.atoms_charge[_i]) if abs(stored.atoms_charge[_i]) < abs(minValue) else abs(minValue)))

            index = cmd.get_color_index(str(_i) + "_color")
            stored.atoms_colors.append(index)
            _i += 1

        cmd.alter_state(1, '(' + selection + ')',
                        "color=stored.atoms_colors.pop(0)")
        cmd.ramp_new('chargy_ramp', 'chargyc_map', range=[self.scaleNegative, ((self.scaleNegative+self.scalePositive)/2.0), self.scalePositive],
                     color=['negative_color', 'neutral_color', 'positive_color'])

    def getColor(self, color, colorMax, step, index):
        colorStep = [0, 0, 0]

        colorStep[0] = ((colorMax[0]-color[0])/step)
        colorStep[1] = ((colorMax[1]-color[1])/step)
        colorStep[2] = ((colorMax[2]-color[2])/step)

        return [
            1.0 if (color[0] + (colorStep[0]*index)) /
            255.0 >= 1 else (color[0] + (colorStep[0]*index))/255.0,
            1.0 if (color[1] + (colorStep[1]*index)) /
            255.0 >= 1 else (color[1] + (colorStep[1]*index))/255.0,
            1.0 if (color[2] + (colorStep[2]*index)) /
            255.0 >= 1 else (color[2] + (colorStep[2]*index))/255.0
        ]
Пример #6
0
class MoveControl(LabelFrame):
	def __init__(self, root, prtr, settings, log, *arg):
		fn = os.path.join(settings.cmdFolder, "images", "control_xyz.png")
		self.image = Image.open(fn)
		self.photo = ImageTk.PhotoImage(self.image)
		LabelFrame.__init__(self, root, *arg, text="Movement")

		self.app = root
		self.hilite = None
		self.hilitemask = None
		self.settings = settings
		self.printer = prtr
		self.log = log
		
		l = Label(self, text="mm/min")
		l.grid(row=1, column=2)
		
		l = Label(self, text="X/Y Feed Rate:")
		l.grid(row=2, column=1, sticky=E)
		
		self.xyfeed = Spinbox(self, width=10, justify=RIGHT, from_=0, to=MAXFEED)
		self.xyfeed.grid(row=2, column=2)
		self.xyfeed.delete(0, END)
		self.xyfeed.insert(0, settings.xyfeed)
		self.xyfeed.bind("<FocusOut>", self.valxyFeed)
		self.xyfeed.bind("<Leave>", self.valxyFeed)
		
		l = Label(self, text="Z Feed Rate:")
		l.grid(row=3, column=1, sticky=E)
				
		self.zfeed = Spinbox(self, width=10, justify=RIGHT, from_=0, to=MAXFEED)
		self.zfeed.grid(row=3, column=2)
		self.zfeed.delete(0, END)
		self.zfeed.insert(0, settings.zfeed)
		self.zfeed.bind("<FocusOut>", self.valzFeed)
		self.zfeed.bind("<Leave>", self.valzFeed)
		
		self.canvas = Canvas(self, width=self.image.size[0], height=self.image.size[1], *arg)
		self.canvas.create_image((0, 0), image=self.photo, anchor=N+W)
		self.canvas.grid(row=4, column=1, columnspan=2)
		for m in imageMasks:
			self.canvas.create_oval((m[0][0]-mask_rad, m[0][1]-mask_rad, m[0][0]+mask_rad, m[0][1]+mask_rad),
							outline="#FF0000", width=4, tags=m[1], state=HIDDEN)
		self.canvas.bind("<Button-1>", self.OnLeftDown)
		self.canvas.bind("<Motion>", self.OnMotion)
		self.canvas.bind("<Enter>", self.OnEnter)
		self.canvas.bind("<Leave>", self.OnLeave)
		
		self.bAllOff = Button(self, text="Release Motors", command=self.allMotorsOff)	
		self.bAllOff.grid(row=5, column=1, columnspan=2)
		
	def valxyFeed(self, *arg):
		x = self.validFeed(self.xyfeed.get(), 'XY')
			
		if x == None:
			self.xyfeed.delete(0, END)
			self.xyfeed.insert(0, "%d" % self.settings.xyfeed)
			return True

		if self.settings.xyfeed != x:
			self.settings.xyfeed = x
			self.settings.setModified()		
		return True
		
	def valzFeed(self, *arg):
		x = self.validFeed(self.zfeed.get(), 'Z')
			
		if x == None:
			self.zfeed.delete(0, END)
			self.zfeed.insert(0, "%d" % self.settings.zfeed)
			return True

		if self.settings.zfeed != x:
			self.settings.zfeed = x
			self.settings.setModified()		
		return True
	
	def validFeed(self, fv, axis):
		try:
			x = int(fv)
		except:
			self.log.logMsg("Value for %s feed rate not a valid integer" % axis)
			return None

		if x <=0 or x >MAXFEED:
			self.log.logMsg("Value for %s feed rate out of range(0-5000)" % axis)
			return None
		
		return x
	
	def allMotorsOff(self):
		if self.app.printerAvailable(cmd="M84"):
			self.printer.send_now("M84")	

	def OnMotion(self, e):
		for i in range(len(imageGeometry)):
			if boundBy((e.x, e.y), imageGeometry[i][0]):
				self.setHilite(i)
				return
		if self.hilite != None:
			self.clearHilite()

	def OnEnter(self, e):
		self.clearHilite()

	def OnLeave(self, e):
		self.clearHilite()

	def setHilite(self, i):
		if i != self.hilite:
			self.canvas.delete("HILITE")
			self.canvas.create_rectangle(imageGeometry[i][0], outline="#C85E5D", width=3, fill="gray", stipple="gray50", tags="HILITE")
			self.hilite = i
			if self.hilitemask:
				self.canvas.itemconfig(self.hilitemask, state=HIDDEN)
				
			if imageGeometry[i][2]:
				self.hilitemask = imageGeometry[i][2]
				self.canvas.itemconfig(self.hilitemask, state=NORMAL)
				
				
	def clearHilite(self):
		self.canvas.delete("HILITE")
		self.hilite = None
		self.hilitemask = None
		for m in imageMasks:
			self.canvas.itemconfig(m[1], state=HIDDEN)
		
	def OnLeftDown(self, e):
		if self.app.printerAvailable(cmd="G1"):
			for g in imageGeometry:
				if boundBy((e.x, e.y), g[0]):
					if "G1" in g[1]:
						if "X" in g[1]:
							feed = self.settings.xyfeed
						elif "Y" in g[1]:
							feed = self.settings.xyfeed
						elif "Z" in g[1]:
							feed = self.settings.zfeed
						else:
							feed = 100
						self.printer.send_now("G91")
						self.printer.send_now(g[1] + " F" + str(feed))
						self.printer.send_now("G90")
					else:
						self.printer.send_now(g[1])
					break
Пример #7
0
class PeakFinder:
    def __init__(self, master):
        self.master = master
        master.title(u"Weiterreißwiderstand")
        self.big_font = tkFont.Font(family='Helvetica',
        size=36, weight='bold')
        self.normal_font = tkFont.Font(family='Helvetica',
        size=20, weight='normal')
        self.X = None
        self.Y = None
        self.maxima = None
        self.maxima_x = None
        self.number_max = 0
        self.number_max_string = StringVar()
        self.max_max = 0.0
        self.max_max_string = StringVar()
        self.min_max = 0.0
        self.min_max_string = StringVar()
        self.median = 0.0
        self.median_string = StringVar()
        self.w_string = StringVar()
        self.distance_string = StringVar()
        self.method_string = StringVar()
        self.sample_file = ''
        self.project_file = ''
        self.w = 0.0
        self.distance = 0.0
        
        #########################################################################
        
        '''
        Optionen für Dateidialoge
        '''
        self.file_opt = options = {}
        options['defaultextension'] = '.txt'
        options['filetypes'] = [('text files', '.txt')]
        options['initialfile'] = ''
        options['parent'] = master
        options['title'] = 'Messung importieren'
        
        self.file_opt2 = options = {}
        options['defaultextension'] = '.txt'
        options['filetypes'] = [('text files', '.txt')]
        options['initialfile'] = ''
        options['parent'] = master
        options['title'] = 'Neues Projekt erstellen.'
        
        self.file_opt3 = options = {}
        options['defaultextension'] = '.txt'
        options['filetypes'] = [('text files', '.txt')]
        options['initialfile'] = ''
        options['parent'] = master
        options['title'] = 'Vorhandenes Projekt öffnen.'
        
        
        #####################################################################################################
        
        '''
        GUI
        '''
   
        
        '''
        MenueLeiste
        '''
        
        ###############################################################################################
        
        self.menubar = Menu(master)
        # create a pulldown menu, and add it to the menu bar
        self.filemenu = Menu(self.menubar, tearoff=0)
        self.filemenu.add_command(label="Neu", command=self.new_file, font = self.normal_font)
        self.filemenu.add_command(label=u"Öffnen...", command=self.open_file, font = self.normal_font)
        self.filemenu.add_separator()
        self.filemenu.add_command(label="Messung importieren", command=self.get_filepath, font = self.normal_font)
        self.filemenu.add_separator()
        self.filemenu.add_command(label="Beenden", command=root.quit, font = self.normal_font)
        self.menubar.add_cascade(label="Datei", menu=self.filemenu, font = self.normal_font)
        
        self.helpmenu = Menu(self.menubar, tearoff=0)
        self.helpmenu.add_command(label="Hilfe", command=self.help, font = self.normal_font)
        self.helpmenu.add_command(label=u"Über", command=self.info, font = self.normal_font)
        self.menubar.add_cascade(label="Hilfe", menu=self.helpmenu, font = self.normal_font)
        
        master.config(menu=self.menubar)
        
        ##############################################################################################
        
        
        '''
        Parameter
        '''
        self.option_label = ttk.Label(master, text = "Parameter", font = self.big_font)
        self.option_label.grid(row = 0, rowspan = 2, columnspan = 4, sticky=W)
        
        self.delta_x_label = ttk.Label(master, text = "Delta X", font = self.normal_font)
        self.delta_x_label.grid(row = 3, sticky=W)
        
        self.delta_x_spinbox = Spinbox(master, from_=10, to=500, increment = 10, font = self.normal_font, width = 4, command = self.plot)
        self.delta_x_spinbox.grid(row = 3, column = 1)
        
        self.delta_y_label = ttk.Label(master, text = "Delta Y", font = self.normal_font)
        self.delta_y_label.grid(row = 4, column = 0, sticky=W)
        
        self.delta_y_spinbox = Spinbox(master, from_=0, to=2, increment = 0.05, font = self.normal_font, width = 4, command = self.plot)
        self.delta_y_spinbox.grid(row = 4, column = 1)
        
#         self.plot_button = Button(master, text = "Plotten", font = self.normal_font, command = self.plot, width = 10)
#         self.plot_button.grid(row = 3, column = 2, columnspan = 1)
        
        
        
        self.sample_thickness_label = ttk.Label(master, text = "Probendicke [mm]", font = self.normal_font)
        self.sample_thickness_label.grid(row = 5, column = 0, sticky=W)
        
        self.sample_thickness_entry = ttk.Entry(master, font = self.normal_font, width = 5)
        self.sample_thickness_entry.grid(row = 5, column = 1)
        
        self.calculate_button = Button(master, text = "Berechnen", font = self.normal_font, command = self.calculate, width = 10)
        self.calculate_button.grid(row = 6, column = 1, columnspan = 1)
        
        ##########################################################################################################

        '''
        Speichern
        '''
        self.save_label = ttk.Label(master, text = "Auswertung Speichern", font = self.big_font)
        self.save_label.grid(row = 7, rowspan = 2, columnspan = 4, sticky=W)
        
        self.sample_name_label = ttk.Label(master, text = "Probenname", font = self.normal_font)
        self.sample_name_label.grid(row = 9, sticky=W)
        
        self.sample_name_entry = ttk.Entry(master, font = self.normal_font)
        self.sample_name_entry.grid(row = 9, column = 1, columnspan = 3)
        
        self.comment_label = ttk.Label(master, text = "Kommentar", font = self.normal_font)
        self.comment_label.grid(row = 10, sticky=W)
        
        self.comment_entry = ttk.Entry(master, font = self.normal_font)
        self.comment_entry.grid(row = 10, column = 1, columnspan = 3)
        
        self.save_button = Button(master, text = "Speichern", font = self.normal_font, command = self.save, width = 10)
        self.save_button.grid(row = 12, column = 1, columnspan = 2, sticky=W)
        
        
        ##############################################################################################################
        
        
        '''
        Analyse
        '''
        
        self.number_max_label = ttk.Label(master, text = "Anzahl Maxima:", font = self.normal_font)
        self.number_max_label.grid(row = 9, column = 6, sticky=W)
        
        self.number_max_int_label = ttk.Label(master, textvariable = self.number_max_string, font = self.normal_font)
        self.number_max_int_label.grid(row = 9, column = 7)
        
        self.max_max_label = ttk.Label(master, text = "Median [N]:", font = self.normal_font)
        self.max_max_label.grid(row = 10, column = 6, sticky=W)
        
        self.max_max_int_label = ttk.Label(master, textvariable = self.median_string, font = self.normal_font)
        self.max_max_int_label.grid(row = 10, column = 7)
        
        self.min_max_label = ttk.Label(master, text = u"Weiterreißwiderstand [N/mm]:", font = self.normal_font)
        self.min_max_label.grid(row = 11, column = 6, sticky=W)
        
        self.min_max_int_label = ttk.Label(master, textvariable = self.w_string, font = self.normal_font)
        self.min_max_int_label.grid(row = 11, column = 7)
        
        self.min_max_label = ttk.Label(master, text = u"Spannweite [mm]:", font = self.normal_font)
        self.min_max_label.grid(row = 12, column = 6, sticky=W)
        
        self.min_max_int_label = ttk.Label(master, textvariable = self.distance_string, font = self.normal_font)
        self.min_max_int_label.grid(row = 12, column = 7)
        
        self.method_label = ttk.Label(master, text="Methode:", font = self.normal_font)
        self.method_label.grid(row = 13, column = 6, sticky=W)
        
        self.method_method_label = ttk.Label(master, textvariable = self.method_string, font = self.normal_font)
        self.method_method_label.grid(row = 13, column = 7)
        
        
        ##########################################################################################################
        
        '''
        Canvas
        '''
        
        
        # Create a canvas
        self.w, self.h = 800, 500
        self.canvas = Canvas(master, width=self.w, height=self.h)
        self.canvas.grid(row = 0, column = 5, columnspan = 5, rowspan = 9)
        
        
        '''
        Funktionen
        '''




    def plot(self):
        
        try:
            #Maxima finden
            self._max, self._min = self.peakdetect(self.Y, self.X, float(self.delta_x_spinbox.get()), float(self.delta_y_spinbox.get()))
            
            #Maxima in Array schreiben
            self.xm = [p[0] for p in self._max]
            self.ym = [p[1] for p in self._max]
            
            #Maxima verarbeiten
            self.maxima = self.ym
            self.maxima_x = self.xm
            self.number_max = len(self._max)
            self.number_max_string.set(str(self.number_max))
            
            self.max_max = max(self.ym)
            self.max_max_string.set(str(self.max_max))
            
            self.min_max = min(self.ym)
            self.min_max_string.set(str(self.min_max))
            
            #Graph Plotten
            self.fig = plt.Figure(figsize=(8, 5), dpi=100)
            self.ax = self.fig.add_subplot(111)
            self.ax.plot(self.X, self.Y)
            self.ax.plot(self.xm, self.ym, 'ro', markersize = 10)
            #self.ax.axvline(x=10, ymin = 0, ymax = 1, linewidth = 2, color = 'g')
            self.ax.axis('auto')
            self.ax.set_xlabel('Weg [mm]')
            self.ax.set_ylabel('Kraft [N]')
            self.fig_photo = self.draw_figure(self.canvas, self.fig, loc=(0, 0))
            
            #Methode Anzeigen
            if 1 < self.number_max <= 5 :
                self.method_string.set('Median')
            elif self.number_max < 2:
                self.method_string.set('Maximum')
            else:
                self.method_string.set('80% Median')
            
        except:
            tkMessageBox.showwarning('Fehler bei der Berechnung!', 'Bitte Eingaben prüfen.')
    
    def calculate(self):
        if self.sample_thickness_entry.get() == '':
            tkMessageBox.showwarning('Keine Probendicke eingetragen!', 'Bitte Probendicke zur Berechnung eintragen.')

        else:
            if self.number_max <= 5:
                self.median_calculation()
            else:
                self.percent_calculation()
            
    def percent_calculation(self):
        #Berechnung 80 Prozent von #Maxima
        n = int(round(self.number_max*0.8))
        delta = self.number_max - n
       
        #Entfernen der ersten und zweiten 10 Prozent
        del self.maxima[0:int(round(delta/2))]
        del self.maxima[len(self.maxima)-int(round(delta-int(round(delta/2)))):len(self.maxima)]
        del self.maxima_x[0:int(round(delta/2))]
        del self.maxima_x[len(self.maxima_x)-int(round(delta-int(round(delta/2)))):len(self.maxima_x)]
        
        #Berechnung des Weiterreisswiderstands
        try:
            d = float(self.sample_thickness_entry.get()) #Auslesen der Probendicke
            self.median = np.median(self.maxima) #Berechnung des Medians
            self.w = self.median/d
            self.median_string.set(str(self.median))
            self.w_string.set(str(self.w))
            
            #Berechnung der Spannweite
            self.distance = self.maxima_x[len(self.maxima_x)-1]-self.maxima_x[0]
            self.distance_string.set(str(self.distance))
        except:
            tkMessageBox.showwarning(u'Probendicke hat falsche Formatierung!', u'Bitte Probendicke in der Form Z.ZZ eingeben (Z=Zahl).')
        
        
        
           
    def median_calculation(self):
        #Berechnung des Weiterreisswiderstands
        try:
            d = float(self.sample_thickness_entry.get()) #Auslesen der Probendicke
            
            self.median = np.median(self.maxima) #Berechnung des Medians
            self.w = self.median/d
            self.median_string.set(str(self.median))
            self.w_string.set(str(self.w))
            
            #Berechnung der Spannweite
            self.distance = self.maxima_x[len(self.maxima_x)-1]-self.maxima_x[0]
            self.distance_string.set(str(self.distance))
        except:
            tkMessageBox.showwarning(u'Probendicke hat falsche Formatierung!', u'Bitte Probendicke in der Form Z.ZZ eingeben (Z=Zahl).')
            
        
    
    def save(self):
        #Speichern der Auswertung im Projekt
        if self.project_file != '' and self.sample_name_entry.get() != '':
            maxima_string = ''
            for maximum in self.maxima:
                maxima_string += str(maximum)+'\t'
            print(maxima_string)
            self.project_file_write = open(self.project_file, 'a')
            self.project_file_write.write('\n'+self.sample_name_entry.get()+'\t'+str(self.number_max)+'\t'+str(self.median)+'\t'+self.sample_thickness_entry.get()+'\t'+str(self.w)+'\t'+str(self.distance)+'\t'+self.method_string.get()+'\t'+self.comment_entry.get()+'\t'+maxima_string)
            self.project_file_write.close()
        elif self.project_file == '':
            tkMessageBox.showwarning(u'Keine Datei zum Speichern geöffnet!', u'Bitte Datei zum Speichern öffnen oder neue Datei erstellen.')
        elif self.sample_name_entry.get() == '':
            tkMessageBox.showwarning(u'Keine Probenname eingetragen!', u'Bitte Probenname eintragen.')

    def new_file(self):
        #Neues Projekt erstellen
        self.project_file = tkFileDialog.asksaveasfilename(**self.file_opt2)
        self.project_file_write = open(self.project_file, 'a')
        self.project_file_write.write('Probenname\tNMax\tMedian\tProbendicke\tWeiterreisswiderstand\tSpannweite\tMethode\tKommentar\tMaxima(80%)')
        self.project_file_write.close()
    
    def open_file(self):
        #Bestehendes Projekt öffnen
        self.project_file = tkFileDialog.askopenfilename(**self.file_opt3)
    
    def get_filepath(self):
        #Dateipfad von Messung erfragen
        self.sample_file = tkFileDialog.askopenfilename(**self.file_opt)
        self.import_data(self.sample_file)
    
    def import_data(self, loadfile):
        #Messung importieren
        self.X, self.Y = np.loadtxt(loadfile, usecols = (1,0), unpack = True)
        self.plot()
        
    def help(self):
        #Hilfeseite zeigen
        top = Toplevel()
        top.title("Hilfe")
        
        label1 = ttk.Label(top, text = u"Projekt öffnen/erstellen", font=self.normal_font)
        label1.pack()
        
        msg1 = Message(top, text=u'Über Datei -> Neu muss zu Beginn eine .txt-Datei erstellt werden. In dieser werden die Ergebnisse der Auswertung gespeichert.\n\nAlternativ kann über Datei -> Öffnen... ein bereits existierendes Projekt mit den neuen Ergebnissen erweitert werden. \n\n')
        msg1.pack()
        
        label2 = ttk.Label(top, text = u"Messung importieren und auswerten", font=self.normal_font)
        label2.pack()
        
        msg2 = Message(top, text=u'Zunächst muss über Datei -> Messung importieren die gewünschte Messung importiert werden.\n\nAnschließend werden Delta X und Delta Y so eingestellt, dass nur die gewünschten Maxima (rote Punkte im Graphen) vom Algorithmus erkannt werden.\n\nZur Berechnung des Weiterreißwiderstandes wird die Probendicke benötigt. Diese muss im entsprechenden Fenster eingetragen werden (Trennung durch . nicht durch ,  Bsp: 1.75).\n\nÜber die Schaltfläche Berechnen werden die gewünschten Werte berechnet.\n\nNachdem der Probenname und optional ein Kommentar zur Messung in die entsprechenden Fenster eingetragen wurden, lässt sich die Auswertung im zuvor gewählten Projekt abspeichern.')
        msg2.pack()
        
        button = Button(top, text="Verbergen", command=top.destroy)
        button.pack()
    
    def info(self):
        #Infoseite zeigen
        top = Toplevel()
        top.title(u"Über dieses Programm...")
        
        msg = Message(top, text=u'Dieses Programm dient zur Auswertung von Messungen für die Bestimmung des Weiterreißwiderstands nach DIN ISO 6133:2004-05\n\nZur Detektion der Maxima dient ein Algorithmus aus MATLAB (http://billauer.co.il/peakdet.html) verwendet, welcher nach Python übersetzt wurden.\n\nDas Programm entscheidet je nach Anzahl der Maxima selbst, welche Vorgabe für die Auswertung zu verwenden ist.\n\n\n\nErstellt von Lukas Scheffler')
        msg.pack()
        
        button = Button(top, text="Verbergen", command=top.destroy)
        button.pack()
                
    def draw_figure(self, canvas, figure, loc=(0, 0)):
        ''' 
        Draw a matplotlib figure onto a Tk canvas
    
        loc: location of top-left corner of figure on canvas in pixels.
    
        Inspired by matplotlib source: lib/matplotlib/backends/backend_tkagg.py
        '''
        figure_canvas_agg = FigureCanvasAgg(figure)
        figure_canvas_agg.draw()
        figure_x, figure_y, figure_w, figure_h = figure.bbox.bounds
        figure_w, figure_h = int(figure_w), int(figure_h)
        photo = PhotoImage(master=canvas, width=figure_w, height=figure_h)
    
        
        # Position: convert from top-left anchor to center anchor
        canvas.create_image(loc[0] + figure_w/2, loc[1] + figure_h/2, image=photo)
    
        # Unfortunatly, there's no accessor for the pointer to the native renderer
        tkagg.blit(photo, figure_canvas_agg.get_renderer()._renderer, colormode=2)
    
        # Return a handle which contains a reference to the photo object
        # which must be kept live or else the picture disappears
        return photo
    
    def _datacheck_peakdetect(self, x_axis, y_axis):
        if x_axis is None:
            x_axis = range(len(y_axis))
        
        if len(y_axis) != len(x_axis):
            raise (ValueError, 
                    'Input vectors y_axis and x_axis must have same length')
        
        #needs to be a numpy array
        y_axis = np.array(y_axis)
        x_axis = np.array(x_axis)
        return x_axis, y_axis
    
    def peakdetect(self, y_axis, x_axis = None, lookahead = 300, delta=0):
        """
        Converted from/based on a MATLAB script at: 
        http://billauer.co.il/peakdet.html
        
        function for detecting local maximas and minmias in a signal.
        Discovers peaks by searching for values which are surrounded by lower
        or larger values for maximas and minimas respectively
        
        keyword arguments:
        y_axis -- A list containg the signal over which to find peaks
        x_axis -- (optional) A x-axis whose values correspond to the y_axis list
            and is used in the return to specify the postion of the peaks. If
            omitted an index of the y_axis is used. (default: None)
        lookahead -- (optional) distance to look ahead from a peak candidate to
            determine if it is the actual peak (default: 200) 
            '(sample / period) / f' where '4 >= f >= 1.25' might be a good value
        delta -- (optional) this specifies a minimum difference between a peak and
            the following points, before a peak may be considered a peak. Useful
            to hinder the function from picking up false peaks towards to end of
            the signal. To work well delta should be set to delta >= RMSnoise * 5.
            (default: 0)
                delta function causes a 20% decrease in speed, when omitted
                Correctly used it can double the speed of the function
        
        return -- two lists [max_peaks, min_peaks] containing the positive and
            negative peaks respectively. Each cell of the lists contains a tupple
            of: (position, peak_value) 
            to get the average peak value do: np.mean(max_peaks, 0)[1] on the
            results to unpack one of the lists into x, y coordinates do: 
            x, y = zip(*tab)
        """
        max_peaks = []
        min_peaks = []
        dump = []   #Used to pop the first hit which almost always is false
           
        # check input data
        x_axis, y_axis = self._datacheck_peakdetect(x_axis, y_axis)
        # store data length for later use
        length = len(y_axis)
        
        
        #perform some checks
        if lookahead < 1:
            raise ValueError, "Lookahead must be '1' or above in value"
        if not (np.isscalar(delta) and delta >= 0):
            raise ValueError, "delta must be a positive number"
        
        #maxima and minima candidates are temporarily stored in
        #mx and mn respectively
        mn, mx = np.Inf, -np.Inf
        
        #Only detect peak if there is 'lookahead' amount of points after it
        for index, (x, y) in enumerate(zip(x_axis[:-lookahead], 
                                            y_axis[:-lookahead])):
            if y > mx:
                mx = y
                mxpos = x
            if y < mn:
                mn = y
                mnpos = x
            
            ####look for max####
            if y < mx-delta and mx != np.Inf:
                #Maxima peak candidate found
                #look ahead in signal to ensure that this is a peak and not jitter
                if y_axis[index:index+lookahead].max() < mx:
                    max_peaks.append([mxpos, mx])
                    dump.append(True)
                    #set algorithm to only find minima now
                    mx = np.Inf
                    mn = np.Inf
                    if index+lookahead >= length:
                        #end is within lookahead no more peaks can be found
                        break
                    continue
                #else:  #slows shit down this does
                #    mx = ahead
                #    mxpos = x_axis[np.where(y_axis[index:index+lookahead]==mx)]
            
            ####look for min####
            if y > mn+delta and mn != -np.Inf:
                #Minima peak candidate found 
                #look ahead in signal to ensure that this is a peak and not jitter
                if y_axis[index:index+lookahead].min() > mn:
                    min_peaks.append([mnpos, mn])
                    dump.append(False)
                    #set algorithm to only find maxima now
                    mn = -np.Inf
                    mx = -np.Inf
                    if index+lookahead >= length:
                        #end is within lookahead no more peaks can be found
                        break
                #else:  #slows shit down this does
                #    mn = ahead
                #    mnpos = x_axis[np.where(y_axis[index:index+lookahead]==mn)]
        
        
        #Remove the false hit on the first value of the y_axis
        try:
            if dump[0]:
                max_peaks.pop(0)
            else:
                min_peaks.pop(0)
            del dump
        except IndexError:
            #no peaks were found, should the function return empty lists?
            pass
            
        return [max_peaks, min_peaks]
Пример #8
0
class TkPictureFrame(Frame):
    def __init__(self, x, y, master=None):
        Frame.__init__(self, master)
        self.photo = None
        self.resolution = (x, y)
        #The center of the Canvas is 0, 0. Find the center so
        #we can draw the image properly.
        self.center = ( x/2, y/2)
        #Setup the canvas
        self.picture = Canvas(self, width=x, height=y)
        #Place the canvas in the Grid.
        self.picture.grid(row=0,column=0,columnspan=2)
        #Camera check button control.
        self.checkButton = Checkbutton(self, text='Camera?',\
            command=self.toggleCamera)
        #Place it on the grid.
        self.checkButton.grid(row=1,column=0)
        #Spinbox to set FPS
        self.fpsSpin = Spinbox(self, text="FPS", from_=2, to=30,\
            command=self.fpsSpinCallback)
        self.fpsSpin.grid(row=1, column=1)
        #Set framerate
        self.fpsSpinCallback()
        #To determine if the camera is running
        self.capturing = False

    def fpsSpinCallback(self):
        self.fps = int(self.fpsSpin.get())

    def changePic(self, photo):
        #Make a reference to the old photo for removal
        self.oldphoto = self.photo
        #Setup the new photo
        self.photo = photo
        #Draw the new photo over the old photo
        self.picture.create_image(self.center,image=self.photo)
        #Remove the old photo
        self.picture.delete(self.oldphoto)
        #Enable the checkbox
        self.checkButton.config(state="normal")


    def timedDisable(self, widget):
        #Disable a widget for 2 seconds.
        widget.config(state="disabled")
        time.sleep(2)
        widget.config(state="normal")

    def threadTimeDisable(self, widget):
        #Run the timed disable in a thread to avoid lockups.
        thread.start_new_thread(self.timedDisable, (widget,))

    def startCamera(self):
        #Disable the checkbox and fps spinner.
        self.checkButton.config(state="disabled")
        self.fpsSpin.config(state="disabled")
        #Start the camera
        thread.start_new_thread(self.setupCamera, self.resolution)
        self.capturing = True

    def stopCamera(self):
        #Disable the checkbox for a duration.
        self.threadTimeDisable(self.checkButton)
        #Enable the spinner.
        self.fpsSpin.config(state="normal")
        #Clear the canvas.
        self.capturing = False
        self.picture.delete("all")
        

    def toggleCamera(self):
        if self.capturing:
            self.stopCamera()    
        else:
            self.startCamera()

    def setupCamera(self, x, y):
        with picamera.PiCamera() as camera:
            camera.resolution = (x, y)
            camera.framerate = self.fps
            stream = io.BytesIO()
            for each in camera.capture_continuous(stream, format='jpeg'):
                # Truncate the stream to the current position (in case
                # prior iterations output a longer image)
                each.truncate()
                #Rewind the stream
                each.seek(0)
                #Open the image stream
                image = Image.open(each)
                photo = ImageTk.PhotoImage(image)
                #Break out of the loop if not capturing
                if not self.capturing:
                    break
                #Update the canvas
                self.changePic(photo)
                #Reset playback to the beginning for the next image.
                each.seek(0)
Пример #9
0
class Cockpit(ttkFrame):
    '''
    Remote device GUI 
    '''
    
    #TODO: 20160415 DPM - Set these values from configuration file
    #--- config
    THROTTLE_BY_USER = True
    THROTTLE_RESOLUTION = 0.1
    
    # Joystick enabled or not, if any
    JOYSTICK_ENABLED = True 

    DEFAULT_DRONE_IP = "192.168.1.130"
    DEFAULT_DRONE_PORT = 2121
    #--- end config
    

    KEY_ANG_SPEED = "ang-speed"
    KEY_ANGLES = "angles"
    KEY_ACCEL = "accel"
    
    PID_KEYS = ["P", "I", "D"]

    DIR_NONE = 0
    DIR_VERTICAL = 1
    DIR_HORIZONTAL = 2
    
    def __init__(self, parent, isDummy = False, droneIp = DEFAULT_DRONE_IP, dronePort = DEFAULT_DRONE_PORT):
        '''
        Constructor
        '''
        ttkFrame.__init__(self, parent)
        
        self._target = [0.0] * 4        
        
        self._selectedPidConstats = "--"
        self._pidConstants = {
                              Cockpit.KEY_ANG_SPEED:{
                                           "X":{
                                                "P": 0.0,
                                                "I": 0.0,
                                                "D": 0.0
                                                },
                                           "Y":{
                                                "P": 0.0,
                                                "I": 0.0,
                                                "D": 0.0
                                                },
                                           "Z":{
                                                "P": 0.0,
                                                "I": 0.0,
                                                "D": 0.0
                                                }
                                           },
                               Cockpit.KEY_ANGLES: {
                                          "X":{
                                                "P": 0.0,
                                                "I": 0.0,
                                                "D": 0.0
                                                },
                                           "Y":{
                                                "P": 0.0,
                                                "I": 0.0,
                                                "D": 0.0
                                                }
                                          },
                               Cockpit.KEY_ACCEL:{
                                           "X":{
                                                "P": 0.0,
                                                "I": 0.0,
                                                "D": 0.0
                                                },
                                           "Y":{
                                                "P": 0.0,
                                                "I": 0.0,
                                                "D": 0.0
                                                },
                                            "Z":{
                                                "P": 0.0,
                                                "I": 0.0,
                                                "D": 0.0
                                                 }
                                          }
                              }
        
        self.parent = parent

        self.initUI()

        self._controlKeysLocked = False

        if not isDummy:
            self._link = INetLink(droneIp, dronePort)
        else:
            self._link = ConsoleLink()
            
        self._link.open()

        self._updateInfoThread = Thread(target=self._updateInfo)
        self._updateInfoThreadRunning = False
        self._readingState = False

        self._start()
        
            
    def initUI(self):
        
        self.parent.title("Drone control")
        self.style = Style()
        self.style.theme_use("default")
        
        self.pack(fill=BOTH, expand=1)
        
        self.parent.bind_all("<Key>", self._keyDown)
        self.parent.bind_all("<KeyRelease>", self._keyUp)

        if system() == "Linux":
            self.parent.bind_all("<Button-4>", self._onMouseWheelUp)
            self.parent.bind_all("<Button-5>", self._onMouseWheelDown)

        else:
            #case of Windows
            self.parent.bind_all("<MouseWheel>", self._onMouseWheel)
        
        #Commands        
        commandsFrame = tkFrame(self)
        commandsFrame.grid(column=0, row=0, sticky="WE")
        
        self._started = IntVar()
        self._startedCB = Checkbutton(commandsFrame, text="On", variable=self._started, command=self._startedCBChanged)
        self._startedCB.pack(side=LEFT, padx=4)
        
#         self._integralsCB = Checkbutton(commandsFrame, text="Int.", variable=self._integralsEnabled, \
#                                         command=self._integralsCBChanged, state=DISABLED)
#         self._integralsCB.pack(side=LEFT, padx=4)
        
        self._quitButton = Button(commandsFrame, text="Quit", command=self.exit)
        self._quitButton.pack(side=LEFT, padx=2, pady=2)
        
#         self._angleLbl = Label(commandsFrame, text="Angle")
#         self._angleLbl.pack(side=LEFT, padx=4)
#         
#         self._angleEntry = Entry(commandsFrame, state=DISABLED)
#         self._angleEntry.pack(side=LEFT)
        
        #Info
        infoFrame = tkFrame(self)
        infoFrame.grid(column=1, row=1, sticky="NE", padx=4)
        
        #Throttle
        Label(infoFrame, text="Throttle").grid(column=0, row=0, sticky="WE")        
        self._throttleTexts = [StringVar(),StringVar(),StringVar(),StringVar()]
        Entry(infoFrame, textvariable=self._throttleTexts[3], state=DISABLED, width=5).grid(column=0, row=1)                
        Entry(infoFrame, textvariable=self._throttleTexts[0], state=DISABLED, width=5).grid(column=1, row=1)
        Entry(infoFrame, textvariable=self._throttleTexts[2], state=DISABLED, width=5).grid(column=0, row=2)
        Entry(infoFrame, textvariable=self._throttleTexts[1], state=DISABLED, width=5).grid(column=1, row=2)
        
        #Angles
        Label(infoFrame, text="Angles").grid(column=0, row=3, sticky="WE")        
        self._angleTexts = [StringVar(),StringVar(),StringVar()]
        for index in range(3):
            Entry(infoFrame, textvariable=self._angleTexts[index], state=DISABLED, width=5).grid(column=index, row=4)
               
        #Accels
        Label(infoFrame, text="Accels").grid(column=0, row=5, sticky="WE")
        self._accelTexts = [StringVar(),StringVar(),StringVar()]
        for index in range(3):
            Entry(infoFrame, textvariable=self._accelTexts[index], state=DISABLED, width=5).grid(column=index, row=6)
        
        #Speeds
        Label(infoFrame, text="Speeds").grid(column=0, row=7, sticky="WE")
        self._speedTexts = [StringVar(),StringVar(),StringVar()]
        for index in range(3):
            Entry(infoFrame, textvariable=self._speedTexts[index], state=DISABLED, width=5).grid(column=index, row=8)
        
        #Height
        Label(infoFrame, text="Height").grid(column=0, row=9, sticky="E")
        self._heightText = StringVar()
        Entry(infoFrame, textvariable=self._heightText, state=DISABLED, width=5).grid(column=1, row=9)
        
        #Loop rate
        Label(infoFrame, text="Loop @").grid(column=0, row=10, sticky="E")
        self._loopRateText = StringVar()
        Entry(infoFrame, textvariable=self._loopRateText, state=DISABLED, width=5).grid(column=1, row=10)
        Label(infoFrame, text="Hz").grid(column=2, row=10, sticky="W")
        
        #control
        
        controlFrame = tkFrame(self)
        controlFrame.grid(column=0, row=1, sticky="W")
        
        self._throttle = DoubleVar()
        
        if Cockpit.THROTTLE_BY_USER:

            self._thrustScale = Scale(controlFrame, orient=VERTICAL, from_=100.0, to=0.0, \
                                tickinterval=0, variable=self._throttle, resolution=Cockpit.THROTTLE_RESOLUTION, \
                                length=200, showvalue=1, \
                                state=DISABLED,
                                command=self._onThrustScaleChanged)

        else:
        
            self._thrustScale = Scale(controlFrame, orient=VERTICAL, from_=100.0, to=-100.0, \
                                tickinterval=0, variable=self._throttle, \
                                length=200, showvalue=1, \
                                state=DISABLED,
                                command=self._onThrustScaleChanged)

        self._thrustScale.bind("<Double-Button-1>", self._onThrustScaleDoubleButton1, "+")
        self._thrustScale.grid(column=0)
        
        self._shiftCanvas = Canvas(controlFrame, bg="white", height=400, width=400, \
                             relief=SUNKEN)
        self._shiftCanvas.bind("<Button-1>", self._onMouseButton1)
        #self._shiftCanvas.bind("<ButtonRelease-1>", self._onMouseButtonRelease1)
        self._shiftCanvas.bind("<B1-Motion>", self._onMouseButton1Motion)
        self._shiftCanvas.bind("<Double-Button-1>", self._onMouseDoubleButton1)

        self._shiftCanvas.bind("<Button-3>", self._onMouseButton3)
        #self._shiftCanvas.bind("<ButtonRelease-3>", self._onMouseButtonRelease3)
        self._shiftCanvas.bind("<B3-Motion>", self._onMouseButton3Motion)

        self._shiftCanvas.grid(row=0,column=1, padx=2, pady=2)
        self._shiftCanvas.create_oval(1, 1, 400, 400, outline="#ff0000")
        self._shiftCanvas.create_line(200, 2, 200, 400, fill="#ff0000")
        self._shiftCanvas.create_line(2, 200, 400, 200, fill="#ff0000")
        self._shiftMarker = self._shiftCanvas.create_oval(196, 196, 204, 204, outline="#0000ff", fill="#0000ff")
        
        self._yaw = DoubleVar()
        self._yawScale = Scale(controlFrame, orient=HORIZONTAL, from_=-100.0, to=100.0, \
                            tickinterval=0, variable=self._yaw, \
                            length=200, showvalue=1, \
                            command=self._onYawScaleChanged)
        self._yawScale.bind("<Double-Button-1>", self._onYawScaleDoubleButton1, "+")
        self._yawScale.grid(row=1, column=1)
        
        self._controlKeyActive = False
        

        #PID calibration

        pidCalibrationFrame = tkFrame(self)
        pidCalibrationFrame.grid(column=0, row=2, sticky="WE");

        self._pidSelected = StringVar()
        self._pidSelected.set("--")
        self._pidListBox = OptionMenu(pidCalibrationFrame, self._pidSelected, "--", \
                                      Cockpit.KEY_ANG_SPEED, Cockpit.KEY_ANGLES, Cockpit.KEY_ACCEL, \
                                       command=self._onPidListBoxChanged)
        self._pidListBox.pack(side=LEFT, padx=2)
        self._pidListBox.config(width=10)
        
        self._axisSelected = StringVar()
        self._axisSelected.set("--")
        self._axisListBox = OptionMenu(pidCalibrationFrame, self._axisSelected, "--", "X", "Y", "Z", \
                                       command=self._onAxisListBoxChanged)
        self._axisListBox.pack(side=LEFT, padx=2)
        self._axisListBox.config(state=DISABLED)

        Label(pidCalibrationFrame, text="P").pack(side=LEFT, padx=(14, 2))

        self._pidPString = StringVar()
        self._pidPString.set("0.00")
        self._pidPSpinbox = Spinbox(pidCalibrationFrame, width=5, from_=0.0, to=10000.0, increment=0.01, state=DISABLED, \
                                         textvariable=self._pidPString, command=self._onPidSpinboxChanged)
        self._pidPSpinbox.pack(side=LEFT, padx=2)

        Label(pidCalibrationFrame, text="I").pack(side=LEFT, padx=(14, 2))

        self._pidIString = StringVar()
        self._pidIString.set("0.00")
        self._pidISpinbox = Spinbox(pidCalibrationFrame, width=5, from_=0.0, to=10000.0, increment=0.01, state=DISABLED, \
                                         textvariable=self._pidIString, command=self._onPidSpinboxChanged)
        self._pidISpinbox.pack(side=LEFT, padx=2)
        
        Label(pidCalibrationFrame, text="D").pack(side=LEFT, padx=(14, 2))
        
        self._pidDString = StringVar()
        self._pidDString.set("0.00")
        self._pidDSpinbox = Spinbox(pidCalibrationFrame, width=5, from_=0.0, to=10000.0, increment=0.01, state=DISABLED, \
                                         textvariable=self._pidDString, command=self._onPidSpinboxChanged)
        self._pidDSpinbox.pack(side=LEFT, padx=2)
        
        #debug
        debugFrame = tkFrame(self)
        debugFrame.grid(column=0, row=3, sticky="WE")
        
        self._debugMsg = Message(debugFrame, anchor="nw", justify=LEFT, relief=SUNKEN, width=300)
        self._debugMsg.pack(fill=BOTH, expand=1)



    def _start(self):

        self._readDroneConfig()
        
        if Cockpit.JOYSTICK_ENABLED:
            self._joystickManager = JoystickManager.getInstance()
            self._joystickManager.start()
            
            joysticks = self._joystickManager.getJoysticks()
            if len(joysticks) != 0:
                self._joystick = joysticks[0]
                self._joystick.onAxisChanged += self._onJoystickAxisChanged
                self._joystick.onButtonPressed += self._onJoystickButtonPressed
            else:
                self._joystick = None     
        
        
    def _onJoystickAxisChanged(self, sender, index):
        
        if self._started.get() and sender == self._joystick:
            
            axisValue = self._joystick.getAxisValue(index) 
            
            if index == 0:
                
                self._yaw.set(axisValue)
                self._updateTarget()
            
            elif index == 1 and not Cockpit.THROTTLE_BY_USER:
            
                thrust = -axisValue
                self._throttle.set(thrust)            
                self._updateTarget()

            elif index == 2 and Cockpit.THROTTLE_BY_USER:            
            
                rowThrottle = (axisValue + 100.0)/2.0 
                if rowThrottle < 10.0:
                    throttle = rowThrottle * 6.0
                elif rowThrottle < 90.0:
                    throttle = 60.0 + ((rowThrottle - 10.0) / 8.0)
                else:
                    throttle = 70.0 + (rowThrottle - 90.0) * 3.0
                self._throttle.set(throttle)
                self._sendThrottle()
                
            elif index == 3:
                
                x = 196 + axisValue * 2                
                lastCoords = self._shiftCanvas.coords(self._shiftMarker)
                coords = (x, lastCoords[1])                 
                self._plotShiftCanvasMarker(coords)
                
            elif index == 4:
                
                y = 196 + axisValue * 2 
                lastCoords = self._shiftCanvas.coords(self._shiftMarker)
                coords = (lastCoords[0], y)                 
                self._plotShiftCanvasMarker(coords)


    def _onJoystickButtonPressed(self, sender, index):
        
        if sender == self._joystick and index == 7:
            
            if self._started.get() == 0:
                self._startedCB.select()
            else:
                self._startedCB.deselect()
                
            # Tkinter's widgets seem not to be calling the event-handler
            # when they are changed programmatically. Therefore, the 
            # even-handler is called explicitly here.
            self._startedCBChanged()
        
    
    def exit(self):
        
        self._link.send({"key": "close", "data": None})
        
        self._stopUpdateInfoThread()
        
        self._link.close()

        if Cockpit.JOYSTICK_ENABLED:
            self._joystickManager.stop()
        
        self.quit()


    def _updateTarget(self):
        
        markerCoords = self._shiftCanvas.coords(self._shiftMarker)
        coords = ((markerCoords[0] + markerCoords[2]) / 2, (markerCoords[1] + markerCoords[3]) / 2)
        
        self._target[0] = float(coords[1] - 200) / 2.0 # X-axis angle / X-axis acceleration
        self._target[1] = float(coords[0] - 200) / 2.0 # Y-axis angle / Y-axis acceleration
        #Remote control uses clockwise angle, but the drone's referece system uses counter-clockwise angle
        self._target[2] = -self._yaw.get() # Z-axis angular speed
        
        # Z-axis acceleration (thrust). Only when the motor throttle is not controlled by user directly
        if Cockpit.THROTTLE_BY_USER:
            self._target[3] = 0.0
        else:        
            self._target[3] = self._throttle.get()
        
        self._sendTarget() 
    
        
    def _keyDown(self, event):

        if event.keysym == "Escape":            
            self._throttle.set(0)
            self._started.set(0)
            self._thrustScale.config(state=DISABLED)
            self._stopUpdateInfoThread()
            self._sendIsStarted()
            
        elif event.keysym.startswith("Control"):            
            self._controlKeyActive = True
            
        elif not self._controlKeysLocked and self._controlKeyActive:
            
            if event.keysym == "Up":
                self._thrustScaleUp()
                
            elif event.keysym == "Down":
                self._thrustScaleDown()
                
            elif event.keysym == "Left":
                self._yawLeft()
                
            elif event.keysym == "Right":
                self._yawRight()
                
            elif event.keysym == "space":
                self._yawReset()
                if not Cockpit.THROTTLE_BY_USER:
                    self._thrustReset()
                
        elif not self._controlKeysLocked and not self._controlKeyActive:
            
            if event.keysym == "Up":
                self._moveShiftCanvasMarker((0,-5))
                
            elif event.keysym == "Down":
                self._moveShiftCanvasMarker((0,5))
                
            elif event.keysym == "Left":
                self._moveShiftCanvasMarker((-5,0))
                
            elif event.keysym == "Right":
                self._moveShiftCanvasMarker((5,0))
                
            elif event.keysym == "space":
                self._resetShiftCanvasMarker()                
    
    
    def _keyUp(self, eventArgs):
        
        if eventArgs.keysym.startswith("Control"):
            self._controlKeyActive = False
            
    
    def _onMouseButton1(self, eventArgs):

        self._lastMouseCoords = (eventArgs.x, eventArgs.y)

        
    def _onMouseButtonRelease1(self, eventArgs):

        self._shiftCanvas.coords(self._shiftMarker, 196, 196, 204, 204)

    
    def _limitCoordsToSize(self, coords, size, width):
        
        maxSize = size-(width/2.0)
        minSize = -(width/2.0)
        
        if coords[0] > maxSize:
            x = maxSize
        
        elif coords[0] < minSize:
            x = minSize
            
        else:
            x = coords[0]
            
            
        if coords[1] > maxSize:
            y = maxSize
            
        elif coords[1] < minSize:
            y = minSize
            
        else:
            y = coords[1]
            
        
        return (x,y)
    
    
    def _plotShiftCanvasMarker(self, coords):
        
        coords = self._limitCoordsToSize(coords, 400, 8)
        self._shiftCanvas.coords(self._shiftMarker, coords[0], coords[1], coords[0] + 8, coords[1] + 8)
        self._updateTarget()

    
    def _moveShiftCanvasMarker(self, shift):

        lastCoords = self._shiftCanvas.coords(self._shiftMarker)
        newCoords = (lastCoords[0] + shift[0], lastCoords[1] + shift[1])        
        self._plotShiftCanvasMarker(newCoords)
    
    
    def _resetShiftCanvasMarker(self):
    
        self._shiftCanvas.coords(self._shiftMarker, 196, 196, 204, 204)
        self._updateTarget()
        
    
    def _onMouseButton1Motion(self, eventArgs):

        deltaCoords = (eventArgs.x - self._lastMouseCoords[0], eventArgs.y - self._lastMouseCoords[1])
        self._moveShiftCanvasMarker(deltaCoords)
        self._lastMouseCoords = (eventArgs.x, eventArgs.y)
  
      
    def _onMouseDoubleButton1(self, eventArgs):
        
        self._resetShiftCanvasMarker()        
            

    def _onMouseButton3(self, eventArgs):

        self._lastMouseCoords = (eventArgs.x, eventArgs.y)
        self._mouseDirection = Cockpit.DIR_NONE

        
    def _onMouseButtonRelease3(self, eventArgs):

        self._shiftCanvas.coords(self._shiftMarker, 196, 196, 204, 204)

        
    def _onMouseButton3Motion(self, eventArgs):

        deltaCoords = (eventArgs.x - self._lastMouseCoords[0], eventArgs.y - self._lastMouseCoords[1])

        if self._mouseDirection == Cockpit.DIR_NONE:
            if abs(deltaCoords[0]) > abs(deltaCoords[1]):
                self._mouseDirection = Cockpit.DIR_HORIZONTAL
            else:
                self._mouseDirection = Cockpit.DIR_VERTICAL

        if self._mouseDirection == Cockpit.DIR_HORIZONTAL:
            deltaCoords = (deltaCoords[0], 0)
        else:
            deltaCoords = (0, deltaCoords[1])

        self._moveShiftCanvasMarker(deltaCoords)
        self._lastMouseCoords = (eventArgs.x, eventArgs.y)
        
    
    def _thrustScaleUp(self):

        #TODO: 20160526 DPM: El valor de incremento de aceleración (1.0) puede ser muy alto
        if self._started.get(): 
            newValue = self._thrustScale.get() \
                + (Cockpit.THROTTLE_RESOLUTION if Cockpit.THROTTLE_BY_USER else 1.0)
            self._thrustScale.set(newValue)
            
            self._updateTarget()
    
    
    def _thrustScaleDown(self):
        
        #TODO: 20160526 DPM: El valor de decremento de aceleración (1.0) puede ser muy alto
        if self._started.get():
            newValue = self._thrustScale.get() \
                - (Cockpit.THROTTLE_RESOLUTION if Cockpit.THROTTLE_BY_USER else 1.0)
            self._thrustScale.set(newValue)
            
            self._updateTarget()
            
    
    def _thrustReset(self):
        
        if self._started.get():
            self._thrustScale.set(0.0)
            
            self._updateTarget()
            
            
    def _onThrustScaleDoubleButton1(self, eventArgs):
        
        self._thrustReset()
        
        return "break"
        
    
    def _yawRight(self):
        
        newValue = self._yaw.get() + 1
        self._yaw.set(newValue)
        self._updateTarget()
            

    def _yawLeft(self):
        
        newValue = self._yaw.get() - 1
        self._yaw.set(newValue)
        self._updateTarget()
        
        
    def _yawReset(self):
        
        self._yaw.set(0)
        self._updateTarget()
        
        
    def _onMouseWheelUp(self, eventArgs):
        
        if not self._controlKeyActive:
            self._thrustScaleUp()
            
        else:
            self._yawRight()
            

    def _onMouseWheelDown(self, eventArgs):

        if not self._controlKeyActive:
            self._thrustScaleDown()
            
        else:
            self._yawLeft()
    

    def _onMouseWheel(self, eventArgs):

        factor = eventArgs.delta/(1200.0 if Cockpit.THROTTLE_BY_USER and not self._controlKeyActive else 120.0)

        if not self._controlKeyActive:
        
            if self._started.get():
                newValue = self._thrustScale.get() + factor 
                self._thrustScale.set(newValue)
                
                self._updateTarget()
        else:
            newValue = self._yaw.get() + factor
            self._yaw.set(newValue)
            self._updateTarget()

    
    def _onYawScaleChanged(self, eventArgs):
        
        self._updateTarget()
    
    
    def _onYawScaleDoubleButton1(self, eventArgs):
        
        self._yawReset()
        
        return "break"
        
    
    def _startedCBChanged(self):
        
        if not self._started.get():
            self._throttle.set(0)
            self._thrustScale.config(state=DISABLED)            
            #self._integralsCB.config(state=DISABLED)
            self._stopUpdateInfoThread()
        else:
            self._thrustScale.config(state="normal")            
            #self._integralsCB.config(state="normal")
            self._startUpdateInfoThread()
            
        self._sendIsStarted()
     
    
#     def _integralsCBChanged(self):
#     
#         self._link.send({"key": "integrals", "data":self._integralsEnabled.get() != 0})
#             
    
     
    def _onThrustScaleChanged(self, eventArgs):
        
        if Cockpit.THROTTLE_BY_USER:
            
            self._sendThrottle()
        
        else:
        
            self._updateTarget()


    def _sendThrottle(self):
        
        self._link.send({"key": "throttle", "data": self._throttle.get()})
    

    def _sendTarget(self):
        
        self._link.send({"key": "target", "data": self._target})
        
        
    def _sendIsStarted(self):
        
        isStarted = self._started.get() != 0        
        self._link.send({"key": "is-started", "data": isStarted})
        

    def _sendPidCalibrationData(self):

        if self._pidSelected.get() != "--" and self._axisSelected.get() != "--":

            pidData = {
                "pid": self._pidSelected.get(),
                "axis": self._axisSelected.get(), 
                "p": float(self._pidPSpinbox.get()),
                "i": float(self._pidISpinbox.get()),
                "d": float(self._pidDSpinbox.get())}
        
            self._link.send({"key": "pid-calibration", "data": pidData})


    def _updatePidCalibrationData(self):

        pid = self._pidSelected.get()
        axis = self._axisSelected.get()

        if pid != "--" and axis != "--":
             
            self._pidConstants[pid][axis]["P"] = float(self._pidPSpinbox.get())
            self._pidConstants[pid][axis]["I"] = float(self._pidISpinbox.get())
            self._pidConstants[pid][axis]["D"] = float(self._pidDSpinbox.get())
            

    def _readDroneConfig(self):

        self._link.send({"key": "read-drone-config", "data": None}, self._onDroneConfigRead)


    def _readDroneState(self):
        
        if not self._readingState:
            self._readingState = True
            self._link.send({"key": "read-drone-state", "data": None}, self._onDroneStateRead)


    def _readPidConfigItem(self, message, cockpitKey, axises, configKeys):
        
        for i in range(len(axises)):
            for j in range(len(Cockpit.PID_KEYS)):
                self._pidConstants[cockpitKey][axises[i]][Cockpit.PID_KEYS[j]] = message[configKeys[j]][i]
                

    def _onDroneConfigRead(self, message):

        #TODO Show current configuration within the GUI (at least relevant settings)
        if message:
            
            #Angle-speeds
            self._readPidConfigItem(message, Cockpit.KEY_ANG_SPEED, ["X", "Y", "Z"], \
                                    [Configuration.PID_ANGLES_SPEED_KP, \
                                     Configuration.PID_ANGLES_SPEED_KI, \
                                     Configuration.PID_ANGLES_SPEED_KD])
            
            #Angles
            self._readPidConfigItem(message, Cockpit.KEY_ANGLES, ["X", "Y"], \
                                    [Configuration.PID_ANGLES_KP, \
                                     Configuration.PID_ANGLES_KI, \
                                     Configuration.PID_ANGLES_KD])
                        
            #Accels
            self._readPidConfigItem(message, Cockpit.KEY_ACCEL, ["X", "Y", "Z"], \
                                    [Configuration.PID_ACCEL_KP, \
                                     Configuration.PID_ACCEL_KI, \
                                     Configuration.PID_ACCEL_KD])
        

    def _onDroneStateRead(self, state):
        
        if state:
            
            for index in range(4):
                self._throttleTexts[index].set("{0:.3f}".format(state["_throttles"][index]))
                
            for index in range(3):
                self._accelTexts[index].set("{0:.3f}".format(state["_accels"][index]))
                self._angleTexts[index].set("{0:.3f}".format(state["_angles"][index]))
                
            currentPeriod = state["_currentPeriod"]
            if currentPeriod > 0.0:
                
                freq = 1.0/currentPeriod                
                self._loopRateText.set("{0:.3f}".format(freq))
                
            else:
                self._loopRateText.set("--")
                
        else:
            self._stopUpdateInfoThread()
            
        self._readingState = False
   

    def _onPidSpinboxChanged(self):

        self._updatePidCalibrationData()
        self._sendPidCalibrationData()

    
    def _onPidListBoxChanged(self, pid):
        
        self._axisSelected.set("--")
        
        self._pidPString.set("--")
        self._pidIString.set("--")
        self._pidDString.set("--")

        self._pidPSpinbox.config(state=DISABLED)
        self._pidISpinbox.config(state=DISABLED)
        self._pidDSpinbox.config(state=DISABLED)

        self._selectedPidConstats = pid

        if pid == "--":
            self._axisListBox.config(state=DISABLED)
            self._controlKeysLocked = False
                       
        else:
            self._axisListBox.config(state="normal")
            self._controlKeysLocked = True


    def _onAxisListBoxChanged(self, axis):
        
        if axis == "--" or (self._selectedPidConstats == Cockpit.KEY_ANGLES and axis == "Z"):
            
            self._pidPString.set("--")
            self._pidIString.set("--")
            self._pidDString.set("--")
            
            self._pidPSpinbox.config(state=DISABLED)
            self._pidISpinbox.config(state=DISABLED)
            self._pidDSpinbox.config(state=DISABLED)
            
            self._controlKeysLocked = axis != "--"
            
        else:
            
            self._pidPString.set("{:.2f}".format(self._pidConstants[self._selectedPidConstats][axis]["P"]))
            self._pidIString.set("{:.2f}".format(self._pidConstants[self._selectedPidConstats][axis]["I"]))
            self._pidDString.set("{:.2f}".format(self._pidConstants[self._selectedPidConstats][axis]["D"]))
            
            self._pidPSpinbox.config(state="normal")
            self._pidISpinbox.config(state="normal")
            self._pidDSpinbox.config(state="normal")
            
            self._controlKeysLocked = True

            
    def _updateInfo(self):
        
        while self._updateInfoThreadRunning:
            
            self._readDroneState()
            
            time.sleep(1.0)
            

    def _startUpdateInfoThread(self):
        
        self._updateInfoThreadRunning = True
        if not self._updateInfoThread.isAlive():                
            self._updateInfoThread.start()
        
            
    def _stopUpdateInfoThread(self):
        
        self._updateInfoThreadRunning = False
        if self._updateInfoThread.isAlive():
            self._updateInfoThread.join()
Пример #10
0
class TTTUI(object):

    default_ply = 6
    neither_color = '#%02x%02x%02x' % (255, 255, 255)  # white
    player_color = '#%02x%02x%02x' % (62, 188, 0)  # green
    computer_color = '#%02x%02x%02x' % (192, 35, 3)  # red
    win_color = '#%02x%02x%02x' % (25, 111, 254)  # blue

    def __init__(self):
        # TTT related
        self.ttt = Board(ply=9)
        self.human_first = True

        # UI related
        self.root = Tk()
        self.root.resizable(0, 0)
        self.root.title("3D TTT")

        # TTT frames
        self.ttt_frames = [Frame(self.root) for x in range(3)]
        for i in range(3):
            self.ttt_frames[i].grid(row=0, column=i)
        self.button_pos = dict()
        self._init_board()

        # control frame
        self.control_frame = Frame(self.root, padx=5, pady=5)
        self.control_frame.grid(row=1, column=1)
        self.new_game_btn = Button(self.control_frame, text='New Game', \
                command=lambda: self.reset())
        self.new_game_btn.pack(side=LEFT, fill=BOTH, expand=True)
        self.toggle_human_first_btn = Button(self.control_frame, \
                text='Human First', command=lambda: self.toggle_human_first())
        self.toggle_human_first_btn.pack(side=RIGHT, fill=BOTH, expand=True)
        self.ply_box = Spinbox(self.control_frame, from_=1, to=20, \
                textvariable=self.ttt.difficulty, command=lambda: self.reset())
        self.ply_box.pack(side=RIGHT, fill=BOTH, expand=True)

        # start UI
        self.update_pieces()
        self.start()
        self.root.mainloop()

    def toggle_human_first(self):
        self.human_first = not self.human_first
        self.toggle_human_first_btn.config(text='Human First' if \
                self.human_first else 'Computer First')
        self.reset()

    def _find_button(self, frame, r, c):
        for child in frame.children.values():
            info = child.grid_info()
            if info['row'] == r and info['column'] == c:
                return child
        return None

    def update_pieces(self):
        player_pieces = self.ttt.get_moves(self.ttt.human)
        computer_pieces = self.ttt.get_moves(self.ttt.ai)

        cnt = 0
        for b, board in enumerate(self.ttt.board):
            for r, row in enumerate(board):
                for c, col in enumerate(row):
                    color = self.neither_color
                    text = '-'
                    occupied = False
                    if cnt in player_pieces:
                        color = self.player_color
                        text = self.ttt.human
                    if cnt in computer_pieces:
                        color = self.computer_color
                        text = self.ttt.ai
                    if self.ttt.complete and cnt in self.ttt.winning_combo:
                        color = self.win_color
                    btn = self.button_pos[cnt]
                    btn.config(text=text, bg=color, state=DISABLED if \
                            occupied else NORMAL)
                    cnt += 1

    def place_human(self, position):
        if position in self.ttt.allowed_moves and not self.ttt.complete:
            self.ttt.move(position, self.ttt.human)
            self.ttt.human_turn = False
            self.update_pieces()
            self.place_computer()

    def place_computer(self):
        if not self.ttt.complete:
            self.ttt.computers_move()
            self.update_pieces()

    def reset(self):
        self.ttt.reset()
        self.ttt.difficulty = self.default_ply if not \
                self.ply_box.get().isdigit() else int(self.ply_box.get())
        self.ttt.human_turn = self.human_first
        self.update_pieces()
        self.start()

    def _init_board(self):
        cnt = 0
        for b, board in enumerate(self.ttt.board):
            for x, row in enumerate(board):
                for y, cell in enumerate(row):
                    padding = (0, 0)
                    if y == 2 and b != 2:
                        padding = (0, 12)
                    btn = Button(self.ttt_frames[b], width=8, height=4, \
                            command=lambda x=cell: self.place_human(x))
                    btn.grid(row=x, column=y, padx=padding)
                    self.button_pos[cnt] = btn
                    cnt += 1

    def start(self):
        if not self.ttt.human_turn:
            self.place_computer()
Пример #11
0
class Cockpit(ttkFrame):
    '''
    Remote controller GUI 
    '''
    
    KEY_ANG_SPEED = "ang-speed"
    KEY_ANGLES = "angles"
    KEY_ACCEL = "accel"
    
    PID_KEYS = ["P", "I", "D"]

    DEFAULT_DRONE_IP = "192.168.1.130"
    DEFAULT_DRONE_PORT = 2121

    DIR_NONE = 0
    DIR_VERTICAL = 1
    DIR_HORIZONTAL = 2
    
    MAX_ACCEL = 10.0 #TODO angles. Replace by m/s²
    MAX_ACCEL_Z = 0.1 #m/s²
    MAX_ANGLE_SPEED = 50.0 #º/s

    def __init__(self, parent, isDummy = False, droneIp = DEFAULT_DRONE_IP, dronePort = DEFAULT_DRONE_PORT):
        '''
        Constructor
        '''
        ttkFrame.__init__(self, parent)
        
        self._started = IntVar()
        self._integralsEnabled = IntVar()
        self._target = [0.0] * 4        
        
        self._selectedPidConstats = "--"
        self._pidConstants = {
                              Cockpit.KEY_ANG_SPEED:{
                                           "X":{
                                                "P": 0.0,
                                                "I": 0.0,
                                                "D": 0.0
                                                },
                                           "Y":{
                                                "P": 0.0,
                                                "I": 0.0,
                                                "D": 0.0
                                                },
                                           "Z":{
                                                "P": 0.0,
                                                "I": 0.0,
                                                "D": 0.0
                                                }
                                           },
                               Cockpit.KEY_ANGLES: {
                                          "X":{
                                                "P": 0.0,
                                                "I": 0.0,
                                                "D": 0.0
                                                },
                                           "Y":{
                                                "P": 0.0,
                                                "I": 0.0,
                                                "D": 0.0
                                                }
                                          },
                               Cockpit.KEY_ACCEL:{
                                           "X":{
                                                "P": 0.0,
                                                "I": 0.0,
                                                "D": 0.0
                                                },
                                           "Y":{
                                                "P": 0.0,
                                                "I": 0.0,
                                                "D": 0.0
                                                },
                                            "Z":{
                                                "P": 0.0,
                                                "I": 0.0,
                                                "D": 0.0
                                                 }
                                          }
                              }
        
        self.parent = parent

        self.initUI()

        self._controlKeysLocked = False

        if not isDummy:
            self._link = INetLink(droneIp, dronePort)
        else:
            self._link = ConsoleLink()
            
        self._link.open()

        self._updateInfoThread = Thread(target=self._updateInfo)
        self._updateInfoThreadRunning = False
        self._readingState = False

        self._start()
        
            
    def initUI(self):
        
        self.parent.title("Drone control")
        self.style = Style()
        self.style.theme_use("default")
        
        self.pack(fill=BOTH, expand=1)
        
        self.parent.bind_all("<Key>", self._keyDown)
        self.parent.bind_all("<KeyRelease>", self._keyUp)

        if system() == "Linux":
            self.parent.bind_all("<Button-4>", self._onMouseWheelUp)
            self.parent.bind_all("<Button-5>", self._onMouseWheelDown)

        else:
            #case of Windows
            self.parent.bind_all("<MouseWheel>", self._onMouseWheel)
        
        #Commands        
        commandsFrame = tkFrame(self)
        commandsFrame.grid(column=0, row=0, sticky="WE")
        
        self._startedCB = Checkbutton(commandsFrame, text="On", variable=self._started, command=self._startedCBChanged)
        self._startedCB.pack(side=LEFT, padx=4)
        
        self._integralsCB = Checkbutton(commandsFrame, text="Int.", variable=self._integralsEnabled, \
                                        command=self._integralsCBChanged, state=DISABLED)
        self._integralsCB.pack(side=LEFT, padx=4)
        
        self._quitButton = Button(commandsFrame, text="Quit", command=self.exit)
        self._quitButton.pack(side=LEFT, padx=2, pady=2)
        
#         self._angleLbl = Label(commandsFrame, text="Angle")
#         self._angleLbl.pack(side=LEFT, padx=4)
#         
#         self._angleEntry = Entry(commandsFrame, state=DISABLED)
#         self._angleEntry.pack(side=LEFT)
        
        #Info
        infoFrame = tkFrame(self)
        infoFrame.grid(column=1, row=1, sticky="E", padx=4)
        
        #Throttle
        Label(infoFrame, text="Throttle").grid(column=0, row=0, sticky="WE")        
        self._throttleTexts = [StringVar(),StringVar(),StringVar(),StringVar()]
        Entry(infoFrame, textvariable=self._throttleTexts[3], state=DISABLED, width=5).grid(column=0, row=1)                
        Entry(infoFrame, textvariable=self._throttleTexts[0], state=DISABLED, width=5).grid(column=1, row=1)
        Entry(infoFrame, textvariable=self._throttleTexts[2], state=DISABLED, width=5).grid(column=0, row=2)
        Entry(infoFrame, textvariable=self._throttleTexts[1], state=DISABLED, width=5).grid(column=1, row=2)
        
        #Angles
        Label(infoFrame, text="Angles").grid(column=0, row=3, sticky="WE")        
        self._angleTexts = [StringVar(),StringVar(),StringVar()]
        for index in range(3):
            Entry(infoFrame, textvariable=self._angleTexts[index], state=DISABLED, width=5).grid(column=index, row=4)
               
        #Accels
        Label(infoFrame, text="Accels").grid(column=0, row=5, sticky="WE")
        self._accelTexts = [StringVar(),StringVar(),StringVar()]
        for index in range(3):
            Entry(infoFrame, textvariable=self._accelTexts[index], state=DISABLED, width=5).grid(column=index, row=6)
        
        #Speeds
        Label(infoFrame, text="Speeds").grid(column=0, row=7, sticky="WE")
        self._speedTexts = [StringVar(),StringVar(),StringVar()]
        for index in range(3):
            Entry(infoFrame, textvariable=self._speedTexts[index], state=DISABLED, width=5).grid(column=index, row=8)
        
        #Height
        Label(infoFrame, text="Height").grid(column=0, row=9, sticky="W")
        self._heightText = StringVar()
        Entry(infoFrame, state=DISABLED, width=5).grid(column=1, row=9)
        
        #control
        
        controlFrame = tkFrame(self)
        controlFrame.grid(column=0, row=1, sticky="W")
        
        self._throttle = DoubleVar()
        self._thrustScale = Scale(controlFrame, orient=VERTICAL, from_=100.0, to=-100.0, \
                            tickinterval=0, variable=self._throttle, \
                            length=200, showvalue=1, \
                            state=DISABLED,
                            command=self._onThrustScaleChanged)
        self._thrustScale.bind("<Double-Button-1>", self._onThrustScaleDoubleButton1, "+")
        self._thrustScale.grid(column=0)
        
        self._shiftCanvas = Canvas(controlFrame, bg="white", height=400, width=400, \
                             relief=SUNKEN)
        self._shiftCanvas.bind("<Button-1>", self._onMouseButton1)
        #self._shiftCanvas.bind("<ButtonRelease-1>", self._onMouseButtonRelease1)
        self._shiftCanvas.bind("<B1-Motion>", self._onMouseButton1Motion)
        self._shiftCanvas.bind("<Double-Button-1>", self._onMouseDoubleButton1)

        self._shiftCanvas.bind("<Button-3>", self._onMouseButton3)
        #self._shiftCanvas.bind("<ButtonRelease-3>", self._onMouseButtonRelease3)
        self._shiftCanvas.bind("<B3-Motion>", self._onMouseButton3Motion)

        self._shiftCanvas.grid(row=0,column=1, padx=2, pady=2)
        self._shiftCanvas.create_oval(2, 2, 400, 400, outline="#ff0000")
        self._shiftCanvas.create_line(201, 2, 201, 400, fill="#ff0000")
        self._shiftCanvas.create_line(2, 201, 400, 201, fill="#ff0000")
        self._shiftMarker = self._shiftCanvas.create_oval(197, 197, 205, 205, outline="#0000ff", fill="#0000ff")
        
        self._yaw = DoubleVar()
        self._yawScale = Scale(controlFrame, orient=HORIZONTAL, from_=-100.0, to=100.0, \
                            tickinterval=0, variable=self._yaw, \
                            length=200, showvalue=1, \
                            command=self._onYawScaleChanged)
        self._yawScale.bind("<Double-Button-1>", self._onYawScaleDoubleButton1, "+")
        self._yawScale.grid(row=1, column=1)
        
        self._controlKeyActive = False
        

        #PID calibration

        pidCalibrationFrame = tkFrame(self)
        pidCalibrationFrame.grid(column=0, row=2, sticky="WE");

        self._pidSelected = StringVar()
        self._pidSelected.set("--")
        self._pidListBox = OptionMenu(pidCalibrationFrame, self._pidSelected, "--", \
                                      Cockpit.KEY_ANG_SPEED, Cockpit.KEY_ANGLES, Cockpit.KEY_ACCEL, \
                                       command=self._onPidListBoxChanged)
        self._pidListBox.pack(side=LEFT, padx=2)
        self._pidListBox.config(width=10)
        
        self._axisSelected = StringVar()
        self._axisSelected.set("--")
        self._axisListBox = OptionMenu(pidCalibrationFrame, self._axisSelected, "--", "X", "Y", "Z", \
                                       command=self._onAxisListBoxChanged)
        self._axisListBox.pack(side=LEFT, padx=2)
        self._axisListBox.config(state=DISABLED)

        Label(pidCalibrationFrame, text="P").pack(side=LEFT, padx=(14, 2))

        self._pidPString = StringVar()
        self._pidPString.set("0.00")
        self._pidPSpinbox = Spinbox(pidCalibrationFrame, width=5, from_=0.0, to=100.0, increment=0.01, state=DISABLED, \
                                         textvariable=self._pidPString, command=self._onPidSpinboxChanged)
        self._pidPSpinbox.pack(side=LEFT, padx=2)

        Label(pidCalibrationFrame, text="I").pack(side=LEFT, padx=(14, 2))

        self._pidIString = StringVar()
        self._pidIString.set("0.00")
        self._pidISpinbox = Spinbox(pidCalibrationFrame, width=5, from_=0.0, to=100.0, increment=0.01, state=DISABLED, \
                                         textvariable=self._pidIString, command=self._onPidSpinboxChanged)
        self._pidISpinbox.pack(side=LEFT, padx=2)
        
        Label(pidCalibrationFrame, text="D").pack(side=LEFT, padx=(14, 2))
        
        self._pidDString = StringVar()
        self._pidDString.set("0.00")
        self._pidDSpinbox = Spinbox(pidCalibrationFrame, width=5, from_=0.0, to=100.0, increment=0.01, state=DISABLED, \
                                         textvariable=self._pidDString, command=self._onPidSpinboxChanged)
        self._pidDSpinbox.pack(side=LEFT, padx=2)
        
        #debug
        debugFrame = tkFrame(self)
        debugFrame.grid(column=0, row=3, sticky="WE")
        
        self._debugMsg = Message(debugFrame, anchor="nw", justify=LEFT, relief=SUNKEN, width=300)
        self._debugMsg.pack(fill=BOTH, expand=1)



    def _start(self):

        self._readDroneConfig()
        
    
    def exit(self):
        
        self._link.send({"key": "close", "data": None})
        
        self._stopUpdateInfoThread()
        
        self._link.close()

        self.quit()


    def _updateTarget(self):
        
        markerCoords = self._shiftCanvas.coords(self._shiftMarker)
        coords = ((markerCoords[0] + markerCoords[2]) / 2, (markerCoords[1] + markerCoords[3]) / 2)
        
        self._target[1] = float(coords[0] - 201) * Cockpit.MAX_ACCEL / 200.0
        self._target[0] = float(coords[1] - 201) * Cockpit.MAX_ACCEL / 200.0      
        #Remote control uses clockwise angle, but the drone's referece system uses counter-clockwise angle
        self._target[2] = -self._yaw.get() * Cockpit.MAX_ANGLE_SPEED / 100.0
        
        self._target[3] = self._throttle.get() * Cockpit.MAX_ACCEL_Z / 100.0
        
        self._sendTarget() 
    
        
    def _keyDown(self, event):

        if event.keysym == "Escape":            
            self._throttle.set(0)
            self._started.set(0)
            self._thrustScale.config(state=DISABLED)
            self._stopUpdateInfoThread()
            self._sendIsStarted()
            
        elif event.keysym.startswith("Control"):            
            self._controlKeyActive = True
            
        elif not self._controlKeysLocked and self._controlKeyActive:
            
            if event.keysym == "Up":
                self._thrustScaleUp()
                
            elif event.keysym == "Down":
                self._thrustScaleDown()
                
            elif event.keysym == "Left":
                self._yawLeft()
                
            elif event.keysym == "Right":
                self._yawRight()
                
            elif event.keysym == "space":
                self._yawReset()
                self._thrustReset()
                
        elif not self._controlKeysLocked and not self._controlKeyActive:
            
            if event.keysym == "Up":
                self._moveShiftCanvasMarker((0,-5))
                
            elif event.keysym == "Down":
                self._moveShiftCanvasMarker((0,5))
                
            elif event.keysym == "Left":
                self._moveShiftCanvasMarker((-5,0))
                
            elif event.keysym == "Right":
                self._moveShiftCanvasMarker((5,0))
                
            elif event.keysym == "space":
                self._resetShiftCanvasMarker()                
    
    
    def _keyUp(self, eventArgs):
        
        if eventArgs.keysym.startswith("Control"):
            self._controlKeyActive = False
            
    
    def _onMouseButton1(self, eventArgs):

        self._lastMouseCoords = (eventArgs.x, eventArgs.y)

        
    def _onMouseButtonRelease1(self, eventArgs):

        self._shiftCanvas.coords(self._shiftMarker, 197, 197, 205, 205)

    
    def _limitCoordsToSize(self, coords, size):
        
        if coords[0] > size:
            x = size
        
        elif coords[0] < 0:
            x = 0
            
        else:
            x = coords[0]
            
            
        if coords[1] > size:
            y = size
            
        elif coords[1] < 0:
            y = 0
            
        else:
            y = coords[1]
            
        
        return (x,y)
    
    
    def _moveShiftCanvasMarker(self, shift):

        lastCoords = self._shiftCanvas.coords(self._shiftMarker)
        newCoords = (lastCoords[0] + shift[0], lastCoords[1] + shift[1])        
        newCoords = self._limitCoordsToSize(newCoords, 400)
    
        self._shiftCanvas.coords(self._shiftMarker, newCoords[0], newCoords[1], newCoords[0] + 8, newCoords[1] + 8)
        self._updateTarget()
    
    
    def _resetShiftCanvasMarker(self):
    
        self._shiftCanvas.coords(self._shiftMarker, 197, 197, 205, 205)
        self._updateTarget()
        
    
    def _onMouseButton1Motion(self, eventArgs):

        deltaCoords = (eventArgs.x - self._lastMouseCoords[0], eventArgs.y - self._lastMouseCoords[1])
        self._moveShiftCanvasMarker(deltaCoords)
        self._lastMouseCoords = (eventArgs.x, eventArgs.y)
  
      
    def _onMouseDoubleButton1(self, eventArgs):
        
        self._resetShiftCanvasMarker()        
            

    def _onMouseButton3(self, eventArgs):

        self._lastMouseCoords = (eventArgs.x, eventArgs.y)
        self._mouseDirection = Cockpit.DIR_NONE

        
    def _onMouseButtonRelease3(self, eventArgs):

        self._shiftCanvas.coords(self._shiftMarker, 197, 197, 205, 205)

        
    def _onMouseButton3Motion(self, eventArgs):

        deltaCoords = (eventArgs.x - self._lastMouseCoords[0], eventArgs.y - self._lastMouseCoords[1])

        if self._mouseDirection == Cockpit.DIR_NONE:
            if abs(deltaCoords[0]) > abs(deltaCoords[1]):
                self._mouseDirection = Cockpit.DIR_HORIZONTAL
            else:
                self._mouseDirection = Cockpit.DIR_VERTICAL

        if self._mouseDirection == Cockpit.DIR_HORIZONTAL:
            deltaCoords = (deltaCoords[0], 0)
        else:
            deltaCoords = (0, deltaCoords[1])

        self._moveShiftCanvasMarker(deltaCoords)
        self._lastMouseCoords = (eventArgs.x, eventArgs.y)
        
    
    def _thrustScaleUp(self):

        if self._started.get(): 
            newValue = self._thrustScale.get() + 1
            self._thrustScale.set(newValue)
            
            self._updateTarget()
    
    
    def _thrustScaleDown(self):
        
        if self._started.get():
            newValue = self._thrustScale.get() - 1
            self._thrustScale.set(newValue)
            
            self._updateTarget()
            
    
    def _thrustReset(self):
        
        if self._started.get():
            self._thrustScale.set(0.0)
            
            self._updateTarget()
            
            
    def _onThrustScaleDoubleButton1(self, eventArgs):
        
        self._thrustReset()
        
        return "break"
        
    
    def _yawRight(self):
        
        newValue = self._yaw.get() + 1
        self._yaw.set(newValue)
        self._updateTarget()
            

    def _yawLeft(self):
        
        newValue = self._yaw.get() - 1
        self._yaw.set(newValue)
        self._updateTarget()
        
        
    def _yawReset(self):
        
        self._yaw.set(0)
        self._updateTarget()
        
        
    def _onMouseWheelUp(self, eventArgs):
        
        if not self._controlKeyActive:
            self._thrustScaleUp()
            
        else:
            self._yawRight()
            

    def _onMouseWheelDown(self, eventArgs):

        if not self._controlKeyActive:
            self._thrustScaleDown()
            
        else:
            self._yawLeft()
    

    def _onMouseWheel(self, eventArgs):

        factor = int(eventArgs.delta/120)

        if not self._controlKeyActive:
        
            if self._started.get():
                newValue = self._thrustScale.get() + factor
                self._thrustScale.set(newValue)
                
                self._updateTarget()
        else:
            newValue = self._yaw.get() + factor
            self._yaw.set(newValue)
            self._updateTarget()

    
    def _onYawScaleChanged(self, eventArgs):
        
        self._updateTarget()
    
    
    def _onYawScaleDoubleButton1(self, eventArgs):
        
        self._yawReset()
        
        return "break"
        
    
    def _startedCBChanged(self):
        
        if not self._started.get():
            self._throttle.set(0)
            self._thrustScale.config(state=DISABLED)            
            self._integralsCB.config(state=DISABLED)
            self._stopUpdateInfoThread()
        else:
            self._thrustScale.config(state="normal")            
            self._integralsCB.config(state="normal")
            self._startUpdateInfoThread()
            
        self._sendIsStarted()
     
    
    def _integralsCBChanged(self):
    
        self._link.send({"key": "integrals", "data":self._integralsEnabled.get() != 0})
            
     
    def _onThrustScaleChanged(self, eventArgs):
        
        self._updateTarget()
    

    def _sendTarget(self):
        
        self._link.send({"key": "target", "data": self._target})
        
        
    def _sendIsStarted(self):
        
        isStarted = self._started.get() != 0        
        self._link.send({"key": "is-started", "data": isStarted})
        

    def _sendPidCalibrationData(self):

        if self._pidSelected.get() != "--" and self._axisSelected.get() != "--":

            pidData = {
                "pid": self._pidSelected.get(),
                "axis": self._axisSelected.get(), 
                "p": float(self._pidPSpinbox.get()),
                "i": float(self._pidISpinbox.get()),
                "d": float(self._pidDSpinbox.get())}
        
            self._link.send({"key": "pid-calibration", "data": pidData})


    def _updatePidCalibrationData(self):

        pid = self._pidSelected.get()
        axis = self._axisSelected.get()

        if pid != "--" and axis != "--":
             
            self._pidConstants[pid][axis]["P"] = float(self._pidPSpinbox.get())
            self._pidConstants[pid][axis]["I"] = float(self._pidISpinbox.get())
            self._pidConstants[pid][axis]["D"] = float(self._pidDSpinbox.get())
            

    def _readDroneConfig(self):

        self._link.send({"key": "read-drone-config", "data": None}, self._onDroneConfigRead)


    def _readDroneState(self):
        
        if not self._readingState:
            self._readingState = True
            self._link.send({"key": "read-drone-state", "data": None}, self._onDroneStateRead)


    def _readPidConfigItem(self, message, cockpitKey, axises, configKeys):
        
        for i in range(len(axises)):
            for j in range(len(Cockpit.PID_KEYS)):
                self._pidConstants[cockpitKey][axises[i]][Cockpit.PID_KEYS[j]] = message[configKeys[j]][i]
                

    def _onDroneConfigRead(self, message):

        #TODO Show current configuration within the GUI (at least relevant settings)
        if message:
            
            #Angle-speeds
            self._readPidConfigItem(message, Cockpit.KEY_ANG_SPEED, ["X", "Y", "Z"], \
                                    [Configuration.PID_ANGLES_SPEED_KP, \
                                     Configuration.PID_ANGLES_SPEED_KI, \
                                     Configuration.PID_ANGLES_SPEED_KD])
            
            #Angles
            self._readPidConfigItem(message, Cockpit.KEY_ANGLES, ["X", "Y"], \
                                    [Configuration.PID_ANGLES_KP, \
                                     Configuration.PID_ANGLES_KI, \
                                     Configuration.PID_ANGLES_KD])
                        
            #Accels
            self._readPidConfigItem(message, Cockpit.KEY_ACCEL, ["X", "Y", "Z"], \
                                    [Configuration.PID_ACCEL_KP, \
                                     Configuration.PID_ACCEL_KI, \
                                     Configuration.PID_ACCEL_KD])
        

    def _onDroneStateRead(self, state):
        
        if state:
            for index in range(4):
                self._throttleTexts[index].set("{0:.3f}".format(state["_throttles"][index]))
                
            for index in range(3):
                self._accelTexts[index].set("{0:.3f}".format(state["_accels"][index]))
                self._angleTexts[index].set("{0:.3f}".format(state["_angles"][index]))
                
        else:
            self._stopUpdateInfoThread()
            
        self._readingState = False
   

    def _onPidSpinboxChanged(self):

        self._updatePidCalibrationData()
        self._sendPidCalibrationData()

    
    def _onPidListBoxChanged(self, pid):
        
        self._axisSelected.set("--")
        
        self._pidPString.set("--")
        self._pidIString.set("--")
        self._pidDString.set("--")

        self._pidPSpinbox.config(state=DISABLED)
        self._pidISpinbox.config(state=DISABLED)
        self._pidDSpinbox.config(state=DISABLED)

        self._selectedPidConstats = pid

        if pid == "--":
            self._axisListBox.config(state=DISABLED)
            self._controlKeysLocked = False
                       
        else:
            self._axisListBox.config(state="normal")
            self._controlKeysLocked = True


    def _onAxisListBoxChanged(self, axis):
        
        if axis == "--" or (self._selectedPidConstats == Cockpit.KEY_ANGLES and axis == "Z"):
            
            self._pidPString.set("--")
            self._pidIString.set("--")
            self._pidDString.set("--")
            
            self._pidPSpinbox.config(state=DISABLED)
            self._pidISpinbox.config(state=DISABLED)
            self._pidDSpinbox.config(state=DISABLED)
            
            self._controlKeysLocked = axis != "--"
            
        else:
            
            self._pidPString.set("{:.2f}".format(self._pidConstants[self._selectedPidConstats][axis]["P"]))
            self._pidIString.set("{:.2f}".format(self._pidConstants[self._selectedPidConstats][axis]["I"]))
            self._pidDString.set("{:.2f}".format(self._pidConstants[self._selectedPidConstats][axis]["D"]))
            
            self._pidPSpinbox.config(state="normal")
            self._pidISpinbox.config(state="normal")
            self._pidDSpinbox.config(state="normal")
            
            self._controlKeysLocked = True

            
    def _updateInfo(self):
        
        while self._updateInfoThreadRunning:
            
            self._readDroneState()
            
            time.sleep(1.0)
            

    def _startUpdateInfoThread(self):
        
        self._updateInfoThreadRunning = True
        if not self._updateInfoThread.isAlive():                
            self._updateInfoThread.start()
        
            
    def _stopUpdateInfoThread(self):
        
        self._updateInfoThreadRunning = False
        if self._updateInfoThread.isAlive():
            self._updateInfoThread.join()
Пример #12
0
class Cockpit(ttkFrame):
    '''
    Remote device GUI 
    '''

    #TODO: 20160415 DPM - Set these values from configuration file
    #--- config
    THROTTLE_BY_USER = True
    THROTTLE_RESOLUTION = 0.1

    # Joystick enabled or not, if any
    JOYSTICK_ENABLED = True

    DEFAULT_DRONE_IP = "192.168.1.130"
    DEFAULT_DRONE_PORT = 2121
    #--- end config

    KEY_ANG_SPEED = "ang-speed"
    KEY_ANGLES = "angles"
    KEY_ACCEL = "accel"

    PID_KEYS = ["P", "I", "D"]

    DIR_NONE = 0
    DIR_VERTICAL = 1
    DIR_HORIZONTAL = 2

    def __init__(self,
                 parent,
                 isDummy=False,
                 droneIp=DEFAULT_DRONE_IP,
                 dronePort=DEFAULT_DRONE_PORT):
        '''
        Constructor
        '''
        ttkFrame.__init__(self, parent)

        self._target = [0.0] * 4

        self._selectedPidConstats = "--"
        self._pidConstants = {
            Cockpit.KEY_ANG_SPEED: {
                "X": {
                    "P": 0.0,
                    "I": 0.0,
                    "D": 0.0
                },
                "Y": {
                    "P": 0.0,
                    "I": 0.0,
                    "D": 0.0
                },
                "Z": {
                    "P": 0.0,
                    "I": 0.0,
                    "D": 0.0
                }
            },
            Cockpit.KEY_ANGLES: {
                "X": {
                    "P": 0.0,
                    "I": 0.0,
                    "D": 0.0
                },
                "Y": {
                    "P": 0.0,
                    "I": 0.0,
                    "D": 0.0
                }
            },
            Cockpit.KEY_ACCEL: {
                "X": {
                    "P": 0.0,
                    "I": 0.0,
                    "D": 0.0
                },
                "Y": {
                    "P": 0.0,
                    "I": 0.0,
                    "D": 0.0
                },
                "Z": {
                    "P": 0.0,
                    "I": 0.0,
                    "D": 0.0
                }
            }
        }

        self.parent = parent

        self.initUI()

        self._controlKeysLocked = False

        if not isDummy:
            self._link = INetLink(droneIp, dronePort)
        else:
            self._link = ConsoleLink()

        self._link.open()

        self._updateInfoThread = Thread(target=self._updateInfo)
        self._updateInfoThreadRunning = False
        self._readingState = False

        self._start()

    def initUI(self):

        self.parent.title("Drone control")
        self.style = Style()
        self.style.theme_use("default")

        self.pack(fill=BOTH, expand=1)

        self.parent.bind_all("<Key>", self._keyDown)
        self.parent.bind_all("<KeyRelease>", self._keyUp)

        if system() == "Linux":
            self.parent.bind_all("<Button-4>", self._onMouseWheelUp)
            self.parent.bind_all("<Button-5>", self._onMouseWheelDown)

        else:
            #case of Windows
            self.parent.bind_all("<MouseWheel>", self._onMouseWheel)

        #Commands
        commandsFrame = tkFrame(self)
        commandsFrame.grid(column=0, row=0, sticky="WE")

        self._started = IntVar()
        self._startedCB = Checkbutton(commandsFrame,
                                      text="On",
                                      variable=self._started,
                                      command=self._startedCBChanged)
        self._startedCB.pack(side=LEFT, padx=4)

        #         self._integralsCB = Checkbutton(commandsFrame, text="Int.", variable=self._integralsEnabled, \
        #                                         command=self._integralsCBChanged, state=DISABLED)
        #         self._integralsCB.pack(side=LEFT, padx=4)

        self._quitButton = Button(commandsFrame,
                                  text="Quit",
                                  command=self.exit)
        self._quitButton.pack(side=LEFT, padx=2, pady=2)

        #         self._angleLbl = Label(commandsFrame, text="Angle")
        #         self._angleLbl.pack(side=LEFT, padx=4)
        #
        #         self._angleEntry = Entry(commandsFrame, state=DISABLED)
        #         self._angleEntry.pack(side=LEFT)

        #Info
        infoFrame = tkFrame(self)
        infoFrame.grid(column=1, row=1, sticky="NE", padx=4)

        #Throttle
        Label(infoFrame, text="Throttle").grid(column=0, row=0, sticky="WE")
        self._throttleTexts = [
            StringVar(), StringVar(),
            StringVar(), StringVar()
        ]
        Entry(infoFrame,
              textvariable=self._throttleTexts[3],
              state=DISABLED,
              width=5).grid(column=0, row=1)
        Entry(infoFrame,
              textvariable=self._throttleTexts[0],
              state=DISABLED,
              width=5).grid(column=1, row=1)
        Entry(infoFrame,
              textvariable=self._throttleTexts[2],
              state=DISABLED,
              width=5).grid(column=0, row=2)
        Entry(infoFrame,
              textvariable=self._throttleTexts[1],
              state=DISABLED,
              width=5).grid(column=1, row=2)

        #Angles
        Label(infoFrame, text="Angles").grid(column=0, row=3, sticky="WE")
        self._angleTexts = [StringVar(), StringVar(), StringVar()]
        for index in range(3):
            Entry(infoFrame,
                  textvariable=self._angleTexts[index],
                  state=DISABLED,
                  width=5).grid(column=index, row=4)

        #Accels
        Label(infoFrame, text="Accels").grid(column=0, row=5, sticky="WE")
        self._accelTexts = [StringVar(), StringVar(), StringVar()]
        for index in range(3):
            Entry(infoFrame,
                  textvariable=self._accelTexts[index],
                  state=DISABLED,
                  width=5).grid(column=index, row=6)

        #Speeds
        Label(infoFrame, text="Speeds").grid(column=0, row=7, sticky="WE")
        self._speedTexts = [StringVar(), StringVar(), StringVar()]
        for index in range(3):
            Entry(infoFrame,
                  textvariable=self._speedTexts[index],
                  state=DISABLED,
                  width=5).grid(column=index, row=8)

        #Height
        Label(infoFrame, text="Height").grid(column=0, row=9, sticky="E")
        self._heightText = StringVar()
        Entry(infoFrame,
              textvariable=self._heightText,
              state=DISABLED,
              width=5).grid(column=1, row=9)

        #Loop rate
        Label(infoFrame, text="Loop @").grid(column=0, row=10, sticky="E")
        self._loopRateText = StringVar()
        Entry(infoFrame,
              textvariable=self._loopRateText,
              state=DISABLED,
              width=5).grid(column=1, row=10)
        Label(infoFrame, text="Hz").grid(column=2, row=10, sticky="W")

        #control

        controlFrame = tkFrame(self)
        controlFrame.grid(column=0, row=1, sticky="W")

        self._throttle = DoubleVar()

        if Cockpit.THROTTLE_BY_USER:

            self._thrustScale = Scale(controlFrame, orient=VERTICAL, from_=100.0, to=0.0, \
                                tickinterval=0, variable=self._throttle, resolution=Cockpit.THROTTLE_RESOLUTION, \
                                length=200, showvalue=1, \
                                state=DISABLED,
                                command=self._onThrustScaleChanged)

        else:

            self._thrustScale = Scale(controlFrame, orient=VERTICAL, from_=100.0, to=-100.0, \
                                tickinterval=0, variable=self._throttle, \
                                length=200, showvalue=1, \
                                state=DISABLED,
                                command=self._onThrustScaleChanged)

        self._thrustScale.bind("<Double-Button-1>",
                               self._onThrustScaleDoubleButton1, "+")
        self._thrustScale.grid(column=0)

        self._shiftCanvas = Canvas(controlFrame, bg="white", height=400, width=400, \
                             relief=SUNKEN)
        self._shiftCanvas.bind("<Button-1>", self._onMouseButton1)
        #self._shiftCanvas.bind("<ButtonRelease-1>", self._onMouseButtonRelease1)
        self._shiftCanvas.bind("<B1-Motion>", self._onMouseButton1Motion)
        self._shiftCanvas.bind("<Double-Button-1>", self._onMouseDoubleButton1)

        self._shiftCanvas.bind("<Button-3>", self._onMouseButton3)
        #self._shiftCanvas.bind("<ButtonRelease-3>", self._onMouseButtonRelease3)
        self._shiftCanvas.bind("<B3-Motion>", self._onMouseButton3Motion)

        self._shiftCanvas.grid(row=0, column=1, padx=2, pady=2)
        self._shiftCanvas.create_oval(1, 1, 400, 400, outline="#ff0000")
        self._shiftCanvas.create_line(200, 2, 200, 400, fill="#ff0000")
        self._shiftCanvas.create_line(2, 200, 400, 200, fill="#ff0000")
        self._shiftMarker = self._shiftCanvas.create_oval(196,
                                                          196,
                                                          204,
                                                          204,
                                                          outline="#0000ff",
                                                          fill="#0000ff")

        self._yaw = DoubleVar()
        self._yawScale = Scale(controlFrame, orient=HORIZONTAL, from_=-100.0, to=100.0, \
                            tickinterval=0, variable=self._yaw, \
                            length=200, showvalue=1, \
                            command=self._onYawScaleChanged)
        self._yawScale.bind("<Double-Button-1>", self._onYawScaleDoubleButton1,
                            "+")
        self._yawScale.grid(row=1, column=1)

        self._controlKeyActive = False

        #PID calibration

        pidCalibrationFrame = tkFrame(self)
        pidCalibrationFrame.grid(column=0, row=2, sticky="WE")

        self._pidSelected = StringVar()
        self._pidSelected.set("--")
        self._pidListBox = OptionMenu(pidCalibrationFrame, self._pidSelected, "--", \
                                      Cockpit.KEY_ANG_SPEED, Cockpit.KEY_ANGLES, Cockpit.KEY_ACCEL, \
                                       command=self._onPidListBoxChanged)
        self._pidListBox.pack(side=LEFT, padx=2)
        self._pidListBox.config(width=10)

        self._axisSelected = StringVar()
        self._axisSelected.set("--")
        self._axisListBox = OptionMenu(pidCalibrationFrame, self._axisSelected, "--", "X", "Y", "Z", \
                                       command=self._onAxisListBoxChanged)
        self._axisListBox.pack(side=LEFT, padx=2)
        self._axisListBox.config(state=DISABLED)

        Label(pidCalibrationFrame, text="P").pack(side=LEFT, padx=(14, 2))

        self._pidPString = StringVar()
        self._pidPString.set("0.00")
        self._pidPSpinbox = Spinbox(pidCalibrationFrame, width=5, from_=0.0, to=10000.0, increment=0.01, state=DISABLED, \
                                         textvariable=self._pidPString, command=self._onPidSpinboxChanged)
        self._pidPSpinbox.pack(side=LEFT, padx=2)

        Label(pidCalibrationFrame, text="I").pack(side=LEFT, padx=(14, 2))

        self._pidIString = StringVar()
        self._pidIString.set("0.00")
        self._pidISpinbox = Spinbox(pidCalibrationFrame, width=5, from_=0.0, to=10000.0, increment=0.01, state=DISABLED, \
                                         textvariable=self._pidIString, command=self._onPidSpinboxChanged)
        self._pidISpinbox.pack(side=LEFT, padx=2)

        Label(pidCalibrationFrame, text="D").pack(side=LEFT, padx=(14, 2))

        self._pidDString = StringVar()
        self._pidDString.set("0.00")
        self._pidDSpinbox = Spinbox(pidCalibrationFrame, width=5, from_=0.0, to=10000.0, increment=0.01, state=DISABLED, \
                                         textvariable=self._pidDString, command=self._onPidSpinboxChanged)
        self._pidDSpinbox.pack(side=LEFT, padx=2)

        #debug
        debugFrame = tkFrame(self)
        debugFrame.grid(column=0, row=3, sticky="WE")

        self._debugMsg = Message(debugFrame,
                                 anchor="nw",
                                 justify=LEFT,
                                 relief=SUNKEN,
                                 width=300)
        self._debugMsg.pack(fill=BOTH, expand=1)

    def _start(self):

        self._readDroneConfig()

        if Cockpit.JOYSTICK_ENABLED:
            self._joystickManager = JoystickManager.getInstance()
            self._joystickManager.start()

            joysticks = self._joystickManager.getJoysticks()
            if len(joysticks) != 0:
                self._joystick = joysticks[0]
                self._joystick.onAxisChanged += self._onJoystickAxisChanged
                self._joystick.onButtonPressed += self._onJoystickButtonPressed
            else:
                self._joystick = None

    def _onJoystickAxisChanged(self, sender, index):

        if self._started.get() and sender == self._joystick:

            axisValue = self._joystick.getAxisValue(index)

            if index == 0:

                self._yaw.set(axisValue)
                self._updateTarget()

            elif index == 1 and not Cockpit.THROTTLE_BY_USER:

                thrust = -axisValue
                self._throttle.set(thrust)
                self._updateTarget()

            elif index == 2 and Cockpit.THROTTLE_BY_USER:

                rowThrottle = (axisValue + 100.0) / 2.0
                if rowThrottle < 10.0:
                    throttle = rowThrottle * 6.0
                elif rowThrottle < 90.0:
                    throttle = 60.0 + ((rowThrottle - 10.0) / 8.0)
                else:
                    throttle = 70.0 + (rowThrottle - 90.0) * 3.0
                self._throttle.set(throttle)
                self._sendThrottle()

            elif index == 3:

                x = 196 + axisValue * 2
                lastCoords = self._shiftCanvas.coords(self._shiftMarker)
                coords = (x, lastCoords[1])
                self._plotShiftCanvasMarker(coords)

            elif index == 4:

                y = 196 + axisValue * 2
                lastCoords = self._shiftCanvas.coords(self._shiftMarker)
                coords = (lastCoords[0], y)
                self._plotShiftCanvasMarker(coords)

    def _onJoystickButtonPressed(self, sender, index):

        if sender == self._joystick and index == 7:

            if self._started.get() == 0:
                self._startedCB.select()
            else:
                self._startedCB.deselect()

            # Tkinter's widgets seem not to be calling the event-handler
            # when they are changed programmatically. Therefore, the
            # even-handler is called explicitly here.
            self._startedCBChanged()

    def exit(self):

        self._link.send({"key": "close", "data": None})

        self._stopUpdateInfoThread()

        self._link.close()

        if Cockpit.JOYSTICK_ENABLED:
            self._joystickManager.stop()

        self.quit()

    def _updateTarget(self):

        markerCoords = self._shiftCanvas.coords(self._shiftMarker)
        coords = ((markerCoords[0] + markerCoords[2]) / 2,
                  (markerCoords[1] + markerCoords[3]) / 2)

        self._target[0] = float(
            coords[1] - 200) / 2.0  # X-axis angle / X-axis acceleration
        self._target[1] = float(
            coords[0] - 200) / 2.0  # Y-axis angle / Y-axis acceleration
        #Remote control uses clockwise angle, but the drone's referece system uses counter-clockwise angle
        self._target[2] = -self._yaw.get()  # Z-axis angular speed

        # Z-axis acceleration (thrust). Only when the motor throttle is not controlled by user directly
        if Cockpit.THROTTLE_BY_USER:
            self._target[3] = 0.0
        else:
            self._target[3] = self._throttle.get()

        self._sendTarget()

    def _keyDown(self, event):

        if event.keysym == "Escape":
            self._throttle.set(0)
            self._started.set(0)
            self._thrustScale.config(state=DISABLED)
            self._stopUpdateInfoThread()
            self._sendIsStarted()

        elif event.keysym.startswith("Control"):
            self._controlKeyActive = True

        elif not self._controlKeysLocked and self._controlKeyActive:

            if event.keysym == "Up":
                self._thrustScaleUp()

            elif event.keysym == "Down":
                self._thrustScaleDown()

            elif event.keysym == "Left":
                self._yawLeft()

            elif event.keysym == "Right":
                self._yawRight()

            elif event.keysym == "space":
                self._yawReset()
                if not Cockpit.THROTTLE_BY_USER:
                    self._thrustReset()

        elif not self._controlKeysLocked and not self._controlKeyActive:

            if event.keysym == "Up":
                self._moveShiftCanvasMarker((0, -5))

            elif event.keysym == "Down":
                self._moveShiftCanvasMarker((0, 5))

            elif event.keysym == "Left":
                self._moveShiftCanvasMarker((-5, 0))

            elif event.keysym == "Right":
                self._moveShiftCanvasMarker((5, 0))

            elif event.keysym == "space":
                self._resetShiftCanvasMarker()

    def _keyUp(self, eventArgs):

        if eventArgs.keysym.startswith("Control"):
            self._controlKeyActive = False

    def _onMouseButton1(self, eventArgs):

        self._lastMouseCoords = (eventArgs.x, eventArgs.y)

    def _onMouseButtonRelease1(self, eventArgs):

        self._shiftCanvas.coords(self._shiftMarker, 196, 196, 204, 204)

    def _limitCoordsToSize(self, coords, size, width):

        maxSize = size - (width / 2.0)
        minSize = -(width / 2.0)

        if coords[0] > maxSize:
            x = maxSize

        elif coords[0] < minSize:
            x = minSize

        else:
            x = coords[0]

        if coords[1] > maxSize:
            y = maxSize

        elif coords[1] < minSize:
            y = minSize

        else:
            y = coords[1]

        return (x, y)

    def _plotShiftCanvasMarker(self, coords):

        coords = self._limitCoordsToSize(coords, 400, 8)
        self._shiftCanvas.coords(self._shiftMarker, coords[0], coords[1],
                                 coords[0] + 8, coords[1] + 8)
        self._updateTarget()

    def _moveShiftCanvasMarker(self, shift):

        lastCoords = self._shiftCanvas.coords(self._shiftMarker)
        newCoords = (lastCoords[0] + shift[0], lastCoords[1] + shift[1])
        self._plotShiftCanvasMarker(newCoords)

    def _resetShiftCanvasMarker(self):

        self._shiftCanvas.coords(self._shiftMarker, 196, 196, 204, 204)
        self._updateTarget()

    def _onMouseButton1Motion(self, eventArgs):

        deltaCoords = (eventArgs.x - self._lastMouseCoords[0],
                       eventArgs.y - self._lastMouseCoords[1])
        self._moveShiftCanvasMarker(deltaCoords)
        self._lastMouseCoords = (eventArgs.x, eventArgs.y)

    def _onMouseDoubleButton1(self, eventArgs):

        self._resetShiftCanvasMarker()

    def _onMouseButton3(self, eventArgs):

        self._lastMouseCoords = (eventArgs.x, eventArgs.y)
        self._mouseDirection = Cockpit.DIR_NONE

    def _onMouseButtonRelease3(self, eventArgs):

        self._shiftCanvas.coords(self._shiftMarker, 196, 196, 204, 204)

    def _onMouseButton3Motion(self, eventArgs):

        deltaCoords = (eventArgs.x - self._lastMouseCoords[0],
                       eventArgs.y - self._lastMouseCoords[1])

        if self._mouseDirection == Cockpit.DIR_NONE:
            if abs(deltaCoords[0]) > abs(deltaCoords[1]):
                self._mouseDirection = Cockpit.DIR_HORIZONTAL
            else:
                self._mouseDirection = Cockpit.DIR_VERTICAL

        if self._mouseDirection == Cockpit.DIR_HORIZONTAL:
            deltaCoords = (deltaCoords[0], 0)
        else:
            deltaCoords = (0, deltaCoords[1])

        self._moveShiftCanvasMarker(deltaCoords)
        self._lastMouseCoords = (eventArgs.x, eventArgs.y)

    def _thrustScaleUp(self):

        #TODO: 20160526 DPM: El valor de incremento de aceleración (1.0) puede ser muy alto
        if self._started.get():
            newValue = self._thrustScale.get() \
                + (Cockpit.THROTTLE_RESOLUTION if Cockpit.THROTTLE_BY_USER else 1.0)
            self._thrustScale.set(newValue)

            self._updateTarget()

    def _thrustScaleDown(self):

        #TODO: 20160526 DPM: El valor de decremento de aceleración (1.0) puede ser muy alto
        if self._started.get():
            newValue = self._thrustScale.get() \
                - (Cockpit.THROTTLE_RESOLUTION if Cockpit.THROTTLE_BY_USER else 1.0)
            self._thrustScale.set(newValue)

            self._updateTarget()

    def _thrustReset(self):

        if self._started.get():
            self._thrustScale.set(0.0)

            self._updateTarget()

    def _onThrustScaleDoubleButton1(self, eventArgs):

        self._thrustReset()

        return "break"

    def _yawRight(self):

        newValue = self._yaw.get() + 1
        self._yaw.set(newValue)
        self._updateTarget()

    def _yawLeft(self):

        newValue = self._yaw.get() - 1
        self._yaw.set(newValue)
        self._updateTarget()

    def _yawReset(self):

        self._yaw.set(0)
        self._updateTarget()

    def _onMouseWheelUp(self, eventArgs):

        if not self._controlKeyActive:
            self._thrustScaleUp()

        else:
            self._yawRight()

    def _onMouseWheelDown(self, eventArgs):

        if not self._controlKeyActive:
            self._thrustScaleDown()

        else:
            self._yawLeft()

    def _onMouseWheel(self, eventArgs):

        factor = eventArgs.delta / (1200.0 if Cockpit.THROTTLE_BY_USER
                                    and not self._controlKeyActive else 120.0)

        if not self._controlKeyActive:

            if self._started.get():
                newValue = self._thrustScale.get() + factor
                self._thrustScale.set(newValue)

                self._updateTarget()
        else:
            newValue = self._yaw.get() + factor
            self._yaw.set(newValue)
            self._updateTarget()

    def _onYawScaleChanged(self, eventArgs):

        self._updateTarget()

    def _onYawScaleDoubleButton1(self, eventArgs):

        self._yawReset()

        return "break"

    def _startedCBChanged(self):

        if not self._started.get():
            self._throttle.set(0)
            self._thrustScale.config(state=DISABLED)
            #self._integralsCB.config(state=DISABLED)
            self._stopUpdateInfoThread()
        else:
            self._thrustScale.config(state="normal")
            #self._integralsCB.config(state="normal")
            self._startUpdateInfoThread()

        self._sendIsStarted()

#     def _integralsCBChanged(self):
#
#         self._link.send({"key": "integrals", "data":self._integralsEnabled.get() != 0})
#

    def _onThrustScaleChanged(self, eventArgs):

        if Cockpit.THROTTLE_BY_USER:

            self._sendThrottle()

        else:

            self._updateTarget()

    def _sendThrottle(self):

        self._link.send({"key": "throttle", "data": self._throttle.get()})

    def _sendTarget(self):

        self._link.send({"key": "target", "data": self._target})

    def _sendIsStarted(self):

        isStarted = self._started.get() != 0
        self._link.send({"key": "is-started", "data": isStarted})

    def _sendPidCalibrationData(self):

        if self._pidSelected.get() != "--" and self._axisSelected.get(
        ) != "--":

            pidData = {
                "pid": self._pidSelected.get(),
                "axis": self._axisSelected.get(),
                "p": float(self._pidPSpinbox.get()),
                "i": float(self._pidISpinbox.get()),
                "d": float(self._pidDSpinbox.get())
            }

            self._link.send({"key": "pid-calibration", "data": pidData})

    def _updatePidCalibrationData(self):

        pid = self._pidSelected.get()
        axis = self._axisSelected.get()

        if pid != "--" and axis != "--":

            self._pidConstants[pid][axis]["P"] = float(self._pidPSpinbox.get())
            self._pidConstants[pid][axis]["I"] = float(self._pidISpinbox.get())
            self._pidConstants[pid][axis]["D"] = float(self._pidDSpinbox.get())

    def _readDroneConfig(self):

        self._link.send({
            "key": "read-drone-config",
            "data": None
        }, self._onDroneConfigRead)

    def _readDroneState(self):

        if not self._readingState:
            self._readingState = True
            self._link.send({
                "key": "read-drone-state",
                "data": None
            }, self._onDroneStateRead)

    def _readPidConfigItem(self, message, cockpitKey, axises, configKeys):

        for i in range(len(axises)):
            for j in range(len(Cockpit.PID_KEYS)):
                self._pidConstants[cockpitKey][axises[i]][
                    Cockpit.PID_KEYS[j]] = message[configKeys[j]][i]

    def _onDroneConfigRead(self, message):

        #TODO Show current configuration within the GUI (at least relevant settings)
        if message:

            #Angle-speeds
            self._readPidConfigItem(message, Cockpit.KEY_ANG_SPEED, ["X", "Y", "Z"], \
                                    [Configuration.PID_ANGLES_SPEED_KP, \
                                     Configuration.PID_ANGLES_SPEED_KI, \
                                     Configuration.PID_ANGLES_SPEED_KD])

            #Angles
            self._readPidConfigItem(message, Cockpit.KEY_ANGLES, ["X", "Y"], \
                                    [Configuration.PID_ANGLES_KP, \
                                     Configuration.PID_ANGLES_KI, \
                                     Configuration.PID_ANGLES_KD])

            #Accels
            self._readPidConfigItem(message, Cockpit.KEY_ACCEL, ["X", "Y", "Z"], \
                                    [Configuration.PID_ACCEL_KP, \
                                     Configuration.PID_ACCEL_KI, \
                                     Configuration.PID_ACCEL_KD])

    def _onDroneStateRead(self, state):

        if state:

            for index in range(4):
                self._throttleTexts[index].set("{0:.3f}".format(
                    state["_throttles"][index]))

            for index in range(3):
                self._accelTexts[index].set("{0:.3f}".format(
                    state["_accels"][index]))
                self._angleTexts[index].set("{0:.3f}".format(
                    state["_angles"][index]))

            currentPeriod = state["_currentPeriod"]
            if currentPeriod > 0.0:

                freq = 1.0 / currentPeriod
                self._loopRateText.set("{0:.3f}".format(freq))

            else:
                self._loopRateText.set("--")

        else:
            self._stopUpdateInfoThread()

        self._readingState = False

    def _onPidSpinboxChanged(self):

        self._updatePidCalibrationData()
        self._sendPidCalibrationData()

    def _onPidListBoxChanged(self, pid):

        self._axisSelected.set("--")

        self._pidPString.set("--")
        self._pidIString.set("--")
        self._pidDString.set("--")

        self._pidPSpinbox.config(state=DISABLED)
        self._pidISpinbox.config(state=DISABLED)
        self._pidDSpinbox.config(state=DISABLED)

        self._selectedPidConstats = pid

        if pid == "--":
            self._axisListBox.config(state=DISABLED)
            self._controlKeysLocked = False

        else:
            self._axisListBox.config(state="normal")
            self._controlKeysLocked = True

    def _onAxisListBoxChanged(self, axis):

        if axis == "--" or (self._selectedPidConstats == Cockpit.KEY_ANGLES
                            and axis == "Z"):

            self._pidPString.set("--")
            self._pidIString.set("--")
            self._pidDString.set("--")

            self._pidPSpinbox.config(state=DISABLED)
            self._pidISpinbox.config(state=DISABLED)
            self._pidDSpinbox.config(state=DISABLED)

            self._controlKeysLocked = axis != "--"

        else:

            self._pidPString.set("{:.2f}".format(
                self._pidConstants[self._selectedPidConstats][axis]["P"]))
            self._pidIString.set("{:.2f}".format(
                self._pidConstants[self._selectedPidConstats][axis]["I"]))
            self._pidDString.set("{:.2f}".format(
                self._pidConstants[self._selectedPidConstats][axis]["D"]))

            self._pidPSpinbox.config(state="normal")
            self._pidISpinbox.config(state="normal")
            self._pidDSpinbox.config(state="normal")

            self._controlKeysLocked = True

    def _updateInfo(self):

        while self._updateInfoThreadRunning:

            self._readDroneState()

            time.sleep(1.0)

    def _startUpdateInfoThread(self):

        self._updateInfoThreadRunning = True
        if not self._updateInfoThread.isAlive():
            self._updateInfoThread.start()

    def _stopUpdateInfoThread(self):

        self._updateInfoThreadRunning = False
        if self._updateInfoThread.isAlive():
            self._updateInfoThread.join()
Пример #13
0
class TTTUI(object):

    default_ply = 6
    neither_color = '#%02x%02x%02x' % (255, 255, 255)  # white
    player_color = '#%02x%02x%02x' % (62, 188, 0)  # green
    computer_color = '#%02x%02x%02x' % (192, 35, 3)  # red
    win_color = '#%02x%02x%02x' % (25, 111, 254)  # blue

    def __init__(self):
        # TTT related
        self.ttt = Board(ply=9)
        self.human_first = True

        # UI related
        self.root = Tk()
        self.root.resizable(0, 0)
        self.root.title("3D TTT")

        # TTT frames
        self.ttt_frames = [Frame(self.root) for x in range(3)]
        for i in range(3):
            self.ttt_frames[i].grid(row=0, column=i)
        self.button_pos = dict()
        self._init_board()

        # control frame
        self.control_frame = Frame(self.root, padx=5, pady=5)
        self.control_frame.grid(row=1, column=1)
        self.new_game_btn = Button(self.control_frame, text='New Game', \
                command=lambda: self.reset())
        self.new_game_btn.pack(side=LEFT, fill=BOTH, expand=True)
        self.toggle_human_first_btn = Button(self.control_frame, \
                text='Human First', command=lambda: self.toggle_human_first())
        self.toggle_human_first_btn.pack(side=RIGHT, fill=BOTH, expand=True)
        self.ply_box = Spinbox(self.control_frame, from_=1, to=20, \
                textvariable=self.ttt.difficulty, command=lambda: self.reset())
        self.ply_box.pack(side=RIGHT, fill=BOTH, expand=True)

        # start UI
        self.update_pieces()
        self.start()
        self.root.mainloop()

    def toggle_human_first(self):
        self.human_first = not self.human_first
        self.toggle_human_first_btn.config(text='Human First' if \
                self.human_first else 'Computer First')
        self.reset()

    def _find_button(self, frame, r, c):
        for child in frame.children.values():
            info = child.grid_info()
            if info['row'] == r and info['column'] == c:
                return child
        return None

    def update_pieces(self):
        player_pieces = self.ttt.get_moves(self.ttt.human)
        computer_pieces = self.ttt.get_moves(self.ttt.ai)

        cnt = 0
        for b, board in enumerate(self.ttt.board):
            for r, row in enumerate(board):
                for c, col in enumerate(row):
                    color = self.neither_color
                    text = '-'
                    occupied = False
                    if cnt in player_pieces:
                        color = self.player_color
                        text = self.ttt.human
                    if cnt in computer_pieces:
                        color = self.computer_color
                        text = self.ttt.ai
                    if self.ttt.complete and cnt in self.ttt.winning_combo:
                        color = self.win_color
                    btn = self.button_pos[cnt]
                    btn.config(text=text, bg=color, state=DISABLED if \
                            occupied else NORMAL)
                    cnt += 1

    def place_human(self, position):
        if position in self.ttt.allowed_moves and not self.ttt.complete:
            self.ttt.move(position, self.ttt.human)
            self.ttt.human_turn = False
            self.update_pieces()
            self.place_computer()

    def place_computer(self):
        if not self.ttt.complete:
            self.ttt.computers_move()
            self.update_pieces()

    def reset(self):
        self.ttt.reset()
        self.ttt.difficulty = self.default_ply if not \
                self.ply_box.get().isdigit() else int(self.ply_box.get())
        self.ttt.human_turn = self.human_first
        self.update_pieces()
        self.start()

    def _init_board(self):
        cnt = 0
        for b, board in enumerate(self.ttt.board):
            for x, row in enumerate(board):
                for y, cell in enumerate(row):
                    padding = (0, 0)
                    if y == 2 and b != 2:
                        padding = (0, 12)
                    btn = Button(self.ttt_frames[b], width=8, height=4, \
                            command=lambda x=cell: self.place_human(x))
                    btn.grid(row=x, column=y, padx=padding)
                    self.button_pos[cnt] = btn
                    cnt += 1

    def start(self):
        if not self.ttt.human_turn:
            self.place_computer()
Пример #14
0
class ScanDialog(Frame):
    def __init__(self, parent):
        Frame.__init__(self, parent)
        self.parent = parent
        self.worker = None
        self.elapsed = 0
        self.settings = Settings(self)

        # self.initUI() follows

        self.parent.title("Scan Images")
        self.pack(fill=BOTH, expand=1)

        r = 0  # current grid row

        Label(self, text="Name prefix:").grid(row=r, column=0)
        Label(self, text="Number suffix:").grid(row=r, column=1)
        r += 1

        self.newName = StringVar()
        self.newName.set('Scan_')
        newName = Entry(self, textvariable=self.newName, width=60)
        newName.grid(row=1, column=0)
        newName.bind("<Return>",   lambda event: self.scan())
        newName.bind("<KP_Enter>", lambda event: self.scan())
        newName.bind("<Escape>", lambda event: self.parent.destroy())
        newName.focus_set()
        self.newNameEntry = newName

        self.numberSuffix = Spinbox(self, from_=1, to=999)
        self.numberSuffix.bind("<Return>",   lambda event: self.scan())
        self.numberSuffix.bind("<KP_Enter>", lambda event: self.scan())
        self.numberSuffix.grid(row=r, column=1)
        r += 1

        self.okButton = Button(self, text="Scan", command=self.scan, width=60, height=5)
        self.okButton.grid(row=r, column=0)

        cancelButton = Button(self, text="Cancel", command=self.parent.destroy)
        cancelButton.grid(row=r, column=1)
        r += 1

        settings_panel = tk.Frame(self)

        panel = tk.Frame(settings_panel)
        tk.Label(panel, text="Paper Format").pack()
        tk.Radiobutton(panel, text="A4", value=1.0, variable=self.settings.scale).pack(anchor=tk.W)
        tk.Radiobutton(panel, text="A5", value=2 ** (-0.5), variable=self.settings.scale).pack(anchor=tk.W)
        tk.Radiobutton(panel, text="A6", value=0.5, variable=self.settings.scale).pack(anchor=tk.W)
        panel.pack(side=tk.LEFT, anchor=tk.N)

        panel = tk.Frame(settings_panel)
        tk.Label(panel, text="File Format").pack()
        tk.Radiobutton(panel, text="PNG", value='.png', variable=self.settings.extension).pack(anchor=tk.W)
        tk.Radiobutton(panel, text="JPG", value='.jpg', variable=self.settings.extension).pack(anchor=tk.W)
        panel.pack(side=tk.LEFT, anchor=tk.N)

        panel = tk.Frame(settings_panel)
        tk.Label(panel, text="Scan Mode").pack()
        tk.Radiobutton(panel, text="Color", value='color', variable=self.settings.scan_mode).pack(anchor=tk.W)
        tk.Radiobutton(panel, text="Gray", value='gray', variable=self.settings.scan_mode).pack(anchor=tk.W)
        tk.Radiobutton(panel, text="Lineart", value='lineart', variable=self.settings.scan_mode).pack(anchor=tk.W)
        panel.pack(side=tk.LEFT, anchor=tk.N)

        settings_panel.grid(row=r, column=0, columnspan=2)
        r += 1


        self.statusLabel = Label(self, text="Idle")
        self.statusLabel.grid(row=r, column=0, columnspan=2)

    def _checkAlive(self):
        if self.worker is None:
            return
        if self.worker.is_alive():
            self.after(100, self._checkAlive)
            self.elapsed += 1
            self.statusLabel.config(text='Scanning, please wait... (%.1f s)' % (self.elapsed/10.0))
        else:
            self.worker = None
            self.okButton.config(state=NORMAL)
            self.numberSuffix.invoke('buttonup')
            self.newNameEntry.focus_set()
            self.statusLabel.config(text='Idle (last scan: %.1f s)' % (self.elapsed/10.0))

    def _ext(self):
        return self.settings.ext()

    def scan(self):
        target = '%s%03d%s' % (self.newName.get(), int(self.numberSuffix.get()), self._ext(), )
        if os.path.exists(target):
            if not tkMessageBox.askokcancel(title='Scan Images', message='File exists. Overwrite?'):
                print 'Not scanning: %s - file exists!' % target
                new_name = self.newName.get()
                for i in xrange(int(self.numberSuffix.get()), 1000):
                    new_target = '%s%03d.%s' % (new_name, int(self.numberSuffix.get()), self._ext(), )
                    if not os.path.exists(new_target):
                        print 'Next available filename: %s' % (new_target, )
                        self.numberSuffix.delete(0, 'end')
                        self.numberSuffix.insert(0, i)
                        break
                return

        print "Scanning to filename '%s' ..." % (target, )

        if s is None:
            print('No scanner present. Connect and restart application.')
            return

        if self.worker is None:
            self.worker = ScanWorker(target, self.settings)
            self.worker.start()
            self.elapsed = 0
            self.after(100, self._checkAlive)
            self.okButton.config(state=DISABLED)
            self.statusLabel.config(text='Scanning, please wait...')
        else:
            print "Error - not started, worker exists."
Пример #15
0
class SettingWindow(Toplevel):
    def __init__(self, master, max_num_features, num_frames, mser_image):
        Toplevel.__init__(self, master)

        self.protocol('WM_DELETE_WINDOW', self.withdraw)

        self.notebook = ttk.Notebook(self)
        frame_feats = ttk.Frame(self.notebook)
        frame_forest = ttk.Frame(self.notebook)
        frame_mser = ttk.Frame(self.notebook)
        frame_other = ttk.Frame(self.notebook)
        self.notebook.add(frame_feats, text="Features ")
        self.notebook.add(frame_forest, text=" Forest  ")
        self.notebook.add(frame_mser, text=" MSER  ")
        self.notebook.add(frame_other, text=" Other  ")

        self.max_num_feats = max_num_features
        self.selection = None

        self.mser_image = mser_image

        rand_row = random.randint(1, 512-200)
        rand_col = random.randint(1, 512-110)
        self.mser_area = mser_image[rand_row:rand_row+180, rand_col:rand_col+100]

        # read images from icons folder
        self.hf0_img = PhotoImage(file="./icons/hf0.gif")
        self.hf1_img = PhotoImage(file="./icons/hf1.gif")
        self.hf2_img = PhotoImage(file="./icons/hf2.gif")
        self.hf3_img = PhotoImage(file="./icons/hf3.gif")
        self.hf4_img = PhotoImage(file="./icons/hf4.gif")
        self.hf5_img = PhotoImage(file="./icons/hf5.gif")

        self.features_vars = list()
        for i in range(max_num_features):
            self.features_vars.append(IntVar())

        Label(frame_feats, text="Patch size (" + u"\N{GREEK SMALL LETTER PI}" + "):").grid(row=0, column=0, pady=5)
        self.patch_size_spinbox = Spinbox(frame_feats, from_=3, to=30, width=3)
        self.patch_size_spinbox.delete(0, END)
        self.patch_size_spinbox.insert(END, 10)
        self.patch_size_spinbox.grid(row=0, column=1, padx=5)

        f1 = ttk.Labelframe(frame_feats, text='Mean filter')
        f1.grid(row=1, columnspan=2)

        Label(f1, text=u"\N{GREEK SMALL LETTER PI}").grid(row=0, column=0)
        Checkbutton(f1, text="R", variable=self.features_vars[0]).grid(row=0, column=1)
        Checkbutton(f1, text="G", variable=self.features_vars[1]).grid(row=0, column=2)
        Checkbutton(f1, text="B", variable=self.features_vars[2]).grid(row=0, column=3)

        Label(f1, text=u"\N{GREEK SMALL LETTER PI}" + "/2").grid(row=1, column=0)
        Checkbutton(f1, text="R", variable=self.features_vars[3]).grid(row=1, column=1)
        Checkbutton(f1, text="G", variable=self.features_vars[4]).grid(row=1, column=2)
        Checkbutton(f1, text="B", variable=self.features_vars[5]).grid(row=1, column=3)

        f2 = ttk.Labelframe(frame_feats, text="Gaussian filter")
        f2.grid(row=2, columnspan=2)

        Label(f2, text=str(1.0)).grid(row=0, column=0)
        Checkbutton(f2, text="R", variable=self.features_vars[6]).grid(row=0, column=1)
        Checkbutton(f2, text="G", variable=self.features_vars[7]).grid(row=0, column=2)
        Checkbutton(f2, text="B", variable=self.features_vars[8]).grid(row=0, column=3)

        Label(f2, text=str(3.5)).grid(row=1, column=0)
        Checkbutton(f2, text="R", variable=self.features_vars[9]).grid(row=1, column=1)
        Checkbutton(f2, text="G", variable=self.features_vars[10]).grid(row=1, column=2)
        Checkbutton(f2, text="B", variable=self.features_vars[11]).grid(row=1, column=3)

        f3 = ttk.Labelframe(frame_feats, text="Laplacian of gaussian")
        f3.grid(row=3, columnspan=2)

        Label(f3, text=str(2.0)).grid(row=0, column=0)
        Checkbutton(f3, text="R", variable=self.features_vars[12]).grid(row=0, column=1)
        Checkbutton(f3, text="G", variable=self.features_vars[13]).grid(row=0, column=2)
        Checkbutton(f3, text="B", variable=self.features_vars[14]).grid(row=0, column=3)

        Label(f3, text=str(3.5)).grid(row=1, column=0)
        Checkbutton(f3, text="R", variable=self.features_vars[15]).grid(row=1, column=1)
        Checkbutton(f3, text="G", variable=self.features_vars[16]).grid(row=1, column=2)
        Checkbutton(f3, text="B", variable=self.features_vars[17]).grid(row=1, column=3)

        f4 = ttk.Labelframe(frame_feats, text="Haar-like features")
        f4.grid(row=1, rowspan=2, column=3, padx=5)

        Checkbutton(f4, image=self.hf0_img, variable=self.features_vars[18]).grid(row=0, column=0)
        Checkbutton(f4, image=self.hf1_img, variable=self.features_vars[19]).grid(row=0, column=1)
        Checkbutton(f4, image=self.hf2_img, variable=self.features_vars[20]).grid(row=1, column=0)
        Checkbutton(f4, image=self.hf3_img, variable=self.features_vars[21]).grid(row=1, column=1)
        Checkbutton(f4, image=self.hf4_img, variable=self.features_vars[22]).grid(row=2, column=0)
        Checkbutton(f4, image=self.hf5_img, variable=self.features_vars[23]).grid(row=2, column=1)

        buttons_paned_window = PanedWindow(frame_feats, orient=VERTICAL)
        buttons_paned_window.grid(row=3, column=3)

        self.select_all_button = Button(buttons_paned_window, text="Select all", command=self._select_all)
        buttons_paned_window.add(self.select_all_button)

        self.clear_selection_button = Button(buttons_paned_window, text="Clear selection", command=self._clear_selection)
        buttons_paned_window.add(self.clear_selection_button)

        # default values
        for j in [0, 1, 3, 6, 7, 9, 15, 21, 23]:
            self.features_vars[j].set(1)

        # FOREST FRAMES
        # number of trees
        f5 = ttk.Labelframe(frame_forest, text="Number of trees")
        f5.grid(row=0, columnspan=2, pady=5, padx=5)
        Label(f5, text="N").grid(row=1, column=0)
        self.num_trees_scale = Scale(f5, from_=5, to=500, resolution=5, orient=HORIZONTAL)
        self.num_trees_scale.set(300)
        self.num_trees_scale.grid(row=0, column=1, rowspan=2)

        # depth single tree
        f6 = ttk.Labelframe(frame_forest, text="Depth single tree")
        f6.grid(row=1, columnspan=2, pady=5, padx=5)
        Label(f6, text="d").grid(row=1, column=0)
        self.depth_tree_scale = Scale(f6, from_=2, to=20, orient=HORIZONTAL)
        self.depth_tree_scale.set(3)
        self.depth_tree_scale.grid(row=0, column=1, rowspan=2)

        # percentage number of features
        f7 = ttk.Labelframe(frame_forest, text="% subset of features")
        f7.grid(row=2, columnspan=2, pady=5, padx=5)
        Label(f7, text="m").grid(row=1, column=0)
        self.percentage_feats_scale = Scale(f7, from_=0.0, to=1, resolution=0.05, orient=HORIZONTAL)
        self.percentage_feats_scale.set(0.5)
        self.percentage_feats_scale.grid(row=0, column=1, rowspan=2)

        # mser frame
        # delta
        f8 = ttk.Labelframe(frame_mser, text="Delta")
        f8.grid(row=0, columnspan=2, pady=5, padx=5)
        Label(f8, text=u"\N{GREEK SMALL LETTER DELTA}").grid(row=1, column=0)
        self.delta_scale = Scale(f8, from_=1, to=10, resolution=1, orient=HORIZONTAL)
        self.delta_scale.set(2)
        self.delta_scale.grid(row=0, column=1, rowspan=2)

        # min area
        f9 = ttk.Labelframe(frame_mser, text="Minimum area")
        f9.grid(row=1, columnspan=2, pady=5, padx=5)
        Label(f9, text="m").grid(row=1, column=0)
        self.min_area_scale = Scale(f9, from_=2, to=200, orient=HORIZONTAL)
        self.min_area_scale.set(10)
        self.min_area_scale.grid(row=0, column=1, rowspan=2)

        # percentage number of features
        f10 = ttk.Labelframe(frame_mser, text="Maximum area")
        f10.grid(row=2, columnspan=2, pady=5, padx=5)
        Label(f10, text="M").grid(row=1, column=0)
        self.max_area_scale = Scale(f10, from_=50, to=1000, resolution=5, orient=HORIZONTAL)
        self.max_area_scale.set(350)
        self.max_area_scale.grid(row=0, column=1, rowspan=2)

        # mser image
        f11 = ttk.Labelframe(frame_mser)
        f11.grid(row=0, rowspan=3, column=2, padx=5)

        self.mser_img_array = Image.fromarray(self.mser_area, "RGB")
        self.mser_img = ImageTk.PhotoImage(self.mser_img_array)

        img_label = Label(f11, image=self.mser_img)
        img_label.grid(row=0, column=0)

        buttons_p_w_mser = PanedWindow(f11, orient=HORIZONTAL)
        try_button = Button(f11, text="Try", command=self.try_mser)
        buttons_p_w_mser.add(try_button)
        change_button = Button(f11, text="New img", command=self.change_mser)
        buttons_p_w_mser.add(change_button)
        buttons_p_w_mser.grid(row=1, column=0)

        # other frame
        f12 = ttk.Labelframe(frame_other, text="Refinement")
        f12.grid(row=0, columnspan=2, pady=5, padx=5)
        Label(f12, text=u"\N{GREEK CAPITAL LETTER PHI}_l").grid(row=1, column=0)
        self.low_thresh_scale = Scale(f12, from_=0, to=1, resolution=0.05, orient=HORIZONTAL, length=90)
        self.low_thresh_scale.set(0.45)
        self.low_thresh_scale.grid(row=0, column=1, rowspan=2)
        Label(f12, text=u"\N{GREEK CAPITAL LETTER PHI}_h").grid(row=3, column=0)
        self.high_thresh_scale = Scale(f12, from_=0, to=1, resolution=0.05, orient=HORIZONTAL, length=90)
        self.high_thresh_scale.set(0.65)
        self.high_thresh_scale.grid(row=2, column=1, rowspan=2)

        f13 = ttk.Labelframe(frame_other, text="Dots distance")
        f13.grid(row=1, columnspan=2, pady=5, padx=5)
        Label(f13, text=u"     \N{GREEK SMALL LETTER SIGMA}").grid(row=1, column=0)
        self.dots_distance_scale = Scale(f13, from_=1, to=20, resolution=1, orient=HORIZONTAL, length=90)
        self.dots_distance_scale.set(6)
        self.dots_distance_scale.grid(row=0, column=1, rowspan=2)

        f14 = ttk.Labelframe(frame_other, text="Tracks")
        f14.grid(row=0, column=3, pady=5, padx=5)
        Label(f14, text="N").grid(row=1, column=0)
        self.num_frames_tracks_spinbox = Spinbox(f14, from_=2, to=num_frames, width=10)
        self.num_frames_tracks_spinbox.delete(0, END)
        self.num_frames_tracks_spinbox.insert(END, num_frames)
        self.num_frames_tracks_spinbox.grid(row=0, column=1, rowspan=2)

        Label(f14, text=u"\N{GREEK SMALL LETTER TAU}").grid(row=3, column=0)
        self.gaps_scale = Scale(f14, from_=1, to=10, resolution=1, orient=HORIZONTAL, length=90)
        self.gaps_scale.set(2)
        self.gaps_scale.grid(row=2, column=1, rowspan=2)

        self.notebook.pack(padx=1, pady=1)

        save_button = Button(self, text=" Save and Close window ", command=self.withdraw)
        save_button.pack(pady=2)

    def _select_all(self):
        for i, var in enumerate(self.features_vars):
            var.set(1)

    def _clear_selection(self):
        for i, var in enumerate(self.features_vars):
            var.set(0)

    def change_mser(self):
        rand_row = random.randint(1, 512-200)
        rand_col = random.randint(1, 512-110)
        self.mser_area = self.mser_image[rand_row:rand_row+180, rand_col:rand_col+100]

        self.update_mser_image(self.mser_area)

    def try_mser(self):
        delta = self.delta_scale.get()
        min_area = self.min_area_scale.get()
        max_area = self.max_area_scale.get()

        image = self.mser_area
        red_c = image[:,:,0]
        red_c = cv2.equalizeHist(red_c)

        det_img = image.copy()

        mser = cv2.MSER(delta, _min_area=min_area, _max_area=max_area)
        regions = mser.detect(red_c)
        cp = list()
        new_c = np.zeros(self.mser_area.shape, dtype=np.uint8)
        for r in regions:
            for point in r:
                cp.append(point)
                det_img[point[1], point[0], 0] = 0
                det_img[point[1], point[0], 1] = 0
                det_img[point[1], point[0], 2] = 204
                #new_c[point[1], point[0]] = 255

        self.update_mser_image(det_img)

    def update_mser_image(self, new_image):
        self.mser_img_array = Image.fromarray(new_image)
        self.mser_img.paste(self.mser_img_array)

    def get_patch_size(self):
        patch_size = self.patch_size_spinbox.get()
        return int(patch_size)

    def get_num_frames_tracks(self):
        num_frames_tracks = self.num_frames_tracks_spinbox.get()
        return int(num_frames_tracks)

    def get_mser_opts(self):
        return [self.delta_scale.get(), self.min_area_scale.get(), self.max_area_scale.get()]

    def get_forest_opts(self):
        return [self.num_trees_scale.get(), self.depth_tree_scale.get(), self.percentage_feats_scale.get()]

    def get_low_thresh(self):
        return self.low_thresh_scale.get()

    def get_high_thresh(self):
        return self.high_thresh_scale.get()

    def get_dots_distance(self):
        return int(self.dots_distance_scale.get())

    def get_selection_mask(self):
        if self.selection is not None:
            return self.selection

        selection_mask = np.zeros((self.max_num_feats, ), dtype='bool')
        for i, var in enumerate(self.features_vars):
            selection_mask[i] = var.get()
        self.selection = selection_mask
        return selection_mask
Пример #16
0
    def ventanaImprimir(self):
        t = Toplevel(self)
        t.wm_title("Imprimir")

        Label(t, text="Numero de Copias por etiqueta").pack()
        w = Spinbox(t, from_=1, to=10)
        w.pack()

        buttonImprimir = Button(t, text="Imprimir",  command=lambda:self.imprimir(int(w.get()),t))
        buttonImprimir.pack()
Пример #17
0
class MacroEdit(Toplevel):
	def __init__(self, root, prtr, settings, log, fn, text, *arg):
		Toplevel.__init__(self, root, *arg)
		self.title("Macro Editor")
		
		self.fn = fn
		
		self.app = root
		self.settings = settings
		self.printer = prtr
		self.log = log
		
		self.macroList = self.settings.getMacroList()
		self.macroEntry = None
		
		if fn == None:
			title = "New macro"
			self.macroTitle = None
			self.newMacro = True
		else:
			self.newMacro = False
			self.macroTitle = title = os.path.basename(fn)
			for m in self.macroList:
				if self.macroTitle == m[MNAME]:
					self.macroEntry = m
					break
		
		self.f = LabelFrame(self, text=title)
		
		self.entry = Text(self.f, width=80, height=24, relief=RIDGE, bd=2)
		self.entry.grid(row=1, column=1)
		
		self.f.grid(row=1, column=1, columnspan=6)
		
		self.bSave = Button(self, text="Save", width=20, command=self.doSave)
		self.bSave.grid(row=2, column=1)
		self.bExit = Button(self, text="Exit", width=20, command=self.doExit)
		self.bExit.grid(row=2, column=2)
		
		self.cbvAddButton = IntVar()
		self.cbAddButton = Checkbutton(self, text="Add Button",  variable=self.cbvAddButton, command=self.doAddButton)
		self.cbAddButton.grid(row=2, column=3)
		
		self.buttonText = Entry(self, width=12)
		self.buttonText.grid(row=2, column=4)

		l = Label(self, text="Column:", justify=RIGHT)
		l.grid(row=2, column=5, sticky=E)
		self.spCol = Spinbox(self, values=[1,2,3], width=12, justify=RIGHT)
		self.spCol.grid(row=2, column=6)

		l = Label(self, text="Row:", justify=RIGHT)
		l.grid(row=3, column=5, sticky=E)
		self.spRow = Spinbox(self, values=[1,2,3,4,5,6,7,8,9,10], width=12, justify=RIGHT)
		self.spRow.grid(row=3, column=6)

		if self.macroEntry != None:
			self.cbvAddButton.set(1)
			self.spRow.delete(0, END)
			self.spRow.insert(0, self.macroEntry[MROW])
			self.spCol.delete(0, END)
			self.spCol.insert(0, self.macroEntry[MCOL])
			self.buttonText.delete(0, END)
			self.buttonText.insert(0, self.macroEntry[MTEXT])
			self.initialButtonInfo = [1, self.macroEntry[MCOL], self.macroEntry[MROW], self.macroEntry[MTEXT]]
		else:		
			self.cbvAddButton.set(0)
			self.spRow.delete(0, END)
			self.spRow.insert(0, 1)
			self.spCol.delete(0, END)
			self.spCol.insert(0, 1)
			self.buttonText.delete(0, END)
			self.initialButtonInfo = [0, 1, 1, ""]
			
		self.doAddButton()

		self.startText = text
		self.entry.delete("1.0", END)
		self.entry.insert(END, self.startText)
		self.entry.edit_modified(False)
		
		self.grab_set()
		self.app.wait_window(self)
	
	def doAddButton(self):
		if self.cbvAddButton.get() == 1:
			self.buttonText.config(state=NORMAL)
			self.spRow.config(state=NORMAL)
			self.spCol.config(state=NORMAL)
		else:
			self.buttonText.config(state=DISABLED)
			self.spRow.config(state=DISABLED)
			self.spCol.config(state=DISABLED)
			
	def buttonInfoChanged(self):
		if self.cbvAddButton.get() != self.initialButtonInfo[0]:
			return True
		
		if self.initialButtonInfo[1] != int(self.spCol.get()):
			return True
		
		if self.initialButtonInfo[2] != int(self.spRow.get()):
			return True

		return self.initialButtonInfo[3] != self.buttonText.get()

	def doSave(self):
		if self.cbvAddButton.get() == 1 and self.buttonInfoChanged():
			c = int(self.spCol.get())
			r = int(self.spRow.get())
			for m in self.macroList:
				if c == m[MCOL] and r == m[MROW]:
					if self.newMacro or self.macroTitle != m[MNAME]:
						showerror("Duplicate Location", "That position is already in use by another macro", parent=self)
						return
					
			buttonInfo = [c, r, self.buttonText.get()]
		else:
			buttonInfo = None
			
		if self.entry.edit_modified() or self.buttonInfoChanged():
			l = self.entry.get("1.0", END).rstrip()
			if self.app.macroEditSave(self.fn, l, buttonInfo, self):
				self.entry.edit_modified(False)
				self.initialButtonInfo[0] = self.cbvAddButton.get()
				self.initialButtonInfo[1] = int(self.spCol.get())
				self.initialButtonInfo[2] = int(self.spRow.get())
				self.initialButtonInfo[3] = self.buttonText.get()
	
	def doExit(self):
		if self.entry.edit_modified() or self.buttonInfoChanged():
			if not tkMessageBox.askyesno("Exit?", "Are you sure you want to exit and lose changes?", parent=self):
				return
			
		self.app.macroEditExit(self.fn)
		self.destroy()
Пример #18
0
class Outlier4dfp(Frame):
    def __init__(self,
                 parent,
                 filename=None,
                 filename_roi=None,
                 filename_csv=None,
                 dirname=None,
                 obj_return_value=None):
        Frame.__init__(self, parent)
        self.parent = parent
        self.obj_return_value = obj_return_value

        # check filenames
        if filename is None or not os.path.isfile(filename):
            if dirname is not None:
                filename = tkFileDialog.askopenfilename(initialdir=dirname)
            else:
                filename = tkFileDialog.askopenfilename()

        if not os.path.isfile(filename):
            parent.destroy()
            return

        if filename_roi is None or not os.path.isfile(filename_roi):
            if dirname is not None:
                filename_roi = tkFileDialog.askopenfilename(initialdir=dirname)
            else:
                filename_roi = tkFileDialog.askopenfilename()

        if not os.path.isfile(filename_roi):
            parent.destroy()
            return

        if dirname is None:
            self.dirname = os.path.dirname(filename)
        else:
            self.dirname = dirname

        if filename_csv is None:
            filename_csv = os.path.join(
                self.dirname,
                filename_wo_ext(os.path.basename(filename)) + '.csv')

        self.filename = filename
        self.filename_roi = filename_roi
        self.filename_csv = filename_csv

        self.dat = nib.load(filename).get_data()
        self.shape = self.dat.shape
        print self.shape
        dz = self.shape[2]
        df = self.shape[-1]

        self.badenc = np.zeros((dz, df), dtype=np.int16)
        self.prev = np.zeros((dz, df), dtype=np.int16)
        self.z = 0

        self.initUI()
        self.run()

        #if filename_csv is not None and os.path.isfile(filename_csv):
        #    self.run_read()

    def reset(self):
        dz = self.shape[2]
        df = self.shape[-1]
        self.badenc[:, :] = np.zeros((dz, df), dtype=np.int16)
        self.prev[:, :] = np.zeros((dz, df), dtype=np.int16)

    def make_checkbox_all(self, frame, width=4, ncol=20):
        self.lst_checkbox_slices_values = []
        self.lst_checkbox_slices = []
        ii = 0

        for z in range(self.shape[2]):
            self.lst_checkbox_slices_values.append(
                [BooleanVar() for f in range(self.shape[3])])
            boxes = [
                Checkbutton(frame,
                            text=str('%s' % f),
                            variable=self.lst_checkbox_slices_values[z][f],
                            width=width) for f in range(self.shape[3])
            ]
            jj = 0
            for f in range(self.shape[3]):
                btn = boxes[f]
                btn.grid(row=z, column=f)
                jj += 1
                if ncol is not None and ncol <= jj:
                    ii += 1
                    jj = 0

            self.lst_checkbox_slices.append(boxes)
            if jj > 0:
                ii += 1

    def make_checkbox(self, frame, width=4, ncol=20):
        #self.lst_checkbox_slices_values = [BooleanVar() for f in range(self.shape[3])]
        self.lst_checkbox_slices_values = [
            IntVar() for f in range(self.shape[3])
        ]
        self.lst_checkbox_slices = [
            Checkbutton(frame,
                        text=str('%s' % f),
                        variable=self.lst_checkbox_slices_values[f],
                        width=width,
                        command=functools.partial(self.click_check, f))
            for f in range(self.shape[3])
        ]

        ii = 0
        jj = 0
        for f in range(self.shape[3]):
            btn = self.lst_checkbox_slices[f]
            btn.grid(row=ii, column=jj)
            jj += 1
            if ncol is not None and ncol <= jj:
                jj = 0
                ii += 1

        if jj > 0:
            ii += 1

    def click_check(self, f):
        value = self.lst_checkbox_slices_values[f].get()
        if value == 1:
            value = 0
        else:
            value = 1
        self.lst_checkbox_slices_values[f].set(value)
        self.badenc[self.z, f] = value
        print self.z, f, self.badenc[self.z, f]

    def set_z(self, z=None):
        if z is None:
            z = self.z
        else:
            self.z = z

        for i in range(len(self.lst_checkbox_slices_values)):
            chkbox = self.lst_checkbox_slices_values[i]
            # FIXME
            # avail chkbox
            if self.prev[z, i] > 0 or self.badenc[z, i] > 0:
                to_check = True
                to_check = 1
                self.lst_checkbox_slices[i].select()
            else:
                to_check = False
                to_check = 0
                self.lst_checkbox_slices[i].deselect()

            chkbox.set(to_check)
            # avail

    def run(self):
        dat = self.dat
        roi = nib.load(self.filename_roi).get_data().astype(bool)

        print dat.shape
        print roi.shape

        dz = self.shape[2]
        df = self.shape[3]

        self.values = np.zeros((dz, df), dtype=dat.dtype)
        for z in range(dz):
            for f in range(df):
                self.values[z, f] = dat[:, :, z, f][roi[:, :, z]].mean()

        self.draw_slice()

    def draw_slice(self):
        z = self.z
        df = self.shape[3]

        print z
        #r = self.frame_graph.axes.boxplot(self.values.T)

        sorted_values = np.sort(self.values[z, :])
        q1 = sorted_values[df / 4]
        q2 = sorted_values[df / 2]
        q3 = sorted_values[df - df / 4]
        iqr = q3 - q1
        #if1 = q1 - 1.5*iqr
        #if2 = q3 + 1.5*iqr
        of1 = q1 - 3 * iqr
        of2 = q3 + 3 * iqr

        xx = np.arange(df)
        z_mean = self.values[z, :].mean()
        z_std = self.values[z, :].std()
        #z_min  = self.values[z,:].min()
        #z_max  = self.values[z,:].max()

        #self.frame_graph.axes.hold(False)
        self.frame_graph.axes.clear()
        self.frame_graph.axes.plot([0, df], [z_mean, z_mean], 'k-')
        #self.frame_graph.axes.hold(True)
        self.frame_graph.axes.plot([0, df],
                                   [z_mean + 1 * z_std, z_mean + 1 * z_std],
                                   'y--')
        self.frame_graph.axes.plot([0, df],
                                   [z_mean + 2 * z_std, z_mean + 2 * z_std],
                                   'g--')
        self.frame_graph.axes.plot([0, df],
                                   [z_mean + 3 * z_std, z_mean + 3 * z_std],
                                   'b--')
        self.frame_graph.axes.plot([0, df], [of2, of2], 'r-')

        for f in range(df):
            if self.prev[z, f] > 0:
                self.frame_graph.axes.plot(f, self.values[z, f], 'ko')
                self.frame_graph.axes.text(f + 0.2, self.values[z, f], str(f))
            elif of1 < self.values[z, f] < of2:
                #if self.values[z,f] < z_mean + 3*z_std:
                self.frame_graph.axes.plot(f, self.values[z, f], 'bo')
                if self.values[z, f] > z_mean + 3 * z_std:
                    self.frame_graph.axes.text(f + 0.2, self.values[z, f],
                                               str(f))
            else:
                self.frame_graph.axes.plot(f, self.values[z, f], 'ro')
                self.frame_graph.axes.text(f + 0.2, self.values[z, f], str(f))

        self.frame_graph.draw()
        self.set_z(z)

    def run_read(self):
        filename = tkFileDialog.askopenfilename(initialdir=self.dirname)
        if filename == '':
            return

        with open(filename) as f:
            values = [[int(tmp) for tmp in line.strip().split(',')]
                      for line in f.readlines()]

        self.prev[:, :] = values

    def run_save(self):
        filename = tkFileDialog.asksaveasfilename(
            initialdir=os.path.dirname(self.filename_csv),
            initialfile=os.path.basename(self.filename_csv))
        if filename == '':
            return

        dz = self.shape[2]
        df = self.shape[-1]

        badenc = self.badenc.copy()
        badenc[self.prev > 0] = 1

        with open(filename, 'w') as f:
            for z in range(dz):
                f.write('%s\n' % (','.join([str(tmp)
                                            for tmp in badenc[z, :]])))

        with open(os.path.join(self.dirname, 'badenc.dat'), 'wb') as fout:
            if False:
                for z in range(dz):
                    row = struct.pack('i' * df, *badenc[z, :])
                    fout.write(row)

            fout.write('%s %s\n' % (dz, df))
            for z in range(dz):
                row = ' '.join(str(tmp) for tmp in badenc[z, :])
                fout.write('%s\n' % row)

        if self.obj_return_value is not None:
            self.obj_return_value.delete(0, len(self.obj_return_value.get()))
            self.obj_return_value.insert(0, filename)

    def initUI(self):
        self.frame_top = Frame(self)
        self.frame_graph = MplCanvas(self)
        self.frame_bottom = Frame(self)

        Label(self.frame_top, text='Z = ').pack(side=LEFT)
        self.spin_z = Spinbox(self.frame_top,
                              from_=0,
                              to=self.shape[2] - 1,
                              increment=1,
                              command=self.change_z)
        self.spin_z.pack(side=LEFT)
        self.make_checkbox(self.frame_bottom, width=4)

        Label(self.frame_top, text='   CSV').pack(side=LEFT)
        self.txt_filename_csv = Entry(self.frame_top)
        self.txt_filename_csv.pack(side=LEFT)
        self.button_read = Button(self.frame_top,
                                  text='Read',
                                  command=self.run_read)
        self.button_read.pack(side=LEFT)
        self.button_save = Button(self.frame_top,
                                  text='Save',
                                  command=self.run_save)
        self.button_save.pack(side=LEFT)

        Label(self.frame_top, text='   ').pack(side=LEFT)
        button_reset = Button(self.frame_top, text='Reset',
                              command=self.reset).pack(side=LEFT)

        self.frame_top.pack(side=TOP)
        self.frame_graph.get_tk_widget().pack(fill=BOTH, expand=TRUE)
        self.frame_bottom.pack(fill=BOTH, expand=TRUE)
        self.pack(fill=BOTH, expand=True)

    def change_z(self):
        self.z = int(self.spin_z.get())
        self.draw_slice()

    def reset_box(self, box, text):
        box.delete(0, len(box.get()))
        box.insert(0, text)
Пример #19
0
class CreateMask(Frame):
    def __init__(self,
                 parent,
                 filename=None,
                 dirname=None,
                 mask4d=False,
                 obj_return_value=None):
        Frame.__init__(self, parent)
        self.parent = parent
        self.obj_return_value = obj_return_value

        if dirname is None:
            self.dirname = ''
        else:
            self.dirname = dirname

        if filename is None or not os.path.isfile(filename):
            if dirname is not None:
                filename = tkFileDialog.askopenfilename(initialdir=dirname)
            else:
                filename = tkFileDialog.askopenfilename()

        if not os.path.isfile(filename):
            parent.destroy()
            return

        self.readImage(filename)
        _, _, filename_mask = create_mask.set_filenames(filename)
        self.filename_mask = filename_mask + '.nii.gz'

        if mask4d:
            if len(self.shape) > 3:
                self.mask_base = np.zeros(self.shape, dtype=np.int8)
                self.mask = self.mask_base[:, :, :, 0]
                self.mask4d = True
        else:
            self.mask = np.zeros(self.shape[:3], dtype=np.int8)
            self.mask4d = False
        self.volume = 0

        self.initUI()

        self.modifyUI()
        self.drawSlice()

    def initUI(self):
        self.frame_bottom = Frame(self)
        self.frame_main = Frame(self)

    def modifyUI(self):
        frame_bottom = self.frame_bottom
        frame_main = self.frame_main
        self.sliceView = [
            ImshowMplCanvas(frame_main) for k in range(self.shape[2])
        ]
        self.sliceSpin = [
            MySpinBox(frame_main, k) for k in range(self.shape[2])
        ]

        #Layout
        self.parent.title('CreateMask')

        max_spin = 0
        if self.mask4d:
            max_spin = self.shape[3] - 1
        self.spin_volume = Spinbox(frame_bottom,
                                   from_=0,
                                   to=max_spin,
                                   increment=1,
                                   command=self.change_volume,
                                   width=8)
        self.reset_box(self.spin_volume, 0)

        buttonMask = Button(frame_bottom,
                            text='B0 from Bval...',
                            command=self.createBaseImage)
        buttonMaskCreate = Button(frame_bottom,
                                  text='Create',
                                  command=self.createMaskAll)
        buttonSave = Button(frame_bottom, text='Save', command=self.saveMask)

        self.drawmask = BooleanVar()
        buttonDrawMask = Checkbutton(frame_bottom,
                                     text='Draw Mask',
                                     variable=self.drawmask,
                                     command=self.drawSlice)

        num_col = 3
        num_row = 6
        for col in range(self.shape[2] / num_row):
            for k in range(num_row):
                ind = col * num_row + k
                if ind >= self.shape[2]:
                    break
                self.sliceView[ind].get_tk_widget().grid(row=k,
                                                         column=col * num_col,
                                                         sticky=NSEW)
                self.sliceSpin[ind].grid(row=k, column=col * num_col + 1)
            self.frame_main.grid_columnconfigure(col * num_col, weight=1)

        for k in range(num_row):
            self.frame_main.grid_rowconfigure(k, weight=1)

        self.spin_volume.grid(row=0, column=0)
        buttonMask.grid(row=0, column=1)
        buttonMaskCreate.grid(row=0, column=2)
        buttonSave.grid(row=0, column=3)
        buttonDrawMask.grid(row=0, column=5)

        frame_bottom.pack(side=BOTTOM)
        frame_main.pack(fill=BOTH, expand=TRUE)
        self.pack(fill=BOTH, expand=True)

    def change_volume(self):
        if not self.mask4d:
            return

        self.volume = int(self.spin_volume.get())
        self.data = self.data_base[:, :, :, self.volume]
        self.mask = self.mask_base[:, :, :, self.volume]
        self.drawSlice()

    def saveMask(self):
        print 'save mask to %s' % self.filename_mask
        if self.mask4d:
            img_out = nib.Nifti1Image(self.mask_base, self.img.get_affine(),
                                      self.img.get_header())
        else:
            img_out = nib.Nifti1Image(self.mask, self.img.get_affine(),
                                      self.img.get_header())
        nib.save(img_out, os.path.join(self.dirname, self.filename_mask))

        if self.obj_return_value is not None:
            self.obj_return_value.delete(0, len(self.obj_return_value.get()))
            self.obj_return_value.insert(0,
                                         os.path.basename(self.filename_mask))

    def readImage(self, filename):
        self.filename = filename
        self.img = nib.load(filename)
        self.shape = self.img.shape
        self.data_base = self.img.get_data()
        if len(self.data_base.shape) > 3:
            for f in range(self.data_base.shape[3]):
                for z in range(self.data_base.shape[2]):
                    self.data_base[:, :, z, f] = ndimage.gaussian_filter(
                        self.data_base[:, :, z, f], sigma=0.5)
            self.data = self.data_base[:, :, :, 0]
        else:
            for z in range(self.data_base.shape[2]):
                self.data_base[:, :, z] = ndimage.gaussian_filter(
                    self.data_base[:, :, z], sigma=0.5)
            self.data = self.data_base

    def createBaseImage(self):
        bvalFilename = tkFileDialog.askopenfilename()
        if bvalFilename:
            b0frames = parameter.get_b0_from_bval(bvalFilename)
            print self.filename, b0frames
            filename, filename_fltd, filename_mask = create_mask.set_filenames(
                self.filename)
            create_mask.make_base_image(filename, filename_fltd + '.nii.gz',
                                        b0frames)

            self.filename_mask = filename_mask + '.nii.gz'
            self.readImage(filename_fltd + '.nii.gz')
            self.drawSlice()

    def setSpinBoxConnect(self):
        for k in range(self.shape[2]):
            #self.sliceSpin[k].valueChanged.connect(lambda: self.createMaskSlice(k))
            #self.sliceSpin[k].configure(command=lambda:self.createMaskSlice(k, self.sliceSpin[k]))
            self.sliceSpin[k].configure(command=functools.partial(
                self.createMaskSlice, k, self.sliceSpin[k]))

    def drawSlice(self):
        for k in range(self.shape[2]):
            self.sliceView[k].drawData(self.data[:, :, k], self.mask[:, :, k],
                                       self.drawmask.get())

    def reset_box(self, box, text):
        box.delete(0, len(box.get()))
        box.insert(0, text)

    def createMaskSlice(self, k, value=None):
        self.mask[:, :, k] = 0
        if value is None:
            value_i = int(self.sliceSpin[k].get())
        else:
            value_i = int(value.get())
        #create_mask.mask_from_threshold(self.com_x[k], self.com_y[k], self.sliceSpin[k].value(), self.data, self.mask, k)
        create_mask.mask_from_threshold(self.com_x[k], self.com_y[k], value_i,
                                        self.data, self.mask, k)
        self.sliceView[k].drawData(self.data[:, :, k], self.mask[:, :, k],
                                   self.drawmask.get())

    def createMaskAll(self):
        self.drawmask.set(True)
        hdr = self.img.get_header()
        zooms = hdr.get_zooms()
        shape = self.shape

        self.com_x, self.com_y, roi_x, roi_y = create_mask.calculate_com(
            self.data, zooms)

        for k in range(shape[2]):
            dat_subflt = self.data[roi_x[k][0]:roi_x[k][1],
                                   roi_y[k][0]:roi_y[k][1], k].flatten()

            #threshold = np.mean(dat_subflt)
            threshold = np.mean(dat_subflt) + np.std(dat_subflt)
            self.reset_box(self.sliceSpin[k], int(threshold))
            self.createMaskSlice(k)
            #create_mask.mask_from_threshold(self.com_x[k], self.com_y[k], threshold, self.data, self.mask, k)

        #self.drawSlice()
        self.setSpinBoxConnect()
Пример #20
0
class pump_ui(object):
    def __init__(self):
        master = Tk()
        master.style = ttk.Style()
        master.style.theme_use("default")
        master.config(bg=background_colour)
        master.resizable(
            0, 0
        )  # Disable resizing the UI to prevent having to make widget placing dynamic
        master.winfo_toplevel().title(frame_title)
        master.iconbitmap("bitcoin.ico")

        # Create pumper assistant to store data on the current BTC and alt holdings.
        self.pumper = pumper()

        self.create_title(master)
        self.create_api_info(master, previous_row=0)
        self.create_auto_sell(master, previous_row=3)
        self.create_stop_loss(master, previous_row=4)
        self.create_order_type(master, previous_row=6)
        self.create_fee_type(master, previous_row=7)
        self.create_btc_balance_picker(master, previous_row=8)
        self.create_alt_ticker(master, previous_row=10)
        self.create_pump_and_sell_buttons(master, previous_row=11)
        self.create_current_profit(master, previous_row=12)

        self.create_output_box(master, rightmost_column=1)

        # Can hardcode API key and Secret
        #self.api_key_entry.delete(0,END)
        #self.api_key_entry.insert(0,"KEY")
        #self.api_key_entry.config(state=DISABLED)
        #self.api_secret_entry.delete(0, END)
        #self.api_secret_entry.insert(0, "SECRET")
        #self.api_secret_entry.config(state=DISABLED)

        # Display the UI, this can only be called once per program.
        # Nothing in the main Python script will be run after creating the UI because of this.
        master.mainloop()

    def create_title(self, master, previous_row=-1, previous_column=-1):
        empty = Label(master, text=frame_title)
        empty.grid(row=previous_row + 1,
                   column=previous_column + 2,
                   columnspan=1)
        empty.config(bg=background_colour, fg=label_font_colour)

    def create_api_info(self, master, previous_row=-1, previous_column=-1):
        api_key_lbl = Label(master, text="API Key:")
        api_key_lbl.grid(row=previous_row + 1,
                         column=previous_column + 1,
                         columnspan=1,
                         sticky=E,
                         padx=(3, 0))
        api_key_lbl.config(bg=background_colour, fg=label_font_colour)

        self.api_key_entry = Entry(master,
                                   highlightthickness=0,
                                   bd=0,
                                   width=21,
                                   show="*")
        self.api_key_entry.config(borderwidth=2, relief=default_relief)
        self.api_key_entry.grid(row=previous_row + 1,
                                column=previous_column + 2)

        api_secret_lbl = Label(master, text="API Secret:")
        api_secret_lbl.grid(row=previous_row + 2,
                            column=previous_column + 1,
                            columnspan=1,
                            sticky=E,
                            padx=(3, 0))
        api_secret_lbl.config(bg=background_colour, fg=label_font_colour)

        self.api_secret_entry = Entry(master,
                                      highlightthickness=0,
                                      bd=0,
                                      width=21,
                                      show="*")
        self.api_secret_entry.config(borderwidth=2, relief=default_relief)
        self.api_secret_entry.grid(row=previous_row + 2,
                                   column=previous_column + 2)

        self.api_connect_btn = Button(master,
                                      text="Connect To Binance",
                                      command=self.on_connect_api)
        self.api_connect_btn.grid(row=previous_row + 3,
                                  column=previous_column + 2,
                                  columnspan=1,
                                  sticky=W + E,
                                  padx=10,
                                  pady=(0, 3))
        self.api_connect_btn.config(highlightbackground=background_colour)

    def create_auto_sell(self, master, previous_row=-1, previous_column=-1):
        auto_sell_lbl = Label(master, text="Auto Sell (%):")
        auto_sell_lbl.grid(row=previous_row + 1,
                           column=previous_column + 1,
                           columnspan=1,
                           sticky=E,
                           padx=(3, 0))
        auto_sell_lbl.config(bg=background_colour, fg=label_font_colour)

        self.auto_sell_spinbox = Spinbox(master,
                                         from_=1.0,
                                         to=300.0,
                                         increment=1.0,
                                         highlightbackground=background_colour)
        self.auto_sell_spinbox.config(borderwidth=2, relief=default_relief)
        self.auto_sell_spinbox.grid(row=previous_row + 1,
                                    column=previous_column + 2)
        self.auto_sell_spinbox.delete(0, "end")
        self.auto_sell_spinbox.insert(0, 50)

    def create_stop_loss(self, master, previous_row=-1, previous_column=-1):
        stop_loss_lbl = Label(master, text="Stop Loss (%):")
        stop_loss_lbl.grid(row=previous_row + 1,
                           column=previous_column + 1,
                           columnspan=1,
                           sticky=E,
                           padx=(3, 0))
        stop_loss_lbl.config(bg=background_colour, fg=label_font_colour)

        self.stop_loss_spinbox = Spinbox(master,
                                         from_=-100.0,
                                         to=-10.0,
                                         increment=1.0,
                                         highlightbackground=background_colour)
        self.stop_loss_spinbox.config(borderwidth=2, relief=default_relief)
        self.stop_loss_spinbox.grid(row=previous_row + 1,
                                    column=previous_column + 2)
        self.stop_loss_spinbox.delete(0, "end")
        self.stop_loss_spinbox.insert(0, -10)

    def create_btc_balance_picker(self,
                                  master,
                                  previous_row=-1,
                                  previous_column=-1):
        self.btc_balance_str = StringVar()
        btc_balance_lbl = Label(master, textvar=self.btc_balance_str)
        btc_balance_lbl.grid(row=previous_row + 1,
                             column=previous_column + 1,
                             columnspan=2,
                             sticky=W + E,
                             padx=(3, 0))
        btc_balance_lbl.config(bg=background_colour, fg=label_font_colour)
        self.set_available_btc_balance(Decimal(0))

        btc_to_use_label = Label(master,
                                 text="BTC to spend:",
                                 bg=background_colour,
                                 fg=label_font_colour)
        btc_to_use_label.grid(row=previous_row + 2,
                              column=previous_column + 1,
                              sticky=E,
                              padx=(3, 0))

        self.btc_to_use_spinbox = Spinbox(
            master,
            from_=minimum_trade,
            to=minimum_trade,
            increment=btc_to_use_increment,
            highlightbackground=background_colour)
        self.btc_to_use_spinbox.config(borderwidth=2, relief=default_relief)
        self.btc_to_use_spinbox.grid(row=previous_row + 2,
                                     column=previous_column + 2)

    def create_order_type(self, master, previous_row=-1, previous_column=-1):
        order_type_lbl = Label(master, text="Entry Type:")
        order_type_lbl.grid(row=previous_row + 1,
                            column=previous_column + 1,
                            sticky=E,
                            padx=(3, 0))
        order_type_lbl.config(bg=background_colour, fg=label_font_colour)

        self.is_entry_market = True

        def change_order_type(*args):
            self.is_entry_market = (self.order_type.get() == "Market Buy  \/")

        self.order_type = StringVar()
        self.order_type.trace(
            "w", change_order_type
        )  # Reduces how much work is done when the pump starts
        choices = {"Market Buy  \/", "Limit Buy     \/"}
        self.entry_type_option_menu = OptionMenu(master, self.order_type,
                                                 *choices)
        self.entry_type_option_menu.grid(row=previous_row + 1,
                                         column=previous_column + 2,
                                         sticky=W + E,
                                         padx=8)
        self.entry_type_option_menu.config(highlightthickness=0)
        self.entry_type_option_menu.configure(indicatoron=0)
        self.order_type.set("Market Buy  \/")

    def create_fee_type(self, master, previous_row=-1, previous_column=-1):
        fee_type_lbl = Label(master, text="Fee Type:")
        fee_type_lbl.grid(row=previous_row + 1,
                          column=previous_column + 1,
                          sticky=E,
                          padx=(3, 0))
        fee_type_lbl.config(bg=background_colour, fg=label_font_colour)

        self.is_using_bnb = True

        def change_fee_type(*args):
            self.is_using_bnb = (
                self.order_type.get() == "Binance Coin (BNB) \/")

        self.fee_type = StringVar()
        self.fee_type.trace(
            "w", change_fee_type
        )  # Reduces how much work is done when the pump starts
        choices = {"Binance Coin (BNB) \/", "0.1% Of All Trades    \/"}
        self.fee_type_option_menu = OptionMenu(master, self.fee_type, *choices)
        self.fee_type_option_menu.grid(row=previous_row + 1,
                                       column=previous_column + 2,
                                       sticky=W + E,
                                       padx=8)
        self.fee_type_option_menu.config(highlightthickness=0)
        self.fee_type_option_menu.configure(indicatoron=0)
        self.fee_type.set("Binance Coin (BNB) \/")

    def create_pump_and_sell_buttons(self,
                                     master,
                                     previous_row=-1,
                                     previous_column=-1):
        # Manual sell button can only be activated after initiating a pump.
        self.manual_sell_btn = Button(master,
                                      text="Sell",
                                      state=DISABLED,
                                      command=self.on_manual_sell)
        self.manual_sell_btn.grid(row=previous_row + 1,
                                  column=previous_column + 1,
                                  sticky=W + E,
                                  padx=(3, 0))
        self.manual_sell_btn.config(highlightbackground=background_colour)

        self.pump_btn = Button(master, text="Pump", command=self.on_pump)
        self.pump_btn.grid(row=previous_row + 1,
                           column=previous_column + 2,
                           sticky=W + E,
                           padx=8)
        self.pump_btn.config(highlightbackground=background_colour,
                             state=DISABLED)

    def create_alt_ticker(self, master, previous_row=-1, previous_column=-1):
        ticker_lbl = Label(master, text="Ticker To Pump:")
        ticker_lbl.grid(row=previous_row + 1,
                        column=previous_column + 1,
                        columnspan=1,
                        sticky=E,
                        padx=(3, 0),
                        pady=(0, 8))
        ticker_lbl.config(bg=background_colour, fg=label_font_colour)

        self.ticker_entry = Entry(master, highlightthickness=0, bd=0, width=21)
        self.ticker_entry.config(borderwidth=2, relief=default_relief)
        self.ticker_entry.grid(row=previous_row + 1,
                               column=previous_column + 2,
                               pady=8)
        self.ticker_entry.bind('<Return>', self.on_pump_shortcut)

    def create_current_profit(self,
                              master,
                              previous_row=-1,
                              previous_column=-1):
        self.current_profit_str = StringVar()
        current_profit_lbl = Label(master, textvar=self.current_profit_str)
        current_profit_lbl.grid(row=previous_row + 1,
                                column=previous_column + 1,
                                columnspan=2,
                                sticky=W + E,
                                padx=3,
                                pady=(0, 3))
        current_profit_lbl.config(bg=background_colour, fg=label_font_colour)
        self.current_profit_str.set("Current Profit: 0%")

    def create_output_box(self, master, rightmost_column):
        self.pump_output = StringVar()
        console_lbl = Label(master,
                            textvar=self.pump_output,
                            borderwidth=2,
                            relief=default_relief,
                            anchor=N)
        console_lbl.grid(row=0,
                         column=rightmost_column + 1,
                         columnspan=1,
                         rowspan=14,
                         padx=(10, 0),
                         pady=0)
        console_lbl.config(width=50,
                           height=22,
                           bg="black",
                           font=Font(family="Courier", size=9),
                           fg="white")
        self.lines = 0

    def disable_pre_pump_options(self):
        # Change the buttons that can be clicked to prevent the user
        # from trying to pump multiple coins with one bot.
        self.manual_sell_btn.config(state=NORMAL)
        self.pump_btn.config(state=DISABLED)
        self.btc_to_use_spinbox.config(state=DISABLED)
        self.ticker_entry.config(state=DISABLED)
        self.auto_sell_spinbox.config(state=DISABLED)
        self.stop_loss_spinbox.config(state=DISABLED)
        self.api_key_entry.config(
            state=DISABLED)  # Comment out if hardcoding key
        self.api_secret_entry.config(
            state=DISABLED)  # Comment out if hardcoding secret
        self.api_connect_btn.config(state=DISABLED)
        self.entry_type_option_menu.config(state=DISABLED)
        self.fee_type_option_menu.config(state=DISABLED)

    def enable_pump_options(self):
        # Change the buttons that can be clicked to prevent the user
        # from trying to pump multiple coins with one bot.
        self.manual_sell_btn.config(state=DISABLED)
        self.pump_btn.config(state=NORMAL)
        self.btc_to_use_spinbox.config(state=NORMAL)
        self.ticker_entry.config(state=NORMAL)
        self.auto_sell_spinbox.config(state=NORMAL)
        self.stop_loss_spinbox.config(state=NORMAL)
        self.api_key_entry.config(
            state=NORMAL)  # Comment out if hardcoding key
        self.api_secret_entry.config(
            state=NORMAL)  # Comment out if hardcoding secret
        self.api_connect_btn.config(state=NORMAL)
        self.entry_type_option_menu.config(state=NORMAL)
        self.fee_type_option_menu.config(state=NORMAL)

    def set_available_btc_balance(self, btc_balance):
        self.pumper.btc_balance = btc_balance
        self.btc_balance_str.set("Available Balance: " +
                                 readable_btc_balance(btc_balance))

    def set_current_profit(self, current_profit):
        self.current_profit_str.set(
            "Current Profit: " +
            '{0:.3f}'.format(round(current_profit * Decimal(100), 3)) + "%")

    def write_to_console(self, line):
        self.lines += 1
        if self.lines > max_lines_in_console:
            i = self.pump_output.get().index('\n')
            self.pump_output.set(self.pump_output.get()[i + 1:] + "\n" + line)
        elif self.lines == 1:
            self.pump_output.set(line)
        else:
            self.pump_output.set(self.pump_output.get() + "\n" + line)

    #### Button Behaviour ####
    def on_pump(self):
        try:
            api = self.api
            btc_to_use = Decimal(self.btc_to_use_spinbox.get())
        except InvalidOperation:
            # The BTC to spend box is empty.
            self.write_to_console("Stop!")
            self.write_to_console("BTC to spend cannot be empty.")
            return
        except AttributeError:
            # There is no API object.
            self.write_to_console(
                "You need to connect to Binance before pumping.")
            return

        if btc_to_use >= minimum_trade:
            if btc_to_use <= self.pumper.btc_balance:
                target_profit_percentage = Decimal(
                    float(self.auto_sell_spinbox.get()) / 100.0)

                # Validate auto-sell and stop loss
                if target_profit_percentage <= Decimal(0):
                    self.write_to_console("Auto sell has to be positive.")
                    return
                if Decimal(self.stop_loss_spinbox.get()) >= Decimal(0):
                    self.write_to_console("Stop loss has to be negative.")
                    return

                ticker = self.ticker_entry.get().upper()

                # Empty strings are False in Python
                if ticker:
                    full_ticker = api.full_ticker_for(ticker)

                    try:
                        alt = self.api.get_ticker(symbol=full_ticker)
                    except BinanceAPIException, e:
                        logging.debug(str(e))
                        self.write_to_console("Invalid ticker.")
                        return

                    alt_value = Decimal(alt["askPrice"])

                    # Used in console output
                    decimal_points = minimum_decimals_in_quantity.get(
                        full_ticker, 0)
                    self.pumper.decimal_points_in_alt = decimal_points

                    self.pumper.set_up(btc_to_use, target_profit_percentage,
                                       alt_value, ticker)
                    if self.is_entry_market:
                        self.pumper.alt_holdings = api.market_buy(
                            self.pumper.btc_to_use, full_ticker,
                            self.is_using_bnb)
                        self.write_to_console(
                            "Bought " + readable_alt_balance(
                                decimal_points, pumper=self.pumper) +
                            " with " + readable_btc_balance(btc_to_use) + ".")
                    else:
                        highest_bid = Decimal(alt["bidPrice"])

                        if alt_value - highest_bid <= Decimal(0.00000001):
                            to_bid = highest_bid
                        else:
                            # Bid between the highest bid and the lowest ask for the best odds of being filled.
                            to_bid = (alt_value -
                                      highest_bid) / 2 + highest_bid
                            to_bid = Decimal(
                                floor(to_bid * Decimal(100000000.0))
                            ) / Decimal(100000000.0)
                        self.pumper.starting_alt_value = to_bid

                        expected = api.limit_buy(
                            btc_to_alt(btc_to_use, alt_value), pumper,
                            full_ticker, to_bid, self.is_using_bnb)
                        self.write_to_console("Buying " + readable_alt_balance(
                            decimal_points, alt_amount=expected, ticker=ticker
                        ) + " for " + readable_btc_balance(btc_to_use) + ".")
                        self.write_to_console(
                            "This is a limit order, it may not get filled.")

                    self.disable_pre_pump_options()
                    self.set_stop_loss()
                    self.start_monitoring_orderbook(full_ticker)
                else:
                    # The user is trying to trade with more than they actually have.
                    self.write_to_console("You did not enter a ticker.")
            else:
                # The user is trying to trade with more than they actually have.
                self.write_to_console("Stop!")
                self.write_to_console(
                    "You are trying to spend more BTC than you have.")
        else:
Пример #21
0
class Temperatures(LabelFrame):
	def __init__(self, root, prtr, settings, log, *arg):
		LabelFrame.__init__(self, root, *arg, text="Temperatures")
		self.app = root
		self.printer = prtr
		self.settings = settings
		self.log = log

		l = Label(self, text="Extruder:", justify=LEFT)
		l.grid(row=1, column=1, sticky=W)
		
		self.statExt = Canvas(self, width=150, height=STAT_HEIGHT, bd=2, bg="white", relief=RIDGE)
		self.statExt.grid(row=1, column=2, columnspan=2)
		self.setStatus(self.statExt, UNKNOWN)
		
		self.bSetExt = Button(self, text="Set", width=4, command=self.doSetExt)
		self.bSetExt.grid(row=2, column=1, padx=2)
		
		self.spExtTemp = Spinbox(self, values=self.formatTemps(self.settings.extemps), width=12, justify=RIGHT)
		self.spExtTemp.grid(row=2, column=2)
		if self.settings.lastexttemp != None:
			self.spExtTemp.delete(0, END)
			self.spExtTemp.insert(0, self.settings.lastexttemp)
		self.spExtTemp.bind("<FocusOut>", self.valExtTemp)
		self.spExtTemp.bind("<Leave>", self.valExtTemp)

		self.bOffExt = Button(self, text="Off", width=4, command=self.doOffExt)
		self.bOffExt.grid(row=2, column=3, padx=2)
		
		self.frameExt = Frame(self)
		self.frameExt.grid(row=3, column=1, columnspan=3)
		
		self.legendExt = Canvas(self.frameExt, width=LEGEND_WIDTH, height=100, bd=2, bg="white", relief=RIDGE)
		self.legendExt.pack(side=LEFT, padx=0, pady=2)
		
		self.canvasExt = Canvas(self.frameExt, width=200, height=100, bd=2, bg="white", relief=RIDGE)
		self.canvasExt.pack(side=LEFT, padx=0, pady=2)
		self.drawExtAxes()
		
		self.extFan = IntVar()
		if self.settings.fanwithextruder:
			self.extFan.set(1)
		else:
			self.extFan.set(0)
			
		self.cb = Checkbutton(self, text="Fan on with extruder", variable=self.extFan, command=self.fanCheck)
		self.cb.grid(row=4, column=1, columnspan=3)

		self.forceExtTemp = IntVar()
		if self.settings.forceexttemp:
			self.forceExtTemp.set(1)
		else:
			self.forceExtTemp.set(0)
		self.forceExtTempCheck()
		self.bForceExt = Checkbutton(self, text="Force Ext Temp", variable=self.forceExtTemp, command=self.forceExtTempCheck)
		self.bForceExt.grid(row=5, column=1, columnspan=3)

		l = Label(self, text="Bed:", justify=LEFT)
		l.grid(row=6, column=1, sticky=W)

		self.statBed = Canvas(self, width=150, height=STAT_HEIGHT, bd=2, bg="white", relief=RIDGE)
		self.statBed.grid(row=6, column=2, columnspan=2)
		self.setStatus(self.statBed, UNKNOWN)

		self.bSetBed = Button(self, text="Set", width=4, command=self.doSetBed)
		self.bSetBed.grid(row=7, column=1, padx=2)
		
		self.spBedTemp = Spinbox(self, values=self.formatTemps(self.settings.bedtemps), width=12, justify=RIGHT)
		self.spBedTemp.grid(row=7, column=2)
		if self.settings.lastbedtemp != None:
			self.spBedTemp.delete(0, END)
			self.spBedTemp.insert(0, self.settings.lastbedtemp)
		self.spBedTemp.bind("<FocusOut>", self.valBedTemp)
		self.spBedTemp.bind("<Leave>", self.valBedTemp)
		
		self.bOffBed = Button(self, text="Off", width=4, command=self.doOffBed)
		self.bOffBed.grid(row=7, column=3, padx=2)
		
		self.frameBed = Frame(self)
		self.frameBed.grid(row=8, column=1, columnspan=3)
		
		self.legendBed = Canvas(self.frameBed, width=LEGEND_WIDTH, height=100, bd=2, bg="white", relief=RIDGE)
		self.legendBed.pack(side=LEFT, padx=0, pady=2)
		
		self.canvasBed = Canvas(self.frameBed, width=200, height=100, bd=2, bg="white", relief=RIDGE)
		self.canvasBed.pack(side=LEFT, padx=0, pady=2)
		self.drawBedAxes()
		
		self.dataBed = []
		self.dataExt = []
		
		self.forceBedTemp = IntVar()
		if self.settings.forcebedtemp:
			self.forceBedTemp.set(1)
		else:
			self.forceBedTemp.set(0)
		self.forceBedTempCheck()
		self.bForceBed = Checkbutton(self, text="Force Bed Temp", variable=self.forceBedTemp, command=self.forceBedTempCheck)
		self.bForceBed.grid(row=9, column=1, columnspan=3)
		
		self.monTemp = IntVar()
		self.monTemp.set(1)
		self.monCheck()
		self.cb = Checkbutton(self, text="Monitor temperatures", variable=self.monTemp, command=self.monCheck)
		self.cb.grid(row=10, column=1, columnspan=3)
		
		self.rptre = re.compile("ok *T:([0-9\.]+) *\/([0-9\.]+) *B:([0-9\.]+) *\/([0-9\.]+)")
	
	def fanCheck(self):
		self.settings.fanwithextruder = (self.extFan.get() == 1)
		self.settings.setModified()
	
	def forceBedTempCheck(self):
		if self.forceBedTemp.get() == 1:
			if not self.settings.forcebedtemp:
				self.settings.forcebedtemp = True
				self.settings.setModified()
		else:
			if self.settings.forcebedtemp:
				self.settings.forcebedtemp = False
				self.settings.setModified()
				
	def forceExtTempCheck(self):
		if self.forceExtTemp.get() == 1:
			if not self.settings.forceexttemp:
				self.settings.forceexttemp = True
				self.settings.setModified()
		else:
			if self.settings.forceexttemp:
				self.settings.forceexttemp = False
				self.settings.setModified()
				
	def monCheck(self):
		if self.monTemp.get() == 1:
			self.app.monitorTemp = True
			self.printer.tempcb = self.tempcb
		else:
			self.app.monitorTemp = False
			self.dataBed = []
			self.canvasBed.delete("GRAPH")
			self.canvasBed.delete("TARGET")
			self.dataExt = []
			self.canvasExt.delete("GRAPH")
			self.canvasExt.delete("TARGET")
			self.printer.tempcb = None

			self.setStatus(self.statExt, UNKNOWN)
			self.setStatus(self.statBed, UNKNOWN)
			
	def tempcb(self, l):
		m = self.rptre.search(l)
		t = m.groups()
		if len(t) != 4: return
		
		self.app.exttemp = float(t[0])
		if self.settings.forceexttemp:
			tp = float(t[1])
			if tp >= 0.05 and tp < self.app.exttarget:
				self.log.logMsg("Asserting hot end temperature of %.2f" % self.app.exttarget)
				self.printer.send_now("M104 S%s" % self.app.exttarget)
			else:
				self.app.exttarget = tp
		else:
			self.app.exttarget = float(t[1])
			
		self.app.bedtemp = float(t[2])
		if self.settings.forcebedtemp:
			tp = float(t[3])
			if tp >= 0.05 and tp < self.app.bedtarget:
				self.log.logMsg("Asserting bed temperature of %.2f" % self.app.bedtarget)
				self.printer.send_now("M140 S%s" % self.app.bedtarget)
			else:
				self.app.bedtarget = tp
		else:
			self.app.bedtarget = float(t[3])
			
		self.updateTempDisplay(float(t[2]), float(t[0]))
		
	def updateTempDisplay(self, tBed, tExt):
		self.addBedDatapoint(tBed)
		self.addExtDatapoint(tExt)
		
		if self.app.exttarget < 0.05:
			# unit is off
			if self.app.exttemp > 35:
				self.setStatus(self.statExt, COOLING)
			else:
				self.setStatus(self.statExt, COOL)
		else:
			# unit is on
			if self.app.exttarget - self.app.exttemp < 0.05:
				self.setStatus(self.statExt, HOT)
			else:
				self.setStatus(self.statExt, HEATING)
		
		if self.app.bedtarget < 0.05:
			# unit is off
			if self.app.bedtemp > 35:
				self.setStatus(self.statBed, COOLING)
			else:
				self.setStatus(self.statBed, COOL)
		else:
			# unit is on
			if self.app.bedtarget - self.app.bedtemp < 0.05:
				self.setStatus(self.statBed, HOT)
			else:
				self.setStatus(self.statBed, HEATING)

	def formatTemps(self, t):
		def cmptemp(a, b):
			ta = int(a.split()[0])
			tb = int(b.split()[0])
			return cmp(ta, tb)
		
		result = [x for x in t]
			
		return sorted(result, cmptemp)
		
	def doSetExt(self):
		if self.app.printerAvailable(cmd="M104"):
			if self.settings.fanwithextruder and self.app.FanSpeed != 255:
				if self.settings.forcefanspeed:
					self.logger.logMsg("Asserting fan speed of %d" % self.app.FanSpeed)
				else:
					self.app.toolbar.setFanSpeed(255)
			temp = self.spExtTemp.get().split(' ')[0]
			self.printer.send_now("M104 S%s" % temp)
			self.app.exttarget = float(temp)
		
	def valExtTemp(self, *arg):
		invalid = False
		try:
			choice = self.spExtTemp.get()
			x = int(choice.split(' ')[0])
		except:
			self.log.logMsg("Value for Extruder temperature not a valid integer")
			invalid = True
		else:
			if x <=0 or x >MAXEXTTEMP:
				self.log.logMsg("Value for Extruder temperature out of range(0-%d" % MAXEXTTEMP)
				invalid = True
			
		if invalid:
			self.spExtTemp.delete(0, END)
			self.spExtTemp.insert(0, "%s" % self.formatTemps(self.settings.extemps)[0])
		else:
			if choice not in self.settings.extemps:
				self.settings.extemps.append(choice)
				self.settings.setModified()
				self.spExtTemp.config(values=self.formatTemps(self.settings.extemps))
				self.spExtTemp.delete(0, END)
				self.spExtTemp.insert(0, choice)
				
			if self.settings.lastexttemp != choice:
				self.settings.lastexttemp = choice
				self.settings.setModified()

		return True
		
	def doOffExt(self, *arg):
		if self.app.printerAvailable(cmd="M104"):
			if self.settings.fanwithextruder and self.app.FanSpeed != 0:
				if self.settings.forcefanspeed:
					self.logger.logMsg("Asserting fan speed of %d" % self.app.FanSpeed)
				else:
					self.app.toolbar.setFanSpeed(0)
			self.printer.send_now("M104 S0")

	def drawExtAxes(self):
		self.canvasExt.delete("AXES")
		for i in range(0, MAXEXTTEMP, 50):
			y = 100.0-(float(i)/MAXEXTTEMP*100.0)
			self.canvasExt.create_line(0, y, 200, y, fill="#C0C0C0", tags="AXES")
			self.legendExt.create_text(LEGEND_WIDTH, y+7, anchor=SE, tags="AXES", text="%3d" % i)
	
	def addExtDatapoint(self, t):
		c = (t/MAXEXTTEMP)*100.0
		self.dataExt.append(c)
		while len(self.dataExt) >= MAXDATAPOINTS:
			del(self.dataExt[0])
			
		self.canvasExt.delete("TARGET")
		self.canvasExt.delete("GRAPH")
		target = int((self.app.exttarget/MAXEXTTEMP)*100.0)
		if target != 0:
			self.canvasExt.create_line(0, 100-target, 200, 100-target, fill="blue", tags="TARGET")
			self.canvasExt.create_text(10, 100-target, anchor=SW, tags="TARGET", fill="blue", text="%3.3d" % int(self.app.exttarget))
		start = MAXDATAPOINTS - len(self.dataExt)
		pTemp = 0
		for i in range(start, MAXDATAPOINTS):
			if i != start:
				self.canvasExt.create_line(i*5, 100-pTemp, (i+1)*5, 100-self.dataExt[i-start], fill="red", tags="GRAPH")
			pTemp = self.dataExt[i-start]
		self.canvasExt.create_text(190, 100-c, anchor=SE, tags="GRAPH", fill="red", text="%3.3d" % int(t))
			
	def setStatus(self, w, status):
		if status == UNKNOWN:
			c = "black"
			s = "??"
		elif status == HEATING:
			c = "orange"
			s = "heating"
		elif status == HOT:
			c = "red"
			s = "hot"
		elif status == COOLING:
			c = "blue"
			s = "cooling"
		elif status == COOL:
			c = "green"
			s = "cool"
		else:
			c = "black"
			s = "??"
			
		w.config(bg=c)
		w.delete(ALL)
		w.create_text(75, STAT_HEIGHT-5, text=s, fill="white")
		
	def doSetBed(self):
		if self.app.printerAvailable(cmd="M140"):
			temp = self.spBedTemp.get().split(' ')[0]
			self.printer.send_now("M140 S%s" % temp)
			self.app.bedtarget = float(temp)
		
	def valBedTemp(self, *arg):
		invalid = False
		try:
			choice = self.spBedTemp.get()
			x = int(choice.split(' ')[0])
		except:
			self.log.logMsg("Value for Bed temperature not a valid integer")
			invalid = True
		else:
			if x <=0 or x >MAXEXTTEMP:
				self.log.logMsg("Value for Bed temperature out of range(0-%d" % MAXBEDTEMP)
				invalid = True
			
		if invalid:
			self.spBedTemp.delete(0, END)
			self.spBedTemp.insert(0, "%s" % self.formatTemps(self.settings.bedtemps)[0])
		else:
			if choice not in self.settings.bedtemps:
				self.settings.bedtemps.append(choice)
				self.settings.setModified()
				self.spBedTemp.config(values=self.formatTemps(self.settings.bedtemps))
				self.spBedTemp.delete(0, END)
				self.spBedTemp.insert(0, choice)
				
			if self.settings.lastbedtemp != choice:
				self.settings.lastbedtemp = choice
				self.settings.setModified()

		return True
				
	def doOffBed(self, *arg):
		if self.app.printerAvailable(cmd="M140"):
			self.printer.send_now("M140 S0")
			
	def addBedDatapoint(self, t):
		c = (t/MAXBEDTEMP)*100.0
		self.dataBed.append(c)
		while len(self.dataBed) >= MAXDATAPOINTS:
			del(self.dataBed[0])

		self.canvasBed.delete("TARGET")
		self.canvasBed.delete("GRAPH")
		target = int((self.app.bedtarget/MAXBEDTEMP)*100.0)
		if target != 0:
			self.canvasBed.create_line(0, 100-target, 200, 100-target, fill="blue", tags="TARGET")
			self.canvasBed.create_text(10, 100-target, anchor=SW, tags="TARGET", fill="blue", text="%3.3d" % int(self.app.bedtarget))
		start = MAXDATAPOINTS - len(self.dataBed)
		pTemp = 0
		for i in range(start, MAXDATAPOINTS):
			if i != start:
				self.canvasBed.create_line((i-1)*5, 100-pTemp, i*5, 100-self.dataBed[i-start], fill="red", tags="GRAPH")
			pTemp = self.dataBed[i-start]
		self.canvasBed.create_text(190, 100-c, anchor=SE, tags="GRAPH", fill="red", text="%3.3d" % int(t))

	def drawBedAxes(self):
		self.canvasBed.delete("AXES")
		for i in range(0, MAXBEDTEMP, 50):
			y = 100.0-(float(i)/MAXBEDTEMP*100.0)
			self.canvasBed.create_line(0, y, 200, y, fill="#C0C0C0", tags="AXES")
			self.legendBed.create_text(LEGEND_WIDTH, y+7, anchor=SE, tags="AXES", text="%3d" % i)
Пример #22
0
class ToolBar(Frame):
	def __init__(self, root, printer, settings, logger, *arg):
		self.app = root
		self.printer = printer
		self.settings = settings
		self.logger = logger
		
		self.app.printing = False
		self.app.connected = False
		self.app.paused = False
		
		Frame.__init__(self, root, *arg)
		topBar = Frame(self)
		topBar.grid(row=1, column=1, columnspan=3, sticky=W)
		speedBar = Frame(self)
		speedBar.grid(row=1, column=5, sticky=E)
		bottomBar = Frame(self)
		bottomBar.grid(row=2, column=1, columnspan=6, sticky=W+E)
		
		self.bPort = Button(topBar, text="Port", width=BWIDTH, command=self.doPort)
		self.bPort.pack(side=LEFT, padx=2, pady=2)
		ports = self.scanSerial()
		self.spPort = Spinbox(topBar, values=ports, state="readonly")
		self.spPort.pack(side=LEFT, padx=2, pady=2)
		l = Label(topBar, text=" @ ")
		l.pack(side=LEFT, padx=2, pady=2)
		self.spBaud = Spinbox(topBar, values=baudChoices)
		self.spBaud.pack(side=LEFT, padx=2, pady=2)
		self.spBaud.delete(0, END)
		self.spBaud.insert(0, 115200)
		self.spBaud.config(state="readonly")

		self.bConnectMode = CM_CONNECT
		self.bConnect = Button(topBar, text=connectText[CM_CONNECT], width=BWIDTH, command=self.doConnect)
		self.bConnect.pack(side=LEFT, padx=2, pady=2)
		if len(ports) == 0:
			self.bConnect.config(state=DISABLED)
		else:
			self.bConnect.config(state=NORMAL)


		self.bReset = Button(topBar, text="Reset", width=BWIDTH, command=self.doReset, state=DISABLED)
		self.bReset.pack(side=LEFT, padx=2, pady=2)
		
		l = Label(speedBar, text="Speed:", justify=RIGHT)
		l.grid(row=1, column=1, sticky=E)

		self._speedJob = None		
		self.currentSpeed = self.app.FeedMultiply
		self.scSpeed = Scale(speedBar, from_=MINSPEED, to=MAXSPEED, orient=HORIZONTAL, command=self.updateSpeedCommand)
		self.scSpeed.grid(row=1, column=2)
		self.scSpeed.set(self.currentSpeed);

		l = Label(speedBar, text="Fan:", width=10, anchor=E, justify=RIGHT)
		l.grid(row=1, column=3, sticky=E)
		
		self._fanJob = None		
		self.currentFanSpeed = self.app.FanSpeed
		self.scFan = Scale(speedBar, from_=0, to=255, orient=HORIZONTAL, command=self.updateFanSpeedCommand)
		self.scFan.grid(row=1, column=4)
		self.scFan.set(self.currentFanSpeed);

		if self.settings.speedcommand is not None:
			self.cbvAssertFan = IntVar()
			if self.settings.forcefanspeed:
				self.cbvAssertFan.set(1)
			else:
				self.cbvAssertFan.set(0)
			self.cbAssertFan = Checkbutton(speedBar, text="Force", variable=self.cbvAssertFan,
				command=self.clickAssertFan)
			self.cbAssertFan.grid(row=1, column=5)

		self.bSliceMode = SM_SLICE
		self.bSlice = Button(bottomBar, text=sliceText[SM_SLICE], width=BWIDTH*2, command=self.doSlice)
		self.bSlice.pack(side=LEFT, padx=2, pady=2)
		
		self.bLoad = Button(bottomBar, text="Load GCode", width=BWIDTH, command=self.doLoad)
		self.bLoad.pack(side=LEFT, padx=2, pady=2)
		self.setSliceText()
		
		self.bSD = Button(bottomBar, text="SD", width=BWIDTH, command=self.doSD, state=DISABLED)
		self.bSD.pack(side=LEFT, padx=2, pady=2)
		
		self.bPrintMode = PR_PRINT		
		self.bPrint = Button(bottomBar, text=printText[PR_PRINT], width=BWIDTH, command=self.doPrint, state=DISABLED)
		self.bPrint.pack(side=LEFT, padx=2, pady=2)
		
		self.bPauseMode = PM_PAUSE
		self.bPause = Button(bottomBar, text=pauseText[PM_PAUSE], width=BWIDTH, command=self.doPause, state=DISABLED)
		self.bPause.pack(side=LEFT, padx=2, pady=2)

		self.bAbandon = Button(bottomBar, text="Abandon SD Print", width=BWIDTH+8, command=self.doAbandon, state=DISABLED)
		self.bAbandon.pack(side=LEFT, padx=2, pady=2)
		
		self.cbvLiftOnPause = IntVar()
		if self.settings.liftonpause:
			self.cbvLiftOnPause.set(1)
		else:
			self.cbvLiftOnPause.set(0)
		self.cbLiftOnPause = Checkbutton(bottomBar, text="Lift Head/Retract on Pause", variable=self.cbvLiftOnPause,
			command=self.clickLiftOnPause)
		self.cbLiftOnPause.pack(side=LEFT, padx=2)

		self.cbvResumeAtPause = IntVar()
		if self.settings.resumeatpausepoint:
			self.cbvResumeAtPause.set(1)
		else:
			self.cbvResumeAtPause.set(0)
		self.cbResumeAtPause = Checkbutton(bottomBar, text="Resume print at pause point", variable=self.cbvResumeAtPause,
			command=self.clickResumeAtPause)
		self.cbResumeAtPause.pack(side=LEFT, padx=2)
		
	def clickAssertFan(self):
		if self.cbvAssertFan.get() == 1:
			self.settings.forcefanspeed = True
			self.settings.setModified()
		else:
			self.settings.forcefanspeed = False
			self.settings.setModified()
		
	def clickLiftOnPause(self):
		if self.cbvLiftOnPause.get() == 1:
			self.settings.liftonpause = True
			self.settings.setModified()
		else:
			self.settings.liftonpause = False
			self.settings.setModified()
		
	def clickResumeAtPause(self):
		if self.cbvResumeAtPause.get() == 1:
			self.settings.resumeatpausepoint = True
			self.settings.setModified()
		else:
			self.settings.resumeatpausepoint = False
			self.settings.setModified()
	
	def setSliceText(self):
		if self.settings.slicer == SLIC3R:
			sl = "slic3r:%s" % self.app.slic3r.getProfile()
		else:
			sl = "skeinforge:%s" % self.app.skeinforge.getProfile()
		sliceText[SM_SLICE] = "Slice (%s)" % sl
		if self.bSliceMode == SM_SLICE:
			self.bLoad.config(state=NORMAL)
			self.app.allowLoadGCodeMenu(True)
			lt = len(sliceText[SM_SLICE])+2
			if lt < BWIDTH:
				lt = BWIDTH
			self.bSlice.config(text=sliceText[SM_SLICE], width=lt)
		
	def updateSpeedCommand(self, *arg):
		if self._speedJob:
			self.app.master.after_cancel(self._speedJob)
			
		self._speedJob = self.app.master.after(500, self.updateSpeed)

	def updateSpeed(self, *arg):
		v = self.scSpeed.get()
		self.setSpeed(v)
		
	def setSpeed(self, v):
		if v < MINSPEED or v > MAXSPEED:
			self.logger.logMsg("Attempt to change speed outside of allowable range (%d-%d)" % (MINSPEED, MAXSPEED))
		elif int(v) != self.currentSpeed:
			if self.app.connected:
				self.currentSpeed = int(v)
				self.logger.logMsg("changing speed percentage to %d%%" % self.currentSpeed)
				cmd = "M220 S%d" % self.currentSpeed
				self.printer.send_now(cmd)
			else:
				self.logger.logMsg("Printer is off-line")

		self.scSpeed.set(self.currentSpeed)
		
	def updateFanSpeedCommand(self, *arg):
		if self._fanJob:
			self.app.master.after_cancel(self._fanJob)
			
		self._fanJob = self.app.master.after(500, self.updateFanSpeed)
		
	def updateFanSpeed(self, *arg):
		v = self.scFan.get()
		self.setFanSpeed(v)
		self.app.FanSpeed = v

	def forceFanSpeed(self, v):
		self.currentFanSpeed = -1
		self.setFanSpeed(v)

	def setFanSpeed(self, v):
		if int(v) != self.currentFanSpeed:
			if self.app.connected:
				self.currentFanSpeed = int(v)
				cmd = "M106 S%d" % self.currentFanSpeed
				self.printer.send_now(cmd)
			else:
				self.logger.logMsg("Printer is off-line")
		self.scFan.set(self.currentFanSpeed)
		
	def syncSpeeds(self):
		self.currentSpeed = self.app.FeedMultiply
		self.scSpeed.set(self.currentSpeed)
		self.currentFanSpeed = self.app.FanSpeed
		self.scFan.set(self.currentFanSpeed)
		
	def initializeToolbar(self):
		self.bReset.config(state=DISABLED)
		self.bSliceMode = SM_SLICE
		self.bSlice.config(text=sliceText[SM_SLICE])
		self.bLoad.config(state=NORMAL)
		self.app.allowLoadGCodeMenu(True)
		if not self.app.sdprinting and not self.app.sdpaused:
			self.bPrintMode = PR_PRINT
			self.bPrint.config(text=printText[PR_PRINT], state=DISABLED)
			self.bPauseMode = PM_PAUSE
			self.bPause.config(text=pauseText[PM_PAUSE], state=DISABLED)
		
	def setSDPrint(self):
		self.bPause.config(text=pauseText[PM_PAUSE], state=NORMAL)
		self.bPauseMode = PM_PAUSE
		self.bPrint.config(text=printText[PR_PRINT], state=DISABLED)
		self.bPrintMode = PR_PRINT
		self.bAbandon.config(state=NORMAL)
		
	def clearSDPrint(self):
		self.bPause.config(text=pauseText[PM_PAUSE], state=DISABLED)
		self.bPauseMode = PM_PAUSE
		self.bPrint.config(text=printText[PR_PRINT], state=DISABLED)
		self.bPrintMode = PR_PRINT
		self.bAbandon.config(state=DISABLED)
		self.checkAllowPrint()
		
	def setCancelMode(self):
		self.bSliceMode = SM_CANCEL
		self.bSlice.config(text=sliceText[SM_CANCEL], width=BWIDTH)
		self.bLoad.config(state=DISABLED)
		self.app.allowLoadGCodeMenu(False)
		self.app.allowSliceMenu(False)

	def setLoading(self, flag):
		if flag:
			self.bLoad.config(state=DISABLED)
			self.bSlice.config(state=DISABLED)
			self.app.allowLoadGCodeMenu(False)
			self.app.allowSliceMenu(False)
		else:
			self.bLoad.config(state=NORMAL)
			self.bSlice.config(state=NORMAL)
			self.app.allowLoadGCodeMenu(True)
			self.app.allowSliceMenu(True)
		
	def clearCancelMode(self):
		self.bSliceMode = SM_SLICE
		lt = len(sliceText[SM_SLICE])+2
		if lt < BWIDTH:
			lt = BWIDTH
		self.bSlice.config(text=sliceText[SM_SLICE], width=lt)
		self.bLoad.config(state=NORMAL)
		self.app.allowLoadGCodeMenu(True)
		self.app.allowSliceMenu(True)
		
	def doConnect(self):
		if self.bConnectMode == CM_CONNECT:
			port = self.spPort.get()
			baud = int(self.spBaud.get())
			self.printer.onlinecb = self.onlinecb
			try:
				self.printer.connect(port, baud)
			except SerialException:
				self.logger.logMsg("Unable to open printer port %s" % port)
		else:
			if self.app.printing:
				self.logger.logMsg("Please wait until printing has finished or is paused")
			else:
				self.printer.disconnect()
				self.printer.onlinecb = None
				self.app.printerConnected(False)
#				self.app.connected = False
				self.bConnectMode = CM_CONNECT
				self.bConnect.config(text=connectText[CM_CONNECT])
				self.bReset.config(state=DISABLED)
				self.bSD.config(state=DISABLED)
				if self.app.paused:
					self.bPrint.config(text=printText[PR_PRINT], state=DISABLED)
					self.bPrintMode = PR_PRINT
					self.bPause.config(text=pauseText[PM_PAUSE], state=DISABLED)
					self.bPauseMode = PM_PAUSE
					self.app.printing = False
					self.app.paused = False
					
	def doReset(self):
		if tkMessageBox.askyesno("Reset?", "Are you sure you want to reset the printer?", parent=self.app):
			self.printer.reset()
			self.printer.printing = 0
			self.app.printing = False
			self.bSlice.config(state=NORMAL)
			self.bLoad.config(state=NORMAL)
			self.app.allowLoadGCodeMenu(True)
			self.app.allowSliceMenu(True)

			self.bPrintMode = PR_PRINT
			self.bPrint.config(text=printText[PR_PRINT], state=NORMAL)
			if self.app.paused:
				self.printer.paused = 0
				self.bPause.config(text=pauseText[PM_PAUSE], state=DISABLED)
				self.bPauseMode = PM_PAUSE
				self.app.paused = False

	def onlinecb(self):
		self.logger.logMsg("Printer is on-line")
		self.app.printerConnected(True)
#		self.app.connected = True
		self.bConnectMode = CM_DISCONNECT
		self.bConnect.config(text=connectText[CM_DISCONNECT])
		self.bReset.config(state=NORMAL)
		self.bSD.config(state=NORMAL)
		self.checkAllowPrint()
	
	def checkAllowPrint(self):
		if self.app.connected and len(self.app.gcode) != 0 and not self.app.printing and not self.app.sdprinting:
			self.bPrint.config(text=printText[PR_PRINT], state=NORMAL)
			self.bPrintMode = PR_PRINT
			
	def printComplete(self):
		self.app.endTime = time.time()
		self.app.elapsedTime = self.app.endTime - self.app.startTime
		self.logger.logMsg("Printing completed at %s" % time.strftime('%H:%M:%S', time.localtime()))
		self.logger.logMsg("Total elapsed time: %s" % formatElapsed(self.app.elapsedTime))
		self.bPrintMode = PR_PRINT
		self.bPrint.config(text=printText[PR_PRINT], state=NORMAL)
		
		self.bPauseMode = PM_PAUSE
		self.bPause.config(text=pauseText[PM_PAUSE], state=DISABLED)
		
		self.app.printing = False
		self.bSlice.config(state=NORMAL)
		self.bLoad.config(state=NORMAL)
		self.app.allowLoadGCodeMenu(True)
		self.app.allowSliceMenu(True)
		self.app.paused = False
		self.app.gc.updatePrintProgress(0)
		self.app.closeAllReports()
		if self.settings.endprintmacro is not None:
			self.app.doMacro(name=self.settings.endprintmacro, silent=True)

		
	def doPause(self):
		if self.bPauseMode == PM_PAUSE:
			if self.app.printing:
				self.app.paused = True
				self.printer.pause()
			elif self.app.sdprinting:
				self.app.sdpaused = True
				self.printer.send_now("M25")
				self.app.sdprinting = False
				self.bPause.config(text=pauseText[PM_RESUME])
				self.bPauseMode = PM_RESUME
				self.bPrint.config(text=printText[PR_RESTART], state=NORMAL)
				self.bPrintMode = PR_RESTART
		else:
			if self.app.sdpaused:
				self.printer.send_now("M24")
				self.app.sdpaused = False
				self.app.sdprinting = True
				self.bPause.config(text=pauseText[PM_PAUSE])
				self.bPauseMode = PM_PAUSE
				self.bPrint.config(text=printText[PR_PRINT], state=DISABLED)
				self.bPrintMode = PR_PRINT
			else:
				self.hitPrint = False
				if self.settings.resumeatpausepoint:
					self.printer.send_now("G1 X%s Y%s F%s" % (self.app.pausePoint[XAxis], self.app.pausePoint[YAxis], self.settings.xyfeed))
					self.printer.send_now("G1 Z%s F%s" % (self.app.pausePoint[ZAxis], self.settings.zfeed))
					self.printer.send_now("G92 E%s" % self.app.pausePoint[EAxis])
					self.printer.send_now("G1 F%s" % self.settings.xyfeed)
				self.printer.startcb = self.startcb
				self.printer.resume()
				
	def doAbandon(self):
		self.printer.send_now("M25")
		self.app.sdpaused = False
		self.app.sdprinting = False
		self.clearSDPrint()

	def doSlice(self):
		if self.bSliceMode == SM_SLICE:
			self.bLoad.config(state=DISABLED)
			self.app.allowLoadGCodeMenu(False)
			self.app.openSTLFile()
		else:
			self.app.slicerCancel = True
			self.bLoad.config(state=NORMAL)
			self.app.allowLoadGCodeMenu(True)
			
	def doLoad(self):
		self.app.openGCodeFile()
	
	def doPrint(self):
		if self.app.sdpaused:
			self.printer.send_now("M26 S0")
			self.printer.send_now("M24")
			self.app.sdpaused = False
			self.app.sdprinting = True
			self.bPause.config(text=pauseText[PM_PAUSE])
			self.bPauseMode = PM_PAUSE
			self.bPrint.config(text=printText[PR_PRINT], state=DISABLED)
			self.bPrintMode = PR_PRINT
		else:
			if len(self.app.gcode) == 0:
				self.logger.logMsg("Nothing to print")
			else:
				#if not self.app.paused:
				self.app.gc.updatePrintProgress(0, restart=True)
	
				self.bPauseMode = PM_PAUSE
				self.bPause.config(text=pauseText[PM_PAUSE], state=NORMAL)
				self.hitPrint = True
				self.printer.startcb = self.startcb
				self.printer.startprint(self.app.gcode)
			
	def startcb(self):
		self.printer.startcb = None
		if not self.app.paused:
			self.app.startTime = time.time()
			self.logger.logMsg("Printing Started at %s" % time.strftime('%H:%M:%S', time.localtime(self.app.startTime)))
			self.app.printing = True
			
			self.bSlice.config(state=DISABLED)
			self.bLoad.config(state=DISABLED)
			self.app.allowLoadGCodeMenu(False)
			self.app.allowSliceMenu(False)

			self.bPrint.config(text=printText[PR_RESTART], state=DISABLED)
			self.bPrintMode = PR_RESTART
			self.printer.endcb = self.endcb
		else:
			if self.hitPrint:
				self.app.startTime = time.time()
				self.logger.logMsg("Printing restarted at %s" % time.strftime('%H:%M:%S', time.localtime()))
			else:
				self.logger.logMsg("Printing resumed at %s" % time.strftime('%H:%M:%S', time.localtime()))
			self.bPause.config(text=pauseText[PM_PAUSE])
			self.bPauseMode = PM_PAUSE
			self.app.printing = True
			
			self.bSlice.config(state=DISABLED)
			self.bLoad.config(state=DISABLED)
			self.app.allowLoadGCodeMenu(False)
			self.app.allowSliceMenu(False)


			self.app.paused = False
			self.bPrint.config(state=DISABLED)
			self.printer.endcb = self.endcb
		
	def endcb(self):
		self.printer.endcb = None
		if not self.app.paused:
			self.printComplete()
			if self.app.sduploading:
				self.app.sduploading = False
				self.printer.send_now("M29")
		else:
			self.app.event_generate(MWM_REQUESTPOSITIONREPORT)
			# record the current printer position and how many intervals were willing to wait fo the response
			self.maxWait114 = MAXWAIT114;
			self.waitPos = self.printer.queueindex
			self.check114Response()
		
	def check114Response(self) :
		# tick off 1 interval, and make sure we haven't either received the report or we've waited max intervals
		self.maxWait114 -= 1
		if self.app.m114count == 0 or self.maxWait114 <= 0:
			# one way or the other we're done waiting here
			if self.maxWait114 <= 0:
				self.app.m114count = 0
				self.logger.logMsg("Location report not received - proceeding")
				
			self.app.pausePoint[XAxis] = self.app.location[XAxis]
			self.app.pausePoint[YAxis] = self.app.location[YAxis]
			self.app.pausePoint[ZAxis] = self.app.location[ZAxis]
			self.app.pausePoint[EAxis] = self.app.location[EAxis]

			self.logger.logMsg("Pause location: X:%f Y:%f Z:%f E:%f" %
				(self.app.pausePoint[XAxis], self.app.pausePoint[YAxis], self.app.pausePoint[ZAxis], self.app.pausePoint[EAxis]))
			
			if self.settings.liftonpause:
				self.printer.send_now("G1 E%s F%s" % (self.app.pausePoint[EAxis]-2, self.settings.efeed))
				self.printer.send_now("G1 Z%s F%s" % (self.app.pausePoint[ZAxis]+10, self.settings.zfeed))

			self.bPause.config(text=pauseText[PM_RESUME])
			self.bPauseMode = PM_RESUME
			self.app.printing = False
			
			self.bSlice.config(state=NORMAL)
			self.bLoad.config(state=NORMAL)
			self.app.allowLoadGCodeMenu(True)
			self.app.allowSliceMenu(True)


			if self.app.sduploading:
				self.bPrint.config(text=printText[PR_PRINT], state=DISABLED)
				self.bPrintMode = PR_PRINT
			else:
				self.bPrint.config(text=printText[PR_RESTART], state=NORMAL)
				self.bPrintMode = PR_RESTART
		else:
			# we still are waiting for the report, but reset everything if the printer is still moving
			if self.waitPos != self.printer.queueindex:
				self.waitPos = self.printer.queueindex
				self.maxWait114 = MAXWAIT114
				
			self.app.master.after(500, self.check114Response)
	
	def doPort(self):
		l = self.scanSerial()
		self.spPort.config(values=l)
		if len(l) == 0:
			self.bConnect.config(state=DISABLED)
		else:
			self.bConnect.config(state=NORMAL)
	
	def scanSerial(self):
		"""scan for available ports. return a list of device names."""
		baselist=[]
		if os.name=="nt":
			try:
				key=_winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE,"HARDWARE\\DEVICEMAP\\SERIALCOMM")
				i=0
				while(1):
					baselist+=[_winreg.EnumValue(key,i)[1]]
					i+=1
			except:
				pass
		return baselist+glob.glob('/dev/ttyUSB*') + glob.glob('/dev/ttyACM*') +glob.glob("/dev/tty.*")+glob.glob("/dev/cu.*")+glob.glob("/dev/rfcomm*")
	
	def doSD(self):
		self.app.doSD()
Пример #23
0
class RelyGUI(object):
    """ GUI for driving storage reliability simulations """

    #
    # enumerated values for menus and spin boxes
    #
    disk_type = None
    diskTypes = [       # menu of disk drive types
        "Enterprise", "Consumer", "Real"
    ]

    disk_nre = None
    nre_rates = [       # list of likely NRE rates ... correspond to above
        "1.0E-19", "1.0E-18", "1.0E-17", "1.0E-16", "1.0E-15", "1.0E-14",
        "1.0E-13"
    ]

    # default FIT rates for various classes of drives
    fit_map = {
        'Enterprise': "826",
        'Consumer': "1320",
        'Real': "7800"
    }

    # default NRE rates for various classes of drives
    nre_map = {
        'Enterprise': "1.0E-16",
        'Consumer': "1.0E-15",
        'Real': "1.0E-14"
    }

    raid_type = None
    raidTypes = [       # menu of RAID types
        "RAID-0", "RAID-1", "RAID-5", "RAID-6"
    ]

    raid_vols = None

    # default volume counts for various RAID configurations
    vol_map = {
        'RAID-0': 1,
        'RAID-1': 2,
        'RAID-5': 3,
        'RAID-6': 6,
    }

    nre_model = None
    nreTypes = [      # ways of modeling NREs
        "ignore", "error", "fail", "error+fail/2"
    ]

    raid_rplc = None
    replace_times = [   # list of likely drive replacement times (hours)
        0, 1, 2, 4, 6, 8, 10, 12, 18, 24
    ]

    rados_down = None
    markout_times = [  # list of likely OSD mark-down times (minutes)
        0, 1, 2, 3, 4, 5, 10, 15, 20, 30, 45, 60
    ]

    raid_speed = None
    rados_speed = None
    rebuild_speeds = [  # list of likely rebuild speeds (MB/s)
        1, 2, 5, 10, 15, 20, 25, 40, 50, 60, 80, 100, 120, 140, 160
    ]

    remote_latency = None
    async_latencies = [  # list of likely asynchronous replication latencies
        0, 1, 5, 10, 30, 60, 300, 600, 900, 1800, 3600,
        2 * 3600, 6 * 3600, 12 * 3600, 18 * 3600, 24 * 3600
    ]

    rados_fullness = None
    fullness = [    # list of likely volume fullness percentages
        50, 75, 80, 85, 90, 95, 100
    ]

    site_num = None
    site_count = [  # list of likely remote site numbers
        1, 2, 3, 4, 5, 6, 7, 8, 9, 10
    ]

    remote_speed = None
    remote_speeds = [   # list of likely remote recovery speeds (MB/s)
        1, 2, 5, 10, 20, 25, 40, 50, 60, 80, 100, 150,
        200, 300, 400, 500, 600, 800, 1000
    ]

    remote_fail = None
    site_destroy = [    # force majeure event frequency
        10, 100, 1000, 10000, 100000, "never"
    ]

    remote_rplc = None
    site_recover = [    # number of days to recover a destroyed facility
        1, 2, 4, 8, 12, 16, 20, 30, 40, 50, 60, 80,
        100, 150, 200, 250, 300, 365, "never"
    ]

    verbosities = [    # display verbosity
        "all",
        "parameters",
        "headings",
        "data only"
    ]

    verbosity = None
    period = None
    disk_size = None
    rados_pgs = None
    rados_cpys = None
    stripe_length = None

    # these we generate dynamically
    obj_size = None
    object_sizes = []
    min_obj_size = 1 * 1024 * 1024
    max_obj_size = 1 * 1024 * 1024 * 1024 * 1024
    step_obj_size = 4

    # GUI widget field widths
    ROWS = 20
    BORDER = 5
    short_wid = 2
    med_wid = 4
    long_wid = 6
    short_fmt = "%2d"
    med_fmt = "%4d"
    long_fmt = "%6d"

    # references to the input widget fields (I know ...)

    def do_disk(self):
        """ calculate disk reliability """
        self.getCfgInfo()
        self.doit(self.cfg, "disk")

    def do_raid(self):
        """ calculate raid reliability """
        self.getCfgInfo()
        self.doit(self.cfg, "raid")

    def do_rados(self):
        """ calculate RADOS reliability """
        self.getCfgInfo()
        self.doit(self.cfg, "rados")

    def do_sites(self):
        """ calculate Multi-Site RADOS reliability """
        self.getCfgInfo()
        self.doit(self.cfg, "multi")

    def diskchoice(self, value):
        """ change default FIT and NRE rates to match disk selection """
        self.disk_nre.delete(0, END)
        self.disk_nre.insert(0, self.nre_map[value])
        self.disk_fit.delete(0, END)
        self.disk_fit.insert(0, self.fit_map[value])
        self.disk_fit2.delete(0, END)
        self.disk_fit2.insert(0, self.fit_map[value])

    def raidchoice(self, value):
        """ change default # of volumes to match RAID levels """
        self.raid_vols.delete(0, END)
        self.raid_vols.insert(0, self.vol_map[value])

    def __init__(self, cfg, doit):
        """ create the GUI panel widgets
            cfg -- parameter values (input and output)
            doit -- method to call to run simulations
            """

        # gather the basic parameters
        self.cfg = cfg
        self.doit = doit

        self.root = Tk()
        self.root.title('Data Reliability Model')
        t = Frame(self.root, bd=2 * self.BORDER)
        # w.iconbitmap(default='inktank.ico')   # ? windows only ?

        # left stack (DISK)
        f = Frame(t, bd=self.BORDER, relief=RIDGE)
        r = 1
        Label(f, text="Disk Type").grid(row=r)
        self.disk_type = StringVar(f)
        self.disk_type.set(self.diskTypes[0])
        OptionMenu(f, self.disk_type, *self.diskTypes,
                   command=self.diskchoice).grid(row=r + 1)
        Label(f).grid(row=r + 2)
        r += 3
        Label(f, text="Size (GiB)").grid(row=r)
        self.disk_size = Entry(f, width=self.long_wid)
        self.disk_size.delete(0, END)
        self.disk_size.insert(0, self.long_fmt % (cfg.disk_size / GiB))
        self.disk_size.grid(row=r + 1)
        Label(f).grid(row=r + 2)
        r += 3
        Label(f, text="Primary FITs").grid(row=r)
        self.disk_fit = Entry(f, width=self.long_wid)
        self.disk_fit.grid(row=r + 1)
        Label(f).grid(row=r + 2)
        r += 3
        Label(f, text="Secondary FITs").grid(row=r)
        self.disk_fit2 = Entry(f, width=self.long_wid)
        self.disk_fit2.grid(row=r + 1)
        Label(f).grid(row=r + 2)
        r += 3
        Label(f, text="NRE rate").grid(row=r)
        self.disk_nre = Spinbox(f, width=self.long_wid, values=self.nre_rates)
        self.disk_nre.grid(row=r + 1)
        Label(f).grid(row=r + 2)
        r += 3
        while r < self.ROWS:
            Label(f).grid(row=r)
            r += 1
        Button(f, text="RELIABILITY", command=self.do_disk).grid(row=r)
        f.grid(column=1, row=1)
        self.diskchoice(self.diskTypes[0])  # set default disk type

        # second stack (RAID)
        f = Frame(t, bd=self.BORDER, relief=RIDGE)
        r = 1
        Label(f, text="RAID Type").grid(row=r)
        self.raid_type = StringVar(f)
        self.raid_type.set("RAID-1")
        OptionMenu(f, self.raid_type, *self.raidTypes,
                   command=self.raidchoice).grid(row=r + 1)
        Label(f).grid(row=r + 2)
        r += 3
        Label(f, text="Replace (hours)").grid(row=r)
        self.raid_rplc = Spinbox(f, width=self.short_wid,
                                 values=self.replace_times)
        self.raid_rplc.grid(row=r + 1)
        self.raid_rplc.delete(0, END)
        self.raid_rplc.insert(0, "%d" % cfg.raid_replace)
        Label(f).grid(row=r + 2)
        r += 3
        Label(f, text="Rebuild (MiB/s)").grid(row=r)
        self.raid_speed = Spinbox(f, width=self.med_wid,
                                  values=self.rebuild_speeds)
        self.raid_speed.grid(row=r + 1)
        self.raid_speed.delete(0, END)
        self.raid_speed.insert(0, "%d" % (cfg.raid_recover / MiB))
        Label(f).grid(row=r + 2)
        r += 3
        Label(f, text="Volumes").grid(row=r)
        self.raid_vols = Spinbox(f, from_=1, to=10, width=self.short_wid)
        self.raid_vols.grid(row=r + 1)
        Label(f).grid(row=r + 2)
        self.raidchoice("RAID-1")   # set default number of volumes
        r += 3
        while r < self.ROWS:
            Label(f).grid(row=r)
            r += 1
        Button(f, text="RELIABILITY", command=self.do_raid).grid(row=r)
        f.grid(column=2, row=1)

        # third stack (RADOS)
        f = Frame(t, bd=self.BORDER, relief=RIDGE)
        r = 1
        Label(f, text="RADOS copies").grid(row=r)
        self.rados_cpys = Spinbox(f, values=(1, 2, 3, 4, 5, 6),
                                  width=self.short_wid)
        self.rados_cpys.grid(row=r + 1)
        self.rados_cpys.delete(0, END)
        self.rados_cpys.insert(0, "%d" % cfg.rados_copies)
        Label(f).grid(row=r + 2)
        r += 3
        Label(f, text="Mark-out (min)").grid(row=r)
        self.rados_down = Spinbox(f, values=self.markout_times,
                                  width=self.short_wid)
        self.rados_down.grid(row=r + 1)
        self.rados_down.delete(0, END)
        self.rados_down.insert(0, "%d" % (cfg.rados_markout * 60))
        Label(f).grid(row=r + 2)
        r += 3
        Label(f, text="Recovery (MiB/s)").grid(row=r)
        self.rados_speed = Spinbox(f, width=self.med_wid,
                                   values=self.rebuild_speeds)
        self.rados_speed.grid(row=r + 1)
        self.rados_speed.delete(0, END)
        self.rados_speed.insert(0, "%d" % (cfg.rados_recover / MiB))
        Label(f).grid(row=r + 2)
        r += 3
        Label(f, text="Space Usage (%)").grid(row=r)
        self.rados_fullness = Spinbox(f, values=self.fullness,
                                      width=self.med_wid)
        self.rados_fullness.grid(row=r + 1)
        self.rados_fullness.delete(0, END)
        self.rados_fullness.insert(0, "%d" % (cfg.rados_fullness * 100))
        Label(f).grid(row=r + 2)
        r += 3
        Label(f, text="Declustering (pg)").grid(row=r)
        self.rados_pgs = Entry(f, width=self.med_wid)
        self.rados_pgs.delete(0, END)
        self.rados_pgs.insert(0, self.med_fmt % cfg.rados_decluster)
        self.rados_pgs.grid(row=r + 1)
        Label(f).grid(row=r + 2)
        r += 3
        Label(f, text="Stripe Length").grid(row=r)
        self.stripe_length = Entry(f, width=self.med_wid)
        self.stripe_length.delete(0, END)
        self.stripe_length.insert(0, self.med_fmt % cfg.stripe_length)
        self.stripe_length.grid(row=r + 1)
        Label(f).grid(row=r + 2)
        r += 3
        while r < self.ROWS:
            Label(f).grid(row=r)
            r += 1
        Button(f, text="RELIABILITY", command=self.do_rados).grid(row=r)
        f.grid(column=3, row=1)

        # fourth stack (remote site)
        r = 1
        f = Frame(t, bd=self.BORDER, relief=RIDGE)
        Label(f, text="RADOS Sites").grid(row=r)
        self.site_num = Spinbox(f, values=self.site_count,
                                width=self.short_wid)
        self.site_num.grid(row=r + 1)
        self.site_num.delete(0, END)
        self.site_num.insert(0, "%d" % cfg.remote_sites)
        Label(f).grid(row=r + 2)
        r += 3
        Label(f, text="Rep Latency (s)").grid(row=r)
        self.remote_latency = Spinbox(f, values=self.async_latencies,
                                      width=self.long_wid)
        self.remote_latency.grid(row=r + 1)
        self.remote_latency.delete(0, END)
        self.remote_latency.insert(0, "%d" % (cfg.remote_latency * 60 * 60))
        Label(f).grid(row=r + 2)
        r += 3
        Label(f, text="Recovery (MiB/s)").grid(row=r)
        self.remote_speed = Spinbox(f, values=self.remote_speeds,
                                    width=self.med_wid)
        self.remote_speed.grid(row=r + 1)
        self.remote_speed.delete(0, END)
        self.remote_speed.insert(0, "%d" % (cfg.remote_recover / MiB))
        Label(f).grid(row=r + 2)
        r += 3
        Label(f, text="Disaster (years)").grid(row=r)
        self.remote_fail = Spinbox(f, values=self.site_destroy,
                                   width=self.long_wid)
        self.remote_fail.grid(row=r + 1)
        self.remote_fail.delete(0, END)
        self.remote_fail.insert(0, "1000")
        # FIX - get this from cfg ... but translate from FITS
        Label(f).grid(column=2, row=r + 2)
        r += 3
        Label(f, text="Site Recover (days)").grid(row=r)
        self.remote_avail = Spinbox(f, values=self.site_recover,
                                    width=self.long_wid)
        self.remote_avail.grid(row=r + 1)
        self.remote_avail.delete(0, END)
        self.remote_avail.insert(0, "30")
        # FIX - get this from cfg ... but translate from FITS
        Label(f).grid(row=r + 2)
        r += 3
        while r < self.ROWS:
            Label(f).grid(row=r)
            r += 1
        Button(f, text="RELIABILITY", command=self.do_sites).grid(row=r)
        f.grid(column=4, row=1)

        # and the control panel
        r = 2
        c = 1
        Label(t).grid(column=c, row=r)
        Label(t, text="NRE model").grid(column=c, row=r + 1)
        self.nre_model = StringVar(t)
        self.nre_model.set(self.cfg.nre_model)
        OptionMenu(t, self.nre_model, *self.nreTypes).grid(column=c, row=r + 2)

        c = 2
        Label(t).grid(column=c, row=r)
        Label(t, text="Period (years)").grid(column=c, row=r + 1)
        self.period = Spinbox(t, from_=1, to=10, width=self.short_wid)
        self.period.grid(column=c, row=r + 2)

        c = 3
        Label(t).grid(column=c, row=r)
        Label(t, text="Object size").grid(column=c, row=r + 1)
        # generate object sizes dynamically from parameters
        os = self.min_obj_size
        while os <= self.max_obj_size:
            if os < MB:
                s = "%dKB" % (os / KB)
            elif os < GB:
                s = "%dMB" % (os / MB)
            elif os < TB:
                s = "%dGB" % (os / GB)
            else:
                s = "%dTB" % (os / TB)
            self.object_sizes.append(s)
            os *= self.step_obj_size
        self.obj_size = Spinbox(t, values=self.object_sizes,
                                width=self.long_wid)
        self.obj_size.grid(column=c, row=r + 2)
        self.obj_size.delete(0, END)
        self.obj_size.insert(0, self.object_sizes[0])

        c = 4
        Label(t).grid(column=c, row=r)
        Label(t, text="Verbosity").grid(column=c, row=r + 1)
        self.verbosity = StringVar(t)
        self.verbosity.set(cfg.verbose)
        OptionMenu(t, self.verbosity, *self.verbosities).grid(column=c,
                                                              row=r + 2)

        # and then finalize everything
        t.grid()

    def getCfgInfo(self):
        """ scrape configuration information out of the widgets """
        self.cfg.period = 365.25 * 24 * int(self.period.get())
        self.cfg.disk_type = self.disk_type.get()
        self.cfg.disk_size = int(self.disk_size.get()) * GiB
        self.cfg.disk_nre = float(self.disk_nre.get())
        self.cfg.disk_fit = int(self.disk_fit.get())
        self.cfg.disk_fit2 = int(self.disk_fit2.get())
        self.cfg.raid_vols = int(self.raid_vols.get())
        self.cfg.raid_type = self.raid_type.get()
        self.cfg.raid_replace = int(self.raid_rplc.get())
        self.cfg.raid_recover = int(self.raid_speed.get()) * MiB
        self.cfg.nre_model = self.nre_model.get()
        self.cfg.rados_copies = int(self.rados_cpys.get())
        self.cfg.rados_markout = float(self.rados_down.get()) / 60
        self.cfg.rados_recover = int(self.rados_speed.get()) * MiB
        self.cfg.rados_decluster = int(self.rados_pgs.get())
        self.cfg.stripe_length = int(self.stripe_length.get())
        self.cfg.rados_fullness = float(self.rados_fullness.get()) / 100
        self.cfg.remote_latency = float(self.remote_latency.get()) / (60 * 60)
        self.cfg.remote_sites = int(self.site_num.get())
        self.cfg.remote_recover = int(self.remote_speed.get()) * MiB
        self.cfg.verbose = self.verbosity.get()

        # these parameters can also have the value "never"
        v = self.remote_fail.get()
        self.cfg.majeure = 0 if v == "never" else \
            1000000000 / (float(self.remote_fail.get()) * 365.25 * 24)
        v = self.remote_avail.get()
        self.cfg.site_recover = 0 if v == "never" else \
            float(self.remote_avail.get()) * 24

        # a more complex process for the dynamically generated lists
        self.cfg.obj_size = self.min_obj_size
        i = 0
        while i < len(self.object_sizes) and \
                self.cfg.obj_size < self.max_obj_size:
            if self.obj_size.get() == self.object_sizes[i]:
                break
            self.cfg.obj_size *= self.step_obj_size
            i += 1

        # sanity checking on arguments with limits
        if self.cfg.stripe_length < 1:
            self.cfg.stripe_length = 1
        if self.cfg.stripe_length > self.cfg.rados_decluster:
            print("\nIGNORING stripe width (%d) > decluster (%d)\n" %
                  (self.cfg.stripe_length, self.cfg.rados_decluster))
            self.cfg.stripe_length = self.cfg.rados_decluster

    def mainloop(self):
        self.root.mainloop()
Пример #24
0
    def initUI(self):
        # Main Window
        self.parent.title("gBot")
        self.style = Style()
        self.style.theme_use("default")
        self.pack(fill=BOTH, expand=1)

        # Debug Window
        Toplevel1 = Toplevel(self)
        Toplevel1.title("gBot Debug Console")
        self.pack(fill=BOTH, expand=1)
        TL_T1 = Text(Toplevel1, width=50)
        TL_T1.pack()
        Toplevel1.state("withdrawn")
        Toplevel1.protocol('WM_DELETE_WINDOW', lambda:Toplevel1.state("withdrawn"))
        Toplevel1.attributes("-topmost", True)

        # Username Input
        L1 = Label(self, text="G+ User Name")
        L1.grid(row=0, column=0, sticky=E, ipady=1)
        E1 = Entry(self, width=30)
        E1.grid(row=0, column=1, ipady=1, sticky=E)

        # Password Input
        L2 = Label(self, text="G+ Password")
        L2.grid(row=1, column=0, sticky=E, ipady=1)
        E2 = Entry(self, width=30)
        E2.grid(row=1, column=1, ipady=1, sticky=E)

        # Output Path Input
        L3 = Label(self, text="Output Path")
        L3.grid(row=2, column=0, sticky=E, pady=1)
        E3 = Entry(self, width=30)
        E3.grid(row=2, column=1, ipady=1, sticky=E)
        E3.insert(0, "%s\links.txt" % (os.getcwd()))

        # Num Posts
        L4 = Label(self, text="# Of Posts")
        L4.grid(row=3, column=0, sticky=E, pady=1)
        S1 = Spinbox(self, from_=1, to=9999999, width=28)
        S1.grid(row=3, column=1, ipady=1, sticky=E)
        
        # Post Input
        T1 = Text(self, width=30)
        T1.grid(row=5, columnspan=2, sticky=W+E, pady=1)
        
        # Start button
        B1 = Button(self, text="Start Posting", command=lambda:self.doPosting(B1,TL_T1,E1.get(),E2.get(),T1.get(1.0,END),E3.get(),S1.get()))
        B1.grid(row=6,columnspan=2, sticky=W+E)

        # Debug button
        B2 = Button(self, text="Debug log", command=lambda:Toplevel1.state("normal"))
        B2.grid(row=7, columnspan=2, sticky=W+E)

        self.addDebug(TL_T1,"Started successfully")
Пример #25
0
class SettingWindow(Toplevel):
    def __init__(self, master, max_num_features, num_frames, mser_image):
        Toplevel.__init__(self, master)

        self.protocol('WM_DELETE_WINDOW', self.withdraw)

        self.notebook = ttk.Notebook(self)
        frame_feats = ttk.Frame(self.notebook)
        frame_forest = ttk.Frame(self.notebook)
        frame_mser = ttk.Frame(self.notebook)
        frame_other = ttk.Frame(self.notebook)
        self.notebook.add(frame_feats, text="Features ")
        self.notebook.add(frame_forest, text=" Forest  ")
        self.notebook.add(frame_mser, text=" MSER  ")
        self.notebook.add(frame_other, text=" Other  ")

        self.max_num_feats = max_num_features
        self.selection = None

        self.mser_image = mser_image

        rand_row = random.randint(1, 512 - 200)
        rand_col = random.randint(1, 512 - 110)
        self.mser_area = mser_image[rand_row:rand_row + 180,
                                    rand_col:rand_col + 100]

        # read images from icons folder
        self.hf0_img = PhotoImage(file="./icons/hf0.gif")
        self.hf1_img = PhotoImage(file="./icons/hf1.gif")
        self.hf2_img = PhotoImage(file="./icons/hf2.gif")
        self.hf3_img = PhotoImage(file="./icons/hf3.gif")
        self.hf4_img = PhotoImage(file="./icons/hf4.gif")
        self.hf5_img = PhotoImage(file="./icons/hf5.gif")

        self.features_vars = list()
        for i in range(max_num_features):
            self.features_vars.append(IntVar())

        Label(frame_feats,
              text="Patch size (" + u"\N{GREEK SMALL LETTER PI}" + "):").grid(
                  row=0, column=0, pady=5)
        self.patch_size_spinbox = Spinbox(frame_feats, from_=3, to=30, width=3)
        self.patch_size_spinbox.delete(0, END)
        self.patch_size_spinbox.insert(END, 10)
        self.patch_size_spinbox.grid(row=0, column=1, padx=5)

        f1 = ttk.Labelframe(frame_feats, text='Mean filter')
        f1.grid(row=1, columnspan=2)

        Label(f1, text=u"\N{GREEK SMALL LETTER PI}").grid(row=0, column=0)
        Checkbutton(f1, text="R",
                    variable=self.features_vars[0]).grid(row=0, column=1)
        Checkbutton(f1, text="G",
                    variable=self.features_vars[1]).grid(row=0, column=2)
        Checkbutton(f1, text="B",
                    variable=self.features_vars[2]).grid(row=0, column=3)

        Label(f1, text=u"\N{GREEK SMALL LETTER PI}" + "/2").grid(row=1,
                                                                 column=0)
        Checkbutton(f1, text="R",
                    variable=self.features_vars[3]).grid(row=1, column=1)
        Checkbutton(f1, text="G",
                    variable=self.features_vars[4]).grid(row=1, column=2)
        Checkbutton(f1, text="B",
                    variable=self.features_vars[5]).grid(row=1, column=3)

        f2 = ttk.Labelframe(frame_feats, text="Gaussian filter")
        f2.grid(row=2, columnspan=2)

        Label(f2, text=str(1.0)).grid(row=0, column=0)
        Checkbutton(f2, text="R",
                    variable=self.features_vars[6]).grid(row=0, column=1)
        Checkbutton(f2, text="G",
                    variable=self.features_vars[7]).grid(row=0, column=2)
        Checkbutton(f2, text="B",
                    variable=self.features_vars[8]).grid(row=0, column=3)

        Label(f2, text=str(3.5)).grid(row=1, column=0)
        Checkbutton(f2, text="R",
                    variable=self.features_vars[9]).grid(row=1, column=1)
        Checkbutton(f2, text="G",
                    variable=self.features_vars[10]).grid(row=1, column=2)
        Checkbutton(f2, text="B",
                    variable=self.features_vars[11]).grid(row=1, column=3)

        f3 = ttk.Labelframe(frame_feats, text="Laplacian of gaussian")
        f3.grid(row=3, columnspan=2)

        Label(f3, text=str(2.0)).grid(row=0, column=0)
        Checkbutton(f3, text="R",
                    variable=self.features_vars[12]).grid(row=0, column=1)
        Checkbutton(f3, text="G",
                    variable=self.features_vars[13]).grid(row=0, column=2)
        Checkbutton(f3, text="B",
                    variable=self.features_vars[14]).grid(row=0, column=3)

        Label(f3, text=str(3.5)).grid(row=1, column=0)
        Checkbutton(f3, text="R",
                    variable=self.features_vars[15]).grid(row=1, column=1)
        Checkbutton(f3, text="G",
                    variable=self.features_vars[16]).grid(row=1, column=2)
        Checkbutton(f3, text="B",
                    variable=self.features_vars[17]).grid(row=1, column=3)

        f4 = ttk.Labelframe(frame_feats, text="Haar-like features")
        f4.grid(row=1, rowspan=2, column=3, padx=5)

        Checkbutton(f4, image=self.hf0_img,
                    variable=self.features_vars[18]).grid(row=0, column=0)
        Checkbutton(f4, image=self.hf1_img,
                    variable=self.features_vars[19]).grid(row=0, column=1)
        Checkbutton(f4, image=self.hf2_img,
                    variable=self.features_vars[20]).grid(row=1, column=0)
        Checkbutton(f4, image=self.hf3_img,
                    variable=self.features_vars[21]).grid(row=1, column=1)
        Checkbutton(f4, image=self.hf4_img,
                    variable=self.features_vars[22]).grid(row=2, column=0)
        Checkbutton(f4, image=self.hf5_img,
                    variable=self.features_vars[23]).grid(row=2, column=1)

        buttons_paned_window = PanedWindow(frame_feats, orient=VERTICAL)
        buttons_paned_window.grid(row=3, column=3)

        self.select_all_button = Button(buttons_paned_window,
                                        text="Select all",
                                        command=self._select_all)
        buttons_paned_window.add(self.select_all_button)

        self.clear_selection_button = Button(buttons_paned_window,
                                             text="Clear selection",
                                             command=self._clear_selection)
        buttons_paned_window.add(self.clear_selection_button)

        # default values
        for j in [0, 1, 3, 6, 7, 9, 15, 21, 23]:
            self.features_vars[j].set(1)

        # FOREST FRAMES
        # number of trees
        f5 = ttk.Labelframe(frame_forest, text="Number of trees")
        f5.grid(row=0, columnspan=2, pady=5, padx=5)
        Label(f5, text="N").grid(row=1, column=0)
        self.num_trees_scale = Scale(f5,
                                     from_=5,
                                     to=500,
                                     resolution=5,
                                     orient=HORIZONTAL)
        self.num_trees_scale.set(300)
        self.num_trees_scale.grid(row=0, column=1, rowspan=2)

        # depth single tree
        f6 = ttk.Labelframe(frame_forest, text="Depth single tree")
        f6.grid(row=1, columnspan=2, pady=5, padx=5)
        Label(f6, text="d").grid(row=1, column=0)
        self.depth_tree_scale = Scale(f6, from_=2, to=20, orient=HORIZONTAL)
        self.depth_tree_scale.set(3)
        self.depth_tree_scale.grid(row=0, column=1, rowspan=2)

        # percentage number of features
        f7 = ttk.Labelframe(frame_forest, text="% subset of features")
        f7.grid(row=2, columnspan=2, pady=5, padx=5)
        Label(f7, text="m").grid(row=1, column=0)
        self.percentage_feats_scale = Scale(f7,
                                            from_=0.0,
                                            to=1,
                                            resolution=0.05,
                                            orient=HORIZONTAL)
        self.percentage_feats_scale.set(0.5)
        self.percentage_feats_scale.grid(row=0, column=1, rowspan=2)

        # mser frame
        # delta
        f8 = ttk.Labelframe(frame_mser, text="Delta")
        f8.grid(row=0, columnspan=2, pady=5, padx=5)
        Label(f8, text=u"\N{GREEK SMALL LETTER DELTA}").grid(row=1, column=0)
        self.delta_scale = Scale(f8,
                                 from_=1,
                                 to=10,
                                 resolution=1,
                                 orient=HORIZONTAL)
        self.delta_scale.set(2)
        self.delta_scale.grid(row=0, column=1, rowspan=2)

        # min area
        f9 = ttk.Labelframe(frame_mser, text="Minimum area")
        f9.grid(row=1, columnspan=2, pady=5, padx=5)
        Label(f9, text="m").grid(row=1, column=0)
        self.min_area_scale = Scale(f9, from_=2, to=200, orient=HORIZONTAL)
        self.min_area_scale.set(10)
        self.min_area_scale.grid(row=0, column=1, rowspan=2)

        # percentage number of features
        f10 = ttk.Labelframe(frame_mser, text="Maximum area")
        f10.grid(row=2, columnspan=2, pady=5, padx=5)
        Label(f10, text="M").grid(row=1, column=0)
        self.max_area_scale = Scale(f10,
                                    from_=50,
                                    to=1000,
                                    resolution=5,
                                    orient=HORIZONTAL)
        self.max_area_scale.set(350)
        self.max_area_scale.grid(row=0, column=1, rowspan=2)

        # mser image
        f11 = ttk.Labelframe(frame_mser)
        f11.grid(row=0, rowspan=3, column=2, padx=5)

        self.mser_img_array = Image.fromarray(self.mser_area, "RGB")
        self.mser_img = ImageTk.PhotoImage(self.mser_img_array)

        img_label = Label(f11, image=self.mser_img)
        img_label.grid(row=0, column=0)

        buttons_p_w_mser = PanedWindow(f11, orient=HORIZONTAL)
        try_button = Button(f11, text="Try", command=self.try_mser)
        buttons_p_w_mser.add(try_button)
        change_button = Button(f11, text="New img", command=self.change_mser)
        buttons_p_w_mser.add(change_button)
        buttons_p_w_mser.grid(row=1, column=0)

        # other frame
        f12 = ttk.Labelframe(frame_other, text="Refinement")
        f12.grid(row=0, columnspan=2, pady=5, padx=5)
        Label(f12, text=u"\N{GREEK CAPITAL LETTER PHI}_l").grid(row=1,
                                                                column=0)
        self.low_thresh_scale = Scale(f12,
                                      from_=0,
                                      to=1,
                                      resolution=0.05,
                                      orient=HORIZONTAL,
                                      length=90)
        self.low_thresh_scale.set(0.45)
        self.low_thresh_scale.grid(row=0, column=1, rowspan=2)
        Label(f12, text=u"\N{GREEK CAPITAL LETTER PHI}_h").grid(row=3,
                                                                column=0)
        self.high_thresh_scale = Scale(f12,
                                       from_=0,
                                       to=1,
                                       resolution=0.05,
                                       orient=HORIZONTAL,
                                       length=90)
        self.high_thresh_scale.set(0.65)
        self.high_thresh_scale.grid(row=2, column=1, rowspan=2)

        f13 = ttk.Labelframe(frame_other, text="Dots distance")
        f13.grid(row=1, columnspan=2, pady=5, padx=5)
        Label(f13, text=u"     \N{GREEK SMALL LETTER SIGMA}").grid(row=1,
                                                                   column=0)
        self.dots_distance_scale = Scale(f13,
                                         from_=1,
                                         to=20,
                                         resolution=1,
                                         orient=HORIZONTAL,
                                         length=90)
        self.dots_distance_scale.set(6)
        self.dots_distance_scale.grid(row=0, column=1, rowspan=2)

        f14 = ttk.Labelframe(frame_other, text="Tracks")
        f14.grid(row=0, column=3, pady=5, padx=5)
        Label(f14, text="N").grid(row=1, column=0)
        self.num_frames_tracks_spinbox = Spinbox(f14,
                                                 from_=2,
                                                 to=num_frames,
                                                 width=10)
        self.num_frames_tracks_spinbox.delete(0, END)
        self.num_frames_tracks_spinbox.insert(END, num_frames)
        self.num_frames_tracks_spinbox.grid(row=0, column=1, rowspan=2)

        Label(f14, text=u"\N{GREEK SMALL LETTER TAU}").grid(row=3, column=0)
        self.gaps_scale = Scale(f14,
                                from_=1,
                                to=10,
                                resolution=1,
                                orient=HORIZONTAL,
                                length=90)
        self.gaps_scale.set(2)
        self.gaps_scale.grid(row=2, column=1, rowspan=2)

        self.notebook.pack(padx=1, pady=1)

        save_button = Button(self,
                             text=" Save and Close window ",
                             command=self.withdraw)
        save_button.pack(pady=2)

    def _select_all(self):
        for i, var in enumerate(self.features_vars):
            var.set(1)

    def _clear_selection(self):
        for i, var in enumerate(self.features_vars):
            var.set(0)

    def change_mser(self):
        rand_row = random.randint(1, 512 - 200)
        rand_col = random.randint(1, 512 - 110)
        self.mser_area = self.mser_image[rand_row:rand_row + 180,
                                         rand_col:rand_col + 100]

        self.update_mser_image(self.mser_area)

    def try_mser(self):
        delta = self.delta_scale.get()
        min_area = self.min_area_scale.get()
        max_area = self.max_area_scale.get()

        image = self.mser_area
        red_c = image[:, :, 0]
        red_c = cv2.equalizeHist(red_c)

        det_img = image.copy()

        mser = cv2.MSER(delta, _min_area=min_area, _max_area=max_area)
        regions = mser.detect(red_c)
        cp = list()
        new_c = np.zeros(self.mser_area.shape, dtype=np.uint8)
        for r in regions:
            for point in r:
                cp.append(point)
                det_img[point[1], point[0], 0] = 0
                det_img[point[1], point[0], 1] = 0
                det_img[point[1], point[0], 2] = 204
                #new_c[point[1], point[0]] = 255

        self.update_mser_image(det_img)

    def update_mser_image(self, new_image):
        self.mser_img_array = Image.fromarray(new_image)
        self.mser_img.paste(self.mser_img_array)

    def get_patch_size(self):
        patch_size = self.patch_size_spinbox.get()
        return int(patch_size)

    def get_num_frames_tracks(self):
        num_frames_tracks = self.num_frames_tracks_spinbox.get()
        return int(num_frames_tracks)

    def get_mser_opts(self):
        return [
            self.delta_scale.get(),
            self.min_area_scale.get(),
            self.max_area_scale.get()
        ]

    def get_forest_opts(self):
        return [
            self.num_trees_scale.get(),
            self.depth_tree_scale.get(),
            self.percentage_feats_scale.get()
        ]

    def get_low_thresh(self):
        return self.low_thresh_scale.get()

    def get_high_thresh(self):
        return self.high_thresh_scale.get()

    def get_dots_distance(self):
        return int(self.dots_distance_scale.get())

    def get_selection_mask(self):
        if self.selection is not None:
            return self.selection

        selection_mask = np.zeros((self.max_num_feats, ), dtype='bool')
        for i, var in enumerate(self.features_vars):
            selection_mask[i] = var.get()
        self.selection = selection_mask
        return selection_mask