Esempio n. 1
1
class OptionWindow(Toplevel):
    def __call__(self, options=[], display=True):
        self.options = options

        self.listbox.delete(0, END)
        for key, value in options:
            self.listbox.insert(END, key)

        if display:
            self.display()

    def __init__(self):
        Toplevel.__init__(self, master=root)
        self.options = None
        self.title('Matches')

        self.listbox = Listbox(master=self)

        self.listbox.pack(expand=True, fill=BOTH, side=TOP)
        self.listbox.focus_set()
        self.listbox.activate(0)
        self.listbox.selection_set(0)

        self.listbox.config(width=50)

        self.listbox.bind('<Key-h>',
                          lambda event: self.listbox.event_generate('<Left>'))

        self.listbox.bind('<Key-l>',
                          lambda event: self.listbox.event_generate('<Right>'))

        self.listbox.bind('<Key-k>',
                          lambda event: self.listbox.event_generate('<Up>'))

        self.listbox.bind('<Key-j>',
                          lambda event: self.listbox.event_generate('<Down>'))

        self.listbox.bind('<Escape>', lambda event: self.close())
        self.protocol("WM_DELETE_WINDOW", self.close)
        self.transient(root)
        self.withdraw()

    def display(self):
        self.grab_set()
        self.deiconify()
        self.listbox.focus_set()
        # self.wait_window(self)

    def close(self):
        # When calling destroy or withdraw without
        # self.deoiconify it doesnt give back
        # the focus to the parent window.

        self.deiconify()
        self.grab_release()
        self.withdraw()
Esempio n. 2
0
class RSVisCanvasFrame(Frame):

    #   method --------------------------------------------------------------
    # -----------------------------------------------------------------------
    def __init__(
        self, 
        parent,
        images, 
        data,
        **kwargs
    ):
        super(RSVisCanvasFrame, self).__init__(parent)

        self.columnconfigure(2, weight=1)
        self.rowconfigure(0, weight=1)
        self.scrollbar = Scrollbar(self, orient="vertical", width=16)
        self.listbox = Listbox(self, yscrollcommand=self.scrollbar.set, width=37, activestyle=UNDERLINE)
        self.scrollbar.config(command=self.listbox.yview)
        self.scrollbar.grid(row=0, column=0, sticky=N+S)
        self.listbox.grid(row=0, column=1, sticky=N+S)
        for count, item in enumerate(images):
            self.listbox.insert(END, pathlib.Path(item[0].path).stem)
        self.listbox.bind("<<ListboxSelect>>", self.listbox_event)

        self._canvas = rsviscv.RSVisCanvas(self, images, data, **kwargs)
        self._canvas.set_container()
        self._canvas.grid(row=0, column=2, sticky=N+S+E+W)

        # parent.bind("<a>", self.key_a)
        # parent.bind("<d>", self.key_d)  

    #   method --------------------------------------------------------------
    # -----------------------------------------------------------------------
    def listbox_event(self,event):
        try:
            self._canvas._idx_list(index=self.listbox.curselection()[0])
            self._canvas.set_container()
        except IndexError:
            pass

    #   method --------------------------------------------------------------
    # -----------------------------------------------------------------------
    def update_listbox(self, event):
        self.listbox.activate(self._canvas.get_idx_list())

    #   method --------------------------------------------------------------
    # -----------------------------------------------------------------------
    def key_a(self, event, **kwargs):
        """Show the previous image in given image list (see listbox)."""
        self.update_listbox(event)

    #   method --------------------------------------------------------------
    # -----------------------------------------------------------------------
    def key_d(self, event, **kwargs):
        """Show the next image in given image list (see listbox)."""
        self.update_listbox(event)
Esempio n. 3
0
class List:
    def __init__(self, root, array=[]):
        self.__root = root

        self.__frame = Frame(self.__root)

        self.__scrollBar = Scrollbar(self.__frame)

        self.__list = Listbox(self.__frame,
                              font=12,
                              selectmode=SINGLE,
                              width=10,
                              yscrollcommand=self.__scrollBar.set)
        self.__list.config(width=40)
        self.__list.pack(side=LEFT, anchor=W, fill=BOTH, expand=True)

        self.__lessons = []
        self.setList(array)

        self.__scrollBar.config(command=self.__list.yview)
        self.__scrollBar.pack(side=RIGHT, fill=Y)

        self.__frame.pack(side=LEFT, anchor=W, fill=BOTH, expand=True)

    def getObjectList(self):
        return self.__list

    def setList(self, array=[]):
        self.__deleteAll()

        self.__lessons = [x for x in array]
        for item in array:
            self.__list.insert(END, str(item))

    def getSelectedElement(self, e=None):
        if self.__list.curselection() is ():
            return None
        else:
            return self.__lessons[self.__list.curselection()[0]]

    def setSelectedItem(self, i):
        self.__list.activate(i)

    def __deleteAll(self):
        self.__list.delete(0, END)
Esempio n. 4
0
class SerialConfigFrame(
    Frame
):  # pylint: disable=too-many-ancestors, too-many-instance-attributes
    """
    Serial port configuration frame class.
    """

    def __init__(self, container, *args, **kwargs):
        """
        Constructor.

        :param tkinter.Frame container: reference to container frame
        :param args: optional args to pass to Frame parent class
        :param kwargs: optional kwargs for value ranges, or to pass to Frame parent class
        """

        self._bpsrate_rng = kwargs.pop("bpsrates", BPSRATE_RNG)
        self._databits_rng = kwargs.pop("databits", DATABITS_RNG)
        self._stopbits_rng = kwargs.pop("stopbits", STOPBITS_RNG)
        self._parity_rng = kwargs.pop("parities", PARITY_RNG)
        self._timeout_rng = kwargs.pop("timeouts", TIMEOUT_RNG)
        self._preselect = kwargs.pop("preselect", ())
        self._readonlybg = kwargs.pop("readonlybackground", BGCOL)

        Frame.__init__(self, container, *args, **kwargs)

        self._show_advanced = False
        self._noports = True
        self._ports = ()
        self._port = StringVar()
        self._port_desc = StringVar()
        self._bpsrate = IntVar()
        self._databits = IntVar()
        self._stopbits = DoubleVar()
        self._parity = StringVar()
        self._rtscts = IntVar()
        self._xonxoff = IntVar()
        self._timeout = StringVar()

        self._body()
        self._do_layout()
        self._get_ports()
        self._attach_events()
        self.reset()

    def _body(self):
        """
        Set up widgets.
        """

        self._frm_basic = Frame(self)
        self._lbl_port = Label(self._frm_basic, text="Port")
        self._lbx_port = Listbox(
            self._frm_basic,
            border=2,
            relief="sunken",
            bg=self._readonlybg,
            width=28,
            height=5,
            justify=LEFT,
            exportselection=False,
        )
        self._scr_portv = Scrollbar(self._frm_basic, orient=VERTICAL)
        self._scr_porth = Scrollbar(self._frm_basic, orient=HORIZONTAL)
        self._lbx_port.config(yscrollcommand=self._scr_portv.set)
        self._lbx_port.config(xscrollcommand=self._scr_porth.set)
        self._scr_portv.config(command=self._lbx_port.yview)
        self._scr_porth.config(command=self._lbx_port.xview)
        self._lbl_bpsrate = Label(self._frm_basic, text="Rate bps")
        self._spn_bpsrate = Spinbox(
            self._frm_basic,
            values=self._bpsrate_rng,
            width=8,
            state=READONLY,
            readonlybackground=self._readonlybg,
            wrap=True,
            textvariable=self._bpsrate,
        )
        self._btn_toggle = Button(
            self._frm_basic, text=ADVOFF, width=3, command=self._on_toggle_advanced
        )

        self._frm_advanced = Frame(self)
        self._lbl_databits = Label(self._frm_advanced, text="Data Bits")
        self._spn_databits = Spinbox(
            self._frm_advanced,
            values=self._databits_rng,
            width=3,
            state=READONLY,
            readonlybackground=self._readonlybg,
            wrap=True,
            textvariable=self._databits,
        )
        self._lbl_stopbits = Label(self._frm_advanced, text="Stop Bits")
        self._spn_stopbits = Spinbox(
            self._frm_advanced,
            values=self._stopbits_rng,
            width=3,
            state=READONLY,
            readonlybackground=self._readonlybg,
            wrap=True,
            textvariable=self._stopbits,
        )
        self._lbl_parity = Label(self._frm_advanced, text="Parity")
        self._spn_parity = Spinbox(
            self._frm_advanced,
            values=self._parity_rng,
            width=6,
            state=READONLY,
            readonlybackground=self._readonlybg,
            wrap=True,
            textvariable=self._parity,
        )
        self._chk_rts = Checkbutton(
            self._frm_advanced, text="RTS/CTS", variable=self._rtscts
        )
        self._chk_xon = Checkbutton(
            self._frm_advanced, text="Xon/Xoff", variable=self._xonxoff
        )
        self._lbl_timeout = Label(self._frm_advanced, text="Timeout (s)")
        self._spn_timeout = Spinbox(
            self._frm_advanced,
            values=self._timeout_rng,
            width=4,
            state=READONLY,
            readonlybackground=self._readonlybg,
            wrap=True,
            textvariable=self._timeout,
        )

    def _do_layout(self):
        """
        Layout widgets.
        """

        self._frm_basic.grid(column=0, row=0, columnspan=4, sticky=(W, E))
        self._lbl_port.grid(column=0, row=0, sticky=(W))
        self._lbx_port.grid(column=1, row=0, sticky=(W, E), padx=3, pady=3)
        self._scr_portv.grid(column=2, row=0, sticky=(N, S))
        self._scr_porth.grid(column=1, row=1, sticky=(E, W))
        self._lbl_bpsrate.grid(column=0, row=2, sticky=(W))
        self._spn_bpsrate.grid(column=1, row=2, sticky=(W), padx=3, pady=3)
        self._btn_toggle.grid(column=2, row=2, sticky=(E))

        self._frm_advanced.grid_forget()
        self._lbl_databits.grid(column=0, row=0, sticky=(W))
        self._spn_databits.grid(column=1, row=0, sticky=(W), padx=3, pady=3)
        self._lbl_stopbits.grid(column=2, row=0, sticky=(W))
        self._spn_stopbits.grid(column=3, row=0, sticky=(W), padx=3, pady=3)
        self._lbl_parity.grid(column=0, row=1, sticky=(W))
        self._spn_parity.grid(column=1, row=1, sticky=(W), padx=3, pady=3)
        self._chk_rts.grid(column=2, row=1, sticky=(W))
        self._chk_xon.grid(column=3, row=1, sticky=(W), padx=3, pady=3)
        self._lbl_timeout.grid(column=0, row=2, sticky=(W))
        self._spn_timeout.grid(column=1, row=2, sticky=(W), padx=3, pady=3)

    def _attach_events(self):
        """
        Bind events to widgets.
        """

        self._lbx_port.bind("<<ListboxSelect>>", self._on_select_port)

    def _get_ports(self):
        """
        Populate list of available serial ports using pyserial comports tool.

        Attempt to automatically select a serial device matching
        a list of 'preselect' devices (only works on platforms
        which parse UART device desc or HWID e.g. Posix).
        """

        self._ports = sorted(comports())
        init_idx = 0
        port = ""
        desc = ""
        if len(self._ports) > 0:
            for idx, (port, desc, _) in enumerate(self._ports, 1):
                self._lbx_port.insert(idx, port + ": " + desc)
                for dev in self._preselect:
                    if dev in desc:
                        init_idx = idx
                        break
            self._noports = False
        else:
            self._noports = True
            self.enable_controls(True)
        self._lbx_port.activate(init_idx)
        self._port.set(port)
        self._port_desc.set(desc)

    def _on_select_port(self, *args, **kwargs):  # pylint: disable=unused-argument
        """
        Get selected port from listbox and set global variable.
        """

        idx = self._lbx_port.curselection()
        if idx == "":
            idx = 0
        port_orig = self._lbx_port.get(idx)
        port = port_orig[0: port_orig.find(":")]
        desc = port_orig[port_orig.find(":") + 1:]
        if desc == "":
            desc = "device"
        self._port.set(port)
        self._port_desc.set(desc)

    def _on_toggle_advanced(self):
        """
        Toggle advanced serial port settings panel on or off.
        """

        self._show_advanced = not self._show_advanced
        if self._show_advanced:
            self._frm_advanced.grid(column=0, row=1, columnspan=3, sticky=(W, E))
            self._btn_toggle.config(text=ADVON)
        else:
            self._frm_advanced.grid_forget()
            self._btn_toggle.config(text=ADVOFF)

    def enable_controls(self, disabled: bool=False):
        """
        Enable or disable controls (e.g. to prevent
        changes when serial device is connected).

        :param bool disabled: disable controls flag
        """

        for widget in (
            self._lbl_port,
            self._lbl_bpsrate,
            self._lbl_databits,
            self._lbl_stopbits,
            self._lbl_parity,
            self._lbl_timeout,
            self._chk_rts,
            self._chk_xon,
            self._lbx_port,
        ):
            widget.configure(state=(DISABLED if disabled else NORMAL))
        for widget in (
            self._spn_bpsrate,
            self._spn_databits,
            self._spn_stopbits,
            self._spn_parity,
            self._spn_timeout,
        ):
            widget.configure(state=(DISABLED if disabled else READONLY))

    def reset(self):
        """
        Reset settings to defaults (first value in range).
        """

        self._bpsrate.set(self._bpsrate_rng[0])
        self._databits.set(self._databits_rng[0])
        self._stopbits.set(self._stopbits_rng[0])
        self._parity.set(self._parity_rng[0])
        self._rtscts.set(False)
        self._xonxoff.set(False)
        self._timeout.set(self._timeout_rng[0])

    @property
    def noports(self) -> bool:
        """
        Getter for noports flag, which indicates if there are
        no serial ports available.

        :return: noports flag (True/False)
        :rtype: bool
        """

        return self._noports

    @property
    def port(self) -> str:
        """
        Getter for port.

        :return: selected port
        :rtype: str
        """

        return self._port.get()

    @property
    def port_desc(self) -> str:
        """
        Getter for port description.

        :return: selected port description
        :rtype: str
        """

        return self._port_desc.get()

    @property
    def bpsrate(self) -> int:
        """
        Getter for bps rate (commonly but incorrectly referred to as baud rate).

        :return: selected baudrate
        :rtype: int
        """

        return self._bpsrate.get()

    @property
    def databits(self) -> int:
        """
        Getter for databits.

        :return: selected databits
        :rtype: int
        """

        return self._databits.get()

    @property
    def stopbits(self) -> float:
        """
        Getter for stopbits.

        :return: selected stopbits
        :rtype: float
        """

        return self._stopbits.get()

    @property
    def parity(self) -> str:
        """
        Getter for parity.

        :return: selected parity
        :rtype: str
        """

        return PARITIES[self._parity.get()]

    @property
    def rtscts(self) -> bool:
        """
        Getter for rts/cts.

        :return: selected rts/cts
        :rtype: bool
        """

        return self._rtscts.get()

    @property
    def xonxoff(self) -> bool:
        """
        Getter for xon/xoff.

        :return: selected xon/xoff
        :rtype: bool
        """

        return self._xonxoff.get()

    @property
    def timeout(self) -> float:
        """
        Getter for timeout.

        :return: selected timeout
        :rtype: float (or None)
        """

        if self._timeout.get() == "None":
            return None
        return float(self._timeout.get())
Esempio n. 5
0
class AutocompleteEntry(Entry):

    def __init__(self, *args, **kwargs):
        Entry.__init__(self, width=100, *args, **kwargs)

        self.focus_set()
        self.pack()

        self.var = self["textvariable"]
        if self.var == '':
            self.var = self["textvariable"] = StringVar()

        self.var.trace('w', self.changed)
        self.bind("<Right>", self.selection)
        self.bind("<Up>", self.up)
        self.bind("<Down>", self.down)
        self.bind("<Return>", self.enter)
        self.lb_up = False
        self.lb = None

    def enter(self, event):
        print(event)

    def changed(self, name, index, mode):

        if self.var.get() == '':
            if self.lb:
                self.lb.destroy()
            self.lb_up = False
        else:
            words = self.comparison()
            if words:
                if not self.lb_up:
                    self.lb = Listbox(master=root, width=100)

                    self.lb.bind("<Double-Button-1>", self.selection)
                    self.lb.bind("<Right>", self.selection)
                    self.lb.place(x=self.winfo_x(), y=self.winfo_y()+self.winfo_height())
                    self.lb_up = True

                self.lb.delete(0, END)
                for w in words:
                    self.lb.insert(END,w)
            else:
                if self.lb_up:
                    self.lb.destroy()
                    self.lb_up = False

    def selection(self, _):

        if self.lb_up:
            self.var.set(self.lb.get(ACTIVE))
            self.lb.destroy()
            self.lb_up = False
            self.icursor(END)

    def up(self, _):

        if self.lb_up:
            if self.lb.curselection() == ():
                index = '0'
            else:
                index = self.lb.curselection()[0]
            if index != '0':
                self.lb.selection_clear(first=index)
                index = str(int(index)-1)
                self.lb.selection_set(first=index)
                self.lb.activate(index)

    def down(self, _):

        if self.lb_up:
            if self.lb.curselection() == ():
                index = '0'
            else:
                index = self.lb.curselection()[0]
            if index != END:
                self.lb.selection_clear(first=index)
                index = str(int(index)+1)
                self.lb.selection_set(first=index)
                self.lb.activate(index)

    def comparison(self):
        q = self.var.get()
        q = str(q.decode('utf8'))
        for hit in searcher.search(qp.parse(q), limit=50):
            if hit['author']:
                yield '%s. "%s"' % (hit['author'], hit['title'])
            else:
                yield hit['title']
Esempio n. 6
0
class TMaterialsWindow(Frame):
    """
    Class represents auxiliary window containg materials database.
    """
    def __init__(self, master, TApp, TShapesWindow):
        """
        Call the parent class constructor and initialise object variables.
        """
        super().__init__()
        self.TApp = TApp
        self.TShapesWindow = TShapesWindow
        self.round_digits = 2
        self.init_widgets ()
        # Bind this class methods to manin menubar
        self.TApp.file_menu.entryconfig("Open materials", command = self.open_file)
        self.TApp.file_menu.entryconfig("Save materials", command = self.save_file)
        
    def init_widgets(self):
        """
        Initialise widgets.
        """
        # Set weights for columns and rows
        for i in range(6):
            self.grid_columnconfigure (i, weight = 1, uniform = "material_cols", minsize = 50)
        self.grid_rowconfigure (1, weight = 1)
        # self.grid_rowconfigure (2, weight = 1)

        # Create and arrange widgets (using grid)
        self.open_file_button = Button(self, text = "Open", command = self.open_file)
        self.open_file_button.grid(row = 0, column = 0, sticky = NSEW, columnspan = 3, padx = 20, pady = 5)
        self.save_file_button = Button(self, text = "Save", command = self.save_file)
        self.save_file_button.grid(row = 0, column = 3, sticky = NSEW, columnspan = 3, padx = 20, pady = 5)

        # ListBox
        self.materials_list = Listbox(self, exportselection = False)
        self.materials_list.grid(row = 1, column = 0, columnspan = 6, sticky = NSEW, padx = (5, 25), pady = 5)
        self.materials_list.bind("<<ListboxSelect>>", self.material_list_selected_item)

        # ListBox's y-scrollbar
        self.materials_list_scrollbar = Scrollbar(self, orient = VERTICAL, command = self.materials_list.yview)
        self.materials_list_scrollbar.grid(row = 1, column = 5, sticky = NS + E, padx = (0, 5), pady = 5)
        self.materials_list.config(yscrollcommand = self.materials_list_scrollbar.set)

        self.name_label = Label(self, text = "Name", anchor = W)
        self.name_label.grid(row = 2, column = 0, columnspan = 1, sticky = EW)
        self.name_entry = Entry(self, text = "")
        self.name_entry.grid(row = 2, column = 1, columnspan = 5, sticky = NSEW, padx = 5, pady = 2)
        self.epsilon_r_label = Label(self, text = "\u03b5r", anchor = W)
        self.epsilon_r_label.grid(row = 3, column = 0, columnspan = 1, sticky = EW)
        self.epsilon_r_entry = Entry(self, text = "")
        self.epsilon_r_entry.grid(row = 3, column = 1, columnspan = 5, sticky = NSEW, padx = 5, pady = 2)
        self.sigma_label = Label(self, text = "\u03c3", anchor = W)
        self.sigma_label.grid(row = 4, column = 0, columnspan = 1, sticky = EW)
        self.sigma_entry = Entry(self, text = "")
        self.sigma_entry.grid(row = 4, column = 1, columnspan = 5, sticky = NSEW, padx = 5, pady = 2)
        self.mu_r_label = Label(self, text = "\u03bcr", anchor = W)
        self.mu_r_label.grid(row = 5, column = 0, columnspan = 1, sticky = EW)
        self.mu_r_entry = Entry(self, text = "")
        self.mu_r_entry.grid(row = 5, column = 1, columnspan = 5, sticky = NSEW, padx = 5, pady = 2)
        self.sigma_mag_label = Label(self, text = "\u03c3*", anchor = W)
        self.sigma_mag_label.grid(row = 6, column = 0, columnspan = 1, sticky = EW)
        self.sigma_mag_entry = Entry(self, text = "")
        self.sigma_mag_entry.grid(row = 6, column = 1, columnspan = 5, sticky = NSEW, padx = 5, pady = 2)

        self.store_changed_params_button = Button(self, text = "Change", command = self.store_material_parameters)
        self.store_changed_params_button.grid(row = 7, column = 0, columnspan = 2, sticky = NSEW, padx = 5, pady = 5)
        self.delete_material_button = Button(self, text = "Delete", command = self.delete_material)
        self.delete_material_button.grid(row = 7, column = 2, columnspan = 2, sticky = NSEW, padx = 5, pady = 5)
        self.add_material_button = Button(self, text = "Add", command = self.add_material)
        self.add_material_button.grid(row = 7, column = 4, columnspan = 2, sticky = NSEW, padx = 5, pady = 5)

    def open_file(self):
        """
        Read an ASCII file containing materials data.
        """
        filename = filedialog.askopenfilename(initialdir = '.', title = "Select file", \
                    filetypes = [("All files", "*.*")])
        
        try:
            # Check, if given name is empty string
            if(filename == ""):
                raise Exception("No filename given!")
            # Check, if given file is binary
            if(self.is_binary(filename)):
                raise Exception("Designated file is binary!")
            else:
                file = open(filename, "rt")
        except Exception as message:
            messagebox.showerror("File error", message)
            return

        try:
            self.TApp.material = []
        except Exception as message:
            messagebox.showerror("Materials list error", message)
            return

        # Loop reading and parsing all lines one by one
        line_num = 1
        try:
            for line in file:
                if(line[0] != "#"):
                    # Omit lines that don't begin with hash sign (comments)
                    continue
                else:
                        tokens = line.split()
                        if(len(tokens) == 6):
                            epsilon_r = float(tokens[1])
                            sigma = float(tokens[2])
                            mu_r = float(tokens[3])
                            sigma_mag = float(tokens[4])
                            name = str(tokens[5])
                            self.TApp.materials.append(TMaterial(epsilon_r = epsilon_r, \
                                                                 sigma = sigma, \
                                                                 mu_r = mu_r, \
                                                                 sigma_mag = sigma_mag,\
                                                                 name = name))
                        else:
                            raise Exception("Invalid number of inputs in line {}!".format(line_num))
                line_num += 1
        except Exception as message:
            messagebox.showerror("Invalid input format", message)
            self.TApp.materials = []
            self.materials_list.delete(0, self.materials_list.size () )
            return
        finally:
            file.close()

        # Check whether any materials were read
        if(len(self.TApp.materials) == 0):
            messagebox.showwarning("Empty file", "File does not contain any materials' information.")

        # Repleace material's list
        self.update_list(self.TApp.materials)
    
    def save_file(self):
        """
        Save current materials database to an ASCII file.
        """
        filename = filedialog.asksaveasfilename(initialdir = '.', title = "Select file", \
                                                filetypes = [("All files", "*.*")])

        try:
            # Check, if given name is empty string
            if(filename == ""):
                raise Exception("No filename given!")
            else:
                file = open(filename, "wt")
        except Exception as message:
            messagebox.showerror("File error", message)
            return
        
        try:
            if(len(self.TApp.materials) == 0):
                raise Exception ("Materials' list is empty!")
            else:
                for single_material in self.TApp.materials:
                    file.write("# " + str(single_material.epsilon_r) + " " + \
                               str(single_material.sigma) + \
                               " " + str (single_material.mu_r) + " " + \
                               str(single_material.sigma_mag) + " " + \
                               str(single_material.name) + "\n")
                file.close()
        except Exception as message:
            messagebox.showerror("Error while writing file", message)
            return
        finally:
            file.close()
        
    
    def update_list(self, materials):
        """
        Update shapes list.

        :param materials: new materials database.
        :type materials: list
        """
        self.materials_list.delete(0, self.materials_list.size())
        i = 0
        info_string = ""
        materials_names_str = ["pec", "free_space"]
        for single_material in materials:
            info_string += str(single_material.name) + ": " + str(single_material.epsilon_r)+ " " + str(single_material.sigma) + " " + \
                str(single_material.mu_r) + " " + str(single_material.sigma_mag)
            materials_names_str.append(str(single_material.name))
            try:
                self.materials_list.insert (i, info_string)
            except Exception as message:
                messagebox.showerror ("List error", message)
                self.materials_list.delete (0, self.materials_list.size () )
                return None
            i += 1
            info_string = ""
        # Update shapes window combobox
        self.TShapesWindow.material_box.config(values = materials_names_str)

    def get_selected_item_num(self):
        """
        Retrieve a index of a selected material on the list.

        :rtype: integer
        """
        try:
            selection = self.materials_list.curselection()
            return selection[0]
        # except Exception as message:
        except:
            #messagebox.showerror("No material selected!", message)
            return -1

    def material_list_selected_item(self, event):
        """
        Display selected material parameters in the text fields.

        :param event: listbox LMB click event.
        :type event: tkinter.Event
        """
        item_num = self.get_selected_item_num()
        if(item_num < 0):
            return None
        else:
            try:
                material = self.TApp.materials[item_num]
            except Exception as message:
                messagebox.showerror("Materials' list error", message)
                return None

        self.name_entry.delete(0, END)
        self.name_entry.insert(0, material.name)
        self.epsilon_r_entry.delete(0, END)
        self.epsilon_r_entry.insert(0, material.epsilon_r)
        self.sigma_entry.delete(0, END)
        self.sigma_entry.insert(0, material.sigma)
        self.mu_r_entry.delete(0, END)
        self.mu_r_entry.insert(0, material.mu_r)
        self.sigma_mag_entry.delete(0, END)
        self.sigma_mag_entry.insert(0, material.sigma_mag)

        self.materials_list.activate(item_num)
    
    def store_material_parameters(self):
        """
        Update material parameters from values entered in the text fields.
        """
        item_num = self.get_selected_item_num()
        if(item_num < 0):
            return None
        else:
            try:
                self.TApp.materials[item_num].name = str(self.name_entry.get())
                self.TApp.materials[item_num].epsilon_r = float(self.epsilon_r_entry.get())
                self.TApp.materials[item_num].sigma = float(self.sigma_entry.get())
                self.TApp.materials[item_num].mu_r = float(self.mu_r_entry.get())
                self.TApp.materials[item_num].sigma_mag = float(self.sigma_mag_entry.get())
                self.update_list(self.TApp.materials)
                self.materials_list.select_set(item_num)
            except Exception as message:
                messagebox.showerror("Materials' list error", message)

    def delete_material(self):
        """
        Delete a material from the database.
        """
        item_num = self.get_selected_item_num()
        if (item_num < 0):
            return None
        else:
            try:
                del self.TApp.materials[item_num]
                self.update_list(self.TApp.materials)
                if(item_num == 0):
                    self.materials_list.select_set(0)
                else:
                    self.materials_list.select_set(item_num - 1)
            except Exception as message:
                messagebox.showerror("Materials' list error", message)

    def add_material(self):
        """
        Add a material to the database.
        """
        try:
            if(str(self.name_entry.get()) == ""):
                raise Exception("Material can't have name that's an empty string!")
            self.TApp.materials.append(TMaterial(epsilon_r = float(self.epsilon_r_entry.get()), \
                                                 sigma = float(self.sigma_entry.get()),\
                                                 mu_r = float(self.mu_r_entry.get()), \
                                                 sigma_mag = float(self.sigma_mag_entry.get()), \
                                                 name = str(self.name_entry.get())))
        except Exception as message:
            messagebox.showerror("Error while creating material", message)
        self.update_list(self.TApp.materials)
        self.materials_list.select_set(END)

    def is_binary(self, filename):
        """
        Check whether given file is binary (that is non-text).
        """
        try:
            with open(filename, 'tr') as check_file:    # try open file in text mode
                check_file.read()
                return False
        except:                                         # if it fails then file is non-text (binary)
            return True
        finally:
            check_file.close()
Esempio n. 7
0
class Editor:

    # Info Defaults
    LOG_FILE = 'editor.log'

    devices = []
    vidPK = []
    vidPATH = []
    vidNAME = []
    uuid = []
    uuidFK = []

    def __init__(self, master, soundGenerator, rfidScanner):
        self.environment = Environment()
        self.soundProvider = SoundProvider(soundGenerator)
        self.configureScannerProvider(rfidScanner)
        self.load()
        frame = Frame(master)
        frame.pack()
        self.activeCardNumber = StringVar()
        self.usbSpin = StringVar()
        self.usbSpin.set(self.environment.Usb)
        Label(frame, text='RFID Card').grid(row=0, column=0)
        Label(frame, text='Video').grid(row=0, column=2)
        self.ee = Entry(frame, textvariable=self.activeCardNumber,
                        state=DISABLED, disabledforeground='black')
        self.ee.grid(row=1, column=0)
        self.r = Button(frame, text='Read Card', command=self.startCardProcess)
        self.r.grid(row=1, column=1)
        self.box = Listbox(frame)
        for entry in self.vidNAME:
            self.box.insert(END, entry)
        self.box.bind("<<ListboxSelect>>", self.newselection)
        self.box.grid(row=1, rowspan=5, column=2, columnspan=2)
        self.scroll = Scrollbar(self.box, orient=VERTICAL)
        self.box.config(yscrollcommand=self.scroll.set)
        self.scroll.config(command=self.box.yview)
        Button(frame, text='Assign Kill Code',
               command=self.createKiller).grid(row=2, column=0)
        Label(frame, text='Source USB').grid(row=4, column=0)
        self.spin = Spinbox(frame, values=self.devices)
        self.spin.delete(0, END)
        self.spin.insert(0, self.environment.Usb)
        self.spin.grid(row=5, column=0)
        self.status = Button(frame, text='Update Device Repository',
                             command=self.updateDevice, disabledforeground='blue')
        self.status.grid(row=6, column=0)
        Button(frame, text='Save', command=self.save).grid(row=6, column=2)
        Button(frame, text='Quit', command=self.closeWithSavePrompt).grid(
            row=6, column=3)
    
    def configureScannerProvider(self, rfidScanner):
        provider = RFIDScannerProvider(rfidScanner)
        self.RFIDScannerProvider = provider.PN532(
            int(self.environment.CHIP_SELECT_PIN),
            int(self.environment.MASTER_OUTPUT_SLAVE_INPUT_PIN),
            int(self.environment.MASTER_INPUT_SLAVE_OUTPUT_PIN),
            int(self.environment.SERIAL_CLOCK_PIN))

    def closeWithSavePrompt(self):
        ans = messagebox.askquestion(
            'Save And Quit', 'Would you like to save your changes?')
        if ans == 'yes':
            self.save()
        sys.exit(0)

    def startCardProcess(self):
        # Disable button to prevent event stacking
        self.r.config(state=DISABLED)
        self.processCard()
        self.r.config(state=NORMAL)

    def processCard(self):
        # Scans RFID cards and sets them to text box
        try:
            self.processCardUnchecked()
        except Exception as e:
            self.displayScanError(e)

    def processCardUnchecked(self):
        cardScan = CardScanWrapper(self.soundS, self.RFIDScannerProvider)
        cardScan.runScan()
        self.processResult(cardScan.getFormattedResult())

    def processResult(self, scanResult):
        if scanResult == None:
            return
        self.activeCardNumber.set(scanResult)     # Populate text box
        self.deselectActiveListboxItems()
        self.linkCardWithListbox(scanResult)

    def deselectActiveListboxItems(self):
        # De-select any active items in listbox
        self.box.selection_clear(0, END)

    def linkCardWithListbox(self, scanResult):
        index = self.verifyCard(scanResult)
        if str(self.uuidFK[index]) == self.environment.KillCommand:
            messagebox.showinfo(
                'Kill Card', 'This card is currently assigned to kill the application.')
            return
        self.highlightItemInListbox(index)

    def highlightItemInListbox(self, index):
        try:
            i = self.vidPK.index(self.uuidFK[index])
        except:
            messagebox.showinfo('Card Unassigned',
                                'Card is not currently assigned to a video')
        else:
            self.box.see(i)
            self.box.selection_clear(0, END)
            self.box.selection_set(i)
            self.box.activate(i)

    def verifyCard(self, uidt):
        try:
            uuidIndex = self.uuid.index(uidt)
        except:
            uuidIndex = self.addNewCard(uidt)
        return uuidIndex

    def addNewCard(self, uidt):
        self.uuid.append(uidt)
        self.uuidFK.append(-1)
        newIndex = len(self.uuid) - 1
        return newIndex

    def displayScanError(self, e):
        messagebox.showerror('Error Occurred', 'Error: ' + str(e))
        logging.error('Scan Failed: ' + str(e))

    def save(self):
        toSaveList = self.makePairedList(
            self.vidPK, self.vidNAME, self.vidPATH)
        self.safeSaveToFile(self.environment.VideoList, toSaveList)
        toSaveList = self.makePairedList(self.uuid, self.uuidFK)
        self.safeSaveToFile(self.environment.UuidTable, toSaveList)

    def makePairedList(self, *itemLists):
        stop = len(itemLists)
        subList = []
        listAll = []
        for listIndex in range(len(itemLists[0])):
            del subList[:]
            for indice in range(stop):
                subList.append(itemLists[indice][listIndex])
            listAll.append(list(subList))
        return listAll

    def safeSaveToFile(self, fileName, pairList):
        try:
            self.writePairedListToTempFile(fileName, pairList)
        except Exception as e:
            logging.error('Failed to create video list: ' + str(e))
        else:
            self.replaceOriginalFileWithItsTemp(fileName)

    def replaceOriginalFileWithItsTemp(self, fileName):
        try:
            if os.path.isfile(fileName):
                os.remove(fileName)
            os.rename(fileName + '.temp', fileName)
        except Exception as e:
            logging.error('Failed to replace old video list: ' + str(e))

    def writePairedListToTempFile(self, fileName, pairedList):
        f = open(fileName + '.temp', 'w')
        self.writePairedListGivenFile(f, pairedList)
        f.close()

    def writePairedListGivenFile(self, f, pairedList):
        i = 0
        while(i < len(pairedList) - 1):
            self.writeSingleLineOfPairedListToOpenFile(f, pairedList, i)
            f.write('\n')
            i = i+1
        self.writeSingleLineOfPairedListToOpenFile(f, pairedList, i)

    def writeSingleLineOfPairedListToOpenFile(self, f, pairedList, itemIndex):
        fLine = ""
        for item in range(len(pairedList[itemIndex])):
            fLine = fLine + str(pairedList[itemIndex][item]) + ','
        f.write(fLine[:-1])

    def updateDevice(self):
        scan = self.safeScan()
        if scan != None:
            self.safeProcessScan(scan)
        self.status.config(text='Update Device Repository', state=NORMAL)
        self.status.update_idletasks()

    def safeScan(self):
        scan = None
        try:
            scan = self.runScannerWithNotification()
        except Exception as e:
            self.showScanErrorMessage(e)
        return scan

    def runScannerWithNotification(self):
        self.status.config(text='Scanning...', state=DISABLED)
        self.status.update_idletasks()
        scan = ScriptedFileSearch(subprocess)
        scan.scan("scanner.sh")
        return scan

    def showScanErrorMessage(self, e):
        messagebox.showerror('Scan Failed', 'Scan error: ' + str(e))
        logging.error(str(e))

    def safeProcessScan(self, scan):
        try:
            self.processScan(scan)
        except Exception as e:
            self.showErrorMessage(e)

    def showErrorMessage(self, e):
        messagebox.showerror('Error', 'Error: ' + str(e))
        logging.error(str(e))

    def refreshListBox(self):
        self.box.delete(0, END)
        for entry in self.vidNAME:
            self.box.insert(END, entry)

    def processScan(self, scan):
        # Check if a scan turned up any results
        if self.scanIsEmpty(scan):
            self.showAbortScanMessage()
            return
        self.verifyUSB()
        self.processScanFiles(scan)
        self.refreshListBox()

    def showAbortScanMessage(self):
        messagebox.showwarning(
            'No Files Found', 'A scan failed to find any files.')
        logging.warning('Empty Scan occurred when attempting a merge')

    def scanIsEmpty(self, scan):
        return len(scan.NAME) == 0

    def verifyUSB(self):
        if self.environment.Usb != self.spin.get():
            self.Usb = self.spin.get()
            self.environment.update()

    def processScanFiles(self, scan):
        i = 0
        j = 0
        newPK = []
        newName = []
        newPath = []
        self.status.config(text='Reading Files...')
        self.status.update_idletasks()
        # Iterate through list
        while i < len(scan.NAME):
            # Verifiy File
            try:
                if scan.PATH[i].find(self.environment.Usb) >= 0:
                    # File resides on repository - update FK
                    try:
                        # Locate matching entry
                        fkk = self.vidNAME.index(scan.NAME[i])
                    except Exception as e:
                        # No matching entry
                        logging.info('New file found in repository: ' + str(e))
                        pass
                    else:
                        # Update FK on uuid table
                        for uu in self.uuidFK:
                            if uu == self.vidPK[fkk]:
                                uu = scan.PK[i]
                    # Store entry in new Tables
                    newPK.append(scan.PK[i])
                    newName.append(scan.NAME[i])
                    newPath.append(scan.PATH[i])
                else:
                    # Video resides on updating device - check if file already copied
                    found = False
                    while j < len(scan.NAME):
                        if str(scan.NAME[i]) == str(scan.NAME[j]) and scan.PATH[j].find(self.environment.Usb) >= 0:
                            found = True
                            break
                        j = j + 1
                    if not found:
                        # Copy file and append
                        try:
                            # Get device name
                            device = scan.PATH[i].replace('/media/pi/', '')
                            device = device[0:device.find('/')]
                            # Copy
                            self.status.config(
                                text='Copying ' + scan.NAME[i] + '...')
                            self.status.update_idletasks()
                            shutil.copyfile(
                                scan.PATH[i], scan.PATH[i].replace(device, self.environment.Usb))
                        except Exception as e:
                            logging.error('Failed to copy' +
                                          scan.NAME[i] + ': ' + str(e))
                        else:
                            # Add to new array
                            newPK.append(scan.PK[i])
                            newName.append(scan.NAME[i])
                            newPath.append(
                                scan.PATH[i].replace(device, self.environment.Usb))
            except Exception as e:
                logging.error(str(e))
            i = i+1
        del self.vidNAME[:]
        del self.vidPATH[:]
        del self.vidPK[:]
        self.vidNAME = newName
        self.vidPATH = newPath
        self.vidPK = newPK

    def newselection(self, event):
        # Fires when a new item is selected in the listbox
        selection = event.widget.curselection()
        try:
            txt = self.ee.get()
            if txt == '':
                return
            i = self.uuid.index(txt)
            self.uuidFK[i] = self.vidPK[selection[0]]
        except Exception as e:
            messagebox.showerror('Error During Set', 'Error: ' + str(e))
            logging.error(str(e))

    def createKiller(self):
        try:
            self.assignCurrentCardAsKiller()
            self.box.selection_clear(0, END)
        except Exception as e:
            self.handleCardNotScannedError(e)

    def assignCurrentCardAsKiller(self):
        i = self.uuid.index(self.ee.get())
        self.uuidFK[i] = int(self.environment.KillCommand)

    def handleCardNotScannedError(self, e):
        messagebox.showinfo(
            'Card Not Scanned', 'Please scan a card to assign it a [Kill Application] code.' + str(e))
        logging.error(str(e))

    def load(self):
        # Generate Log
        logging.basicConfig(filename=self.LOG_FILE, level=logging.INFO)
        # Load Sound file
        self.soundProvider.init()
        self.soundProvider.mixer.pre_init(44100, -16, 12, 512)
        # pygame.init() IS this only for linux distribution?
        self.soundS = self.soundProvider.mixer.Sound(self.environment.SCAN_SOUND)
        self.soundS.set_volume(1)
        # Create an instance of the PN532 class.
        self.RFIDScannerProvider.begin())
        # Configure PN532 to communicate with MiFare cards.
        self.RFIDScannerProvider.SAM_configuration()
        self.loadFiles()
        self.locateDevices()
        self.loadDevice()

    def loadFiles(self):
        self.readCSV(self.environment.VideoList, (int, self.vidPK),
                     (str, self.vidNAME), (str, self.vidPATH))
        self.readCSV(self.environment.UuidTable,
                     (str, self.uuid), (int, self.uuidFK))
Esempio n. 8
0
class ListboxVidget(Vidget, Eventor):
    """
    ListboxVidget contains a Listbox widget. It adds the following abilities:
    - Store items of any type, unlike Listbox widget that only stores texts.
    - Remember selected item even if the listbox widget lost focus.
    - Notify pre-change and post-change events.
    """

    # Error raised when trying to change the listbox while a change is going on
    class CircularCallError(ValueError):
        pass

    # Error raised when trying to change the listbox while it is disabled
    class DisabledError(ValueError):
        pass

    # Event notified when the listbox's items are to be changed
    ITEMS_CHANGE_SOON = 'ITEMS_CHANGE_SOON'

    # Event notified when the listbox's items are changed
    ITEMS_CHANGE_DONE = 'ITEMS_CHANGE_DONE'

    # Event notified when the listbox's active item is to be changed
    ITEMCUR_CHANGE_SOON = 'ITEMCUR_CHANGE_SOON'

    # Event notified when the listbox's active item is changed
    ITEMCUR_CHANGE_DONE = 'ITEMCUR_CHANGE_DONE'

    # Events list
    EVENTS = (
        ITEMS_CHANGE_SOON,
        ITEMS_CHANGE_DONE,
        ITEMCUR_CHANGE_SOON,
        ITEMCUR_CHANGE_DONE,
    )

    def __init__(
        self,
        items=None,
        item_to_text=None,
        normal_bg='',
        normal_fg='',
        active_bg='sky blue',
        active_fg='white',
        selected_bg='steel blue',
        selected_fg='white',
        master=None,
    ):
        """
        Initialize object.

        @param items: Items list.

        @param item_to_text: Item-to-text function. Default is `str`.

        @param normal_bg: Unselected item background color.

        @param normal_fg: Unselected item foreground color.

        @param active_bg: Active item background color. `Active` means the item
        is selected (in general meaning) but the listbox has no focus.

        @param active_fg: Active item foreground color. `Active` means the item
        is selected (in general meaning) but the listbox has no focus.

        @param selected_bg: Selected item background color. `Selected` means
        the item is selected (in general meaning) and the listbox has focus.

        @param selected_fg: Selected item foreground color. `Selected` means
        the item is selected (in general meaning) and the listbox has focus.

        @param master: Master widget.

        @return: None.
        """
        # Initialize Vidget.
        # Create main frame widget.
        Vidget.__init__(
            self,
            master=master,
        )

        # Initialize Eventor
        Eventor.__init__(self)

        # If items list is given
        if items is not None:
            # If items list is not list
            if not isinstance(items, list):
                # Raise error
                raise TypeError(items)

            # If items list is list.

        # If items list is not given, or items list is given and is list

        # Items list
        self._items = items if items is not None else []

        # Item-to-text function. Default is `str`.
        self._item_to_text = item_to_text if item_to_text is not None else str

        # Unselected item background color
        self._normal_fg = normal_fg

        # Unselected item foreground color
        self._normal_bg = normal_bg

        # Active item background color
        self._active_fg = active_fg

        # Active item foreground color
        self._active_bg = active_bg

        # Selected item background color
        self._selected_fg = selected_fg

        # Selected item foreground color
        self._selected_bg = selected_bg

        # Whether the listbox is changing
        self._is_changing = False

        # Active index. `-1` means void, i.e. no item is active.
        self._indexcur = -1

        # Whether active index is being reset to same value
        self._is_resetting = False

        # Create listbox widget
        self._listbox = Listbox(
            master=self.widget(),
            relief='groove',
            activestyle='none',
            highlightthickness=0,
            # Active index cache only supports single-selection mode for now.
            # See 2N6OR.
            selectmode='single',
        )

        # Set the listbox widget as config target
        self.config_target_set(self._listbox)

        # Create x-axis scrollbar
        self._scrollbar_xview = _HiddenScrollbar(
            self.widget(),
            orient=HORIZONTAL,
        )

        # Create y-axis scrollbar
        self._scrollbar_yview = _HiddenScrollbar(
            self.widget(),
            orient=VERTICAL,
        )

        # Mount scrollbars
        self._listbox.config(xscrollcommand=self._scrollbar_xview.set)

        self._listbox.config(yscrollcommand=self._scrollbar_yview.set)

        self._scrollbar_xview.config(command=self._listbox.xview)

        self._scrollbar_yview.config(command=self._listbox.yview)

        # Bind single-click event handler
        self._listbox.bind('<Button-1>', self._on_single_click)

        # Bind double-click event handler
        self._listbox.bind('<Double-Button-1>', self._on_double_click)

        # Update listbox widget
        self._listbox_widget_update(keep_active=False)

        # Update widget
        self._widget_update()

    def _widget_update(self):
        """
        Update widget.

        @return: None.
        """
        # Row 0 for listbox and y-axis scrollbar
        self.widget().rowconfigure(0, weight=1)

        # Row 1 for x-axis scrollbar
        self.widget().rowconfigure(1, weight=0)

        # Column 0 for listbox and x-axis scrollbar
        self.widget().columnconfigure(0, weight=1)

        # Column 1 for y-axis scrollbar
        self.widget().columnconfigure(1, weight=0)

        # Lay out listbox
        self._listbox.grid(row=0, column=0, sticky='NSEW')

        # Lay out x-axis scrollbar
        self._scrollbar_xview.grid(row=1, column=0, sticky='EW')

        # Lay out y-axis scrollbar
        self._scrollbar_yview.grid(row=0, column=1, sticky='NS')

    def is_enabled(self):
        """
        Test whether the listbox is enabled.

        @return: Boolean.
        """
        # Return whether the listbox is enabled
        return self._listbox.config('state')[4] != DISABLED

    def is_changing(self):
        """
        Test whether the listbox is changing.

        @return: Boolean.
        """
        # Return whether the listbox is changing
        return self._is_changing

    def is_resetting(self):
        """
        Test whether the listbox is setting active index to the same value.

        @return: Boolean.
        """
        # Return whether the listbox is setting active index to the same value
        return self._is_resetting

    def size(self):
        """
        Get number of items.

        @return: Number of items.
        """
        # Return number of items
        return len(self._items)

    def items(self):
        """
        Get items list.
        Notice do not change the list outside.

        @return: Items list.
        """
        # Return items list
        return self._items

    def items_set(
        self,
        items,
        notify=True,
        keep_active=False,
    ):
        """
        Set items list.

        Notice do not change the list outside.

        @param items: Items list.

        @param notify: Whether notify pre-change and post-change events.

        @param keep_active: Whether keep or clear active index.

        @return: None.
        """
        # If the items is not list
        if not isinstance(items, list):
            # Raise error
            raise TypeError(items)

        # If the items is list.

        # If the listbox is disabled
        if not self.is_enabled():
            # Raise error
            raise ListboxVidget.DisabledError()

        # If the listbox is not disabled.

        # If the listbox is changing
        if self._is_changing:
            # Raise error
            raise ListboxVidget.CircularCallError()

        # If the listbox is not changing.

        # Set changing flag on
        self._is_changing = True

        # If notify events
        if notify:
            # Notify pre-change event
            self.handler_notify(self.ITEMS_CHANGE_SOON)

        # Store the new items
        self._items = items

        # Update listbox widget
        self._listbox_widget_update(
            keep_active=keep_active
        )

        # If notify events
        if notify:
            # Notify post-change event
            self.handler_notify(self.ITEMS_CHANGE_DONE)

        # Set changing flag off
        self._is_changing = False

    def index_is_valid(self, index):
        """
        Test whether given index is valid. Notice -1 is not valid.

        @param index: Index to test.

        @return: Boolean.
        """
        # Test whether given index is valid
        return 0 <= index and index < self.size()

    def index_is_valid_or_void(self, index):
        """
        Test whether given index is valid or is -1.

        @param index: Index to test.

        @return: Boolean.
        """
        # Test whether given index is valid or is -1
        return index == -1 or self.index_is_valid(index)

    def index_first(self):
        """
        Get the first item's index.

        @return: First item's index, or -1 if the listbox is empty.
        """
        # Return the first item's index
        return 0 if self.size() > 0 else -1

    def index_last(self):
        """
        Get the last item's index.

        @return: Last item's index, or -1 if the listbox is empty.
        """
        # Return the last item's index
        return self.size() - 1

    def indexcur(self, internal=False, raise_error=False):
        """
        Get the active index.

        @param internal: See 2N6OR.

        @return: The active index. If no active active, either return -1, or
        raise IndexError if `raise_error` is True.
        """
        # Get active indexes
        indexcurs = self._indexcurs(internal=internal)

        # If have active indexes
        if indexcurs:
            # Return the first active index
            return indexcurs[0]

        # If no active indexes
        else:
            # If raise error
            if raise_error:
                # Raise error
                raise IndexError(-1)

            # If not raise error
            else:
                # Return -1
                return -1

    def _indexcurs(self, internal=False):
        """
        Get active indexes list.

        2N6OR
        @param internal: Whether use listbox widget's selected indexes, instead
        of cached active index.
        Notice listbox widget has no selected indexes if it has no focus.
        Notice using cached active index only supports single-selection mode,
        which means the result list has at most one index.

        @return: Active indexes list.
        """
        # If use listbox widget's selected indexes
        if internal:
            # Return listbox widget's selected indexes list
            return [int(x) for x in self._listbox.curselection()]

        # If not use listbox widget's selected indexes
        else:
            # If cached active index is valid
            if self.index_is_valid(self._indexcur):
                # Return a list with the cached active index
                return [self._indexcur]

            # If cached active index is not valid
            else:
                # Return empty list
                return []

    def indexcur_set(
        self,
        index,
        focus=False,
        notify=True,
        notify_arg=None,
    ):
        """
        Set active index.

        @param index: The index to set.

        @param focus: Whether set focus on the listbox widget.

        @param notify: Whether notify pre-change and post-change events.

        @param notify_arg: Event argument.

        @return: None.
        """
        # If the index is not valid or -1
        if not self.index_is_valid_or_void(index):
            # Raise error
            raise IndexError(index)

        # If the index is valid or is -1.

        # If the listbox is not enabled
        if not self.is_enabled():
            # Raise error
            raise ListboxVidget.DisabledError()

        # If the listbox is enabled.

        # If the listbox is changing
        if self._is_changing:
            # Raise error
            raise ListboxVidget.CircularCallError()

        # If the listbox is not changing.

        # Set changing flag on
        self._is_changing = True

        # Get old active index
        old_indexcur = self._indexcur

        # Set resetting flag on if new and old indexes are equal
        self._is_resetting = (index == old_indexcur)

        # If notify events
        if notify:
            # Notify pre-change event
            self.handler_notify(self.ITEMCUR_CHANGE_SOON, notify_arg)

        # If old active index is valid
        if self.index_is_valid(old_indexcur):
            # Set old active item's background color to normal color
            self._listbox.itemconfig(old_indexcur, background=self._normal_bg)

            # Set old active item's foreground color to normal color
            self._listbox.itemconfig(old_indexcur, foreground=self._normal_fg)

        # Cache new active index
        self._indexcur = index

        # Clear listbox widget's selection
        self._listbox.selection_clear(0, END)

        # Set listbox widget's selection
        self._listbox.selection_set(index)

        # Set listbox widget's activated index
        self._listbox.activate(index)

        # If new active index is valid
        if index != -1:
            # Set new active item's background color to active color
            self._listbox.itemconfig(index, background=self._active_bg)

            # Set new active item's foreground color to active color
            self._listbox.itemconfig(index, foreground=self._active_fg)

        # If set focus
        if focus:
            # Set focus on the listbox widget
            self._listbox.focus_set()

        # If new active index is valid
        if index != -1:
            # Make the active item visible
            self._listbox.see(index)

        # If notify events
        if notify:
            # Notify post-change event
            self.handler_notify(self.ITEMCUR_CHANGE_DONE, notify_arg)

        # Set resetting flag off
        self._is_resetting = False

        # Set changing flag off
        self._is_changing = False

    def indexcur_set_by_event(
        self,
        event,
        focus=False,
        notify=True,
        notify_arg=None,
    ):
        """
        Set active index using a Tkinter event object that contains coordinates
        of the active item.

        @param event: Tkinter event object.

        @param focus: Whether set focus on the listbox widget.

        @param notify: Whether notify pre-change and post-change events.

        @param notify_arg: Event argument.

        @return: None.
        """
        # Get the event's y co-ordinate's nearest listbox item index
        index = self._listbox.nearest(event.y)

        # If the index is not valid
        if not self.index_is_valid_or_void(index):
            # Ignore the event
            return

        # If the index is valid
        else:
            # Set the index as active index
            self.indexcur_set(
                index=index,
                focus=focus,
                notify=notify,
                notify_arg=notify_arg,
            )

    def item(self, index):
        """
        Get item at given index.

        @return: Item at given index, or IndexError if the index is not valid.
        """
        return self.items()[index]

    def itemcur(self, internal=False, raise_error=False):
        """
        Get the active item.

        @param internal: See 2N6OR.

        @param raise_error: Whether raise error if no active item.

        @return: The active item. If no active item, if `raise_error` is
        True, raise IndexError, otherwise return None.
        """
        # Get active index.
        # May raise IndexError if `raise_error` is True.
        indexcur = self.indexcur(
            internal=internal,
            raise_error=raise_error,
        )

        # If no active index
        if indexcur == -1:
            # Return None
            return None

        # If have active index
        else:
            # Return the active item
            return self.items()[indexcur]

    def item_insert(
        self,
        item,
        index=None,
        notify=True,
        keep_active=True,
    ):
        """
        Insert item at given index.

        @param item: Item to insert.

        @param index: Index to insert. `None` means active index, and if no
        active index, insert at the end.

        @param notify: Whether notify pre-change and post-change events.

        @param keep_active: Whether keep or clear active index.

        @return: None.
        """
        # If notify events
        if notify:
            # Notify pre-change events
            self.handler_notify(self.ITEMCUR_CHANGE_SOON)

            self.handler_notify(self.ITEMS_CHANGE_SOON)

        # Get old active index
        active_index = self.indexcur()

        # If the index is None,
        # it means use active index.
        if index is None:
            # Use active index.
            # `-1` works and means appending.
            index = active_index

        # Insert the item to the items list
        self._items.insert(index, item)

        # If old active index is valid
        if active_index != -1:
            # If old active index is GE the inserted index
            if active_index >= index:
                # Shift active index by one
                active_index += 1

            # If old active index is not GE the inserted index, use it as-is.

        # Set new active index
        self.indexcur_set(index=active_index, notify=False)

        # Update listbox widget
        self._listbox_widget_update(
            keep_active=keep_active
        )

        # If notify events
        if notify:
            # Notify post-change events
            self.handler_notify(self.ITEMS_CHANGE_DONE)

            self.handler_notify(self.ITEMCUR_CHANGE_DONE)

    def item_remove(
        self,
        index,
        notify=True,
        keep_active=True,
    ):
        """
        Remove item at given index.

        @param index: Index to remove.

        @param notify: Whether notify pre-change and post-change events.

        @param keep_active: Whether keep or clear active index.

        @return: None.
        """
        # If the index is not valid
        if not self.index_is_valid(index):
            # Raise error
            raise ValueError(index)

        # If the index is valid.

        # If notify events
        if notify:
            # Notify pre-change events
            self.handler_notify(self.ITEMCUR_CHANGE_SOON)

            self.handler_notify(self.ITEMS_CHANGE_SOON)

        # Get old active index
        active_index = self.indexcur()

        # Remove item at the index
        del self._items[index]

        # If old active index is valid
        if active_index != -1:
            # Get the last index
            index_last = self.index_last()

            # If old active index is GT the last index
            if active_index > index_last:
                # Use the last index as new active index
                active_index = index_last

            # If old active index is not GT the last index, use it as-is.

        # Set new active index
        self.indexcur_set(index=active_index, notify=False)

        # Update listbox widget
        self._listbox_widget_update(
            keep_active=keep_active
        )

        # If notify events
        if notify:
            # Notify post-change events
            self.handler_notify(self.ITEMS_CHANGE_DONE)

            self.handler_notify(self.ITEMCUR_CHANGE_DONE)

    def handler_add(
        self,
        event,
        handler,
        need_arg=False,
    ):
        """
        Add event handler for an event.
        If the event is ListboxVidget event, add the event handler to Eventor.
        If the event is not ListboxVidget event, add the event handler to
        listbox widget.

        Notice this method overrides `Eventor.handler_add` in order to add
        non-ListboxVidget event handler to listbox widget.

        @param event: Event name.

        @param handler: Event handler.

        @param need_arg: Whether the event handler needs event argument.

        @return: None.
        """
        # If the event is ListboxVidget event
        if event in self.EVENTS:
            # Add the event handler to Eventor
            return Eventor.handler_add(
                self,
                event=event,
                handler=handler,
                need_arg=need_arg,
            )

        # If the event is not ListboxVidget event,
        # it is assumed to be Tkinter widget event.
        else:
            # Add the event handler to listbox widget
            return self.bind(
                event=event,
                handler=handler,
            )

    def bind(
        self,
        event,
        handler,
    ):
        """
        Add event handler to listbox widget.

        ListboxVidget internally uses `<Button-1>` and `<Double-Button-1>` to
        capture active index changes. So if the given event is `<Button-1>` or
        `<Double-Button-1>`, the given handler will be wrapped.

        @param event: Event name.

        @param handler: Event handler.

        @return: None.
        """
        # If the event is not `<Button-1>` or `<Double-Button-1>`
        if event not in ['<Button-1>', '<Double-Button-1>']:
            # Add the event handler to listbox widget
            self._listbox.bind(event, handler)

        # If the event is `<Button-1>` or `<Double-Button-1>`
        else:
            # Create event handler wrapper
            def handler_wrapper(e):
                """
                Event handler wrapper that sets new active index and then calls
                the wrapped event handler.

                Setting new active index is needed because when this handler is
                called by Tkinter, the active index of the listbox is still
                old.

                @param e: Tkinter event object.

                @return: None.
                """
                # Set new active index
                self.indexcur_set_by_event(e, notify=True)

                # Call the wrapped event handler
                handler(e)

            # Add the event handler wrapper to the listbox widget
            self._listbox.bind(event, handler_wrapper)

    def _on_single_click(self, event):
        """
        `<Button-1>` event handler that updates active index.

        @param event: Tkinter event object.

        @return: None.
        """
        # Updates active index
        self.indexcur_set_by_event(event, notify=True)

    def _on_double_click(self, event):
        """
        `<Double-Button-1>` event handler that updates active index.

        @param event: Tkinter event object.

        @return: None.
        """
        # Updates active index
        self.indexcur_set_by_event(event, notify=True)

    def _listbox_widget_update(
        self,
        keep_active,
    ):
        """
        Update listbox widget's items and selection.

        @param keep_active: Whether keep or clear active index.

        @return: None.
        """
        # Remove old items from listbox widget
        self._listbox.delete(0, END)

        # Insert new items into listbox widget.
        # For each ListboxVidget items.
        for index, item in enumerate(self.items()):
            # Get item text
            item_text = self._item_to_text(item)

            # Insert the item text into listbox widget
            self._listbox.insert(index, item_text)

            # Set the item's normal background color
            self._listbox.itemconfig(index, background=self._normal_bg)

            # Set the item's normal foreground color
            self._listbox.itemconfig(index, foreground=self._normal_fg)

            # Set the item's selected background color
            self._listbox.itemconfig(index, selectbackground=self._selected_bg)

            # Set the item's selected foreground color
            self._listbox.itemconfig(index, selectforeground=self._selected_fg)

        # If keep active index
        if keep_active:
            # Use old active index
            indexcur = self._indexcur

        # If not keep active index
        else:
            # Set active index to -1
            indexcur = self._indexcur = -1

        # Clear old selection
        self._listbox.selection_clear(0, END)

        # Set new selection.
        # `-1` works.
        self._listbox.selection_set(indexcur)

        # Set new active index.
        # `-1` works.
        self._listbox.activate(indexcur)

        # If new active index is valid
        if indexcur != -1:
            # Set active background color
            self._listbox.itemconfig(indexcur, background=self._active_bg)

            # Set active foreground color
            self._listbox.itemconfig(indexcur, foreground=self._active_fg)

            # Make the active item visible
            self._listbox.see(indexcur)
class AutocompleteEntry(Entry):
    def __init__(self, lista, *args, **kwargs):

        Entry.__init__(self, *args, **kwargs)
        self.lista = lista
        self.var = self["textvariable"]
        if self.var == '':
            self.var = self["textvariable"] = StringVar()

        self.var.trace('w', self.changed)
        self.bind("<Right>", self.selection)
        self.bind("<Up>", self.up)
        self.bind("<Down>", self.down)

        self.lb_up = False

    def changed(self, name, index, mode):

        if self.var.get() == '':
            self.lb.destroy()
            self.lb_up = False
        else:
            words = self.comparison()
            if words:
                if not self.lb_up:
                    self.lb = Listbox()
                    self.lb.bind("<Double-Button-1>", self.selection)
                    self.lb.bind("<Right>", self.selection)
                    self.lb.place(x=self.winfo_x(),
                                  y=self.winfo_y() + self.winfo_height())
                    self.lb_up = True

                self.lb.delete(0, END)
                for w in words:
                    self.lb.insert(END, w)
            else:
                if self.lb_up:
                    self.lb.destroy()
                    self.lb_up = False

    def selection(self, event):

        if self.lb_up:
            self.var.set(self.lb.get(ACTIVE))
            self.lb.destroy()
            self.lb_up = False
            self.icursor(END)

    def up(self, event):

        if self.lb_up:
            if self.lb.curselection() == ():
                index = '0'
            else:
                index = self.lb.curselection()[0]
            if index != '0':
                self.lb.selection_clear(first=index)
                index = str(int(index) - 1)
                self.lb.selection_set(first=index)
                self.lb.activate(index)

    def down(self, event):

        if self.lb_up:
            if self.lb.curselection() == ():
                index = '0'
            else:
                index = self.lb.curselection()[0]
            if index != END:
                self.lb.selection_clear(first=index)
                index = str(int(index) + 1)
                self.lb.selection_set(first=index)
                self.lb.activate(index)

    def comparison(self):
        pattern = re.compile('.*' + self.var.get() + '.*')
        return [w for w in self.lista if re.match(pattern, w)]
Esempio n. 10
0
class TPolygonWindow(simpledialog.Dialog):
    """
    Class represents a polygon vertices edit window.

    :param master: master window object.
    :type master: tkinter.Tk
    :param app: main app object.
    :type app: TApp
    :param polygon: edited polygon object.
    :type polygon: TPolygon
    """
    def __init__(self, master, app, polygon):
        """
        Initialise object variables and call the parent class constructor.
        """
        self._app = app
        self._polygon = polygon
        super().__init__(master)

    def body(self, master):
        """
        Initialise widgets.

        :param master: master window object.
        :type master: tkinter.Tk
        """
        # Frame for widgets
        self.main_frame = Frame(self)
        # Listbox
        self.vertices_list = Listbox(self.main_frame, exportselection = False, \
                                     width = 40)
        self.vertices_list.config(exportselection=0)
        self.vertices_list.pack(expand=True, fill=BOTH, side=LEFT)
        self.vertices_list.bind("<Double-Button-1>",
                                self.vertices_list_selected_item)
        # Listbox's yscrollbar
        self.vertices_list_scrollbar = Scrollbar(self.main_frame, orient = VERTICAL, \
                                                 command = self.vertices_list.yview)
        self.vertices_list_scrollbar.pack(expand=True, fill=Y, side=LEFT)
        self.vertices_list.config(
            yscrollcommand=self.vertices_list_scrollbar.set)
        self.main_frame.pack(expand=True, fill=BOTH)
        # Fill list with vertices data
        self.update_vertices_list()

    def buttonbox(self):
        """
        Redefine default Ok/Cancel buttons in the bottom of the window with
        Apply/Add/Delete.
        """
        self.bbox = Frame(self)
        self.apply_button = Button(self.bbox, text = "Apply", width = 10, \
                                   command = self.apply)
        self.apply_button.pack(side=LEFT, padx=5, pady=5)
        self.add_button = Button(self.bbox, text = "Add", width = 10, \
                                 command = self.add_vertex)
        self.add_button.pack(side=LEFT, padx=5, pady=5)
        self.delete_button = Button(self.bbox, text = "Delete", width = 10, \
                                    command = self.delete_vertex)
        self.delete_button.pack(side=LEFT, padx=5, pady=5)
        self.bbox.pack()

    def get_current_selection(self):
        """
        Retrieve the selected vertex index. 

        :rtype: integer
        """
        try:
            cursel = self.vertices_list.curselection()[0]
        except:
            cursel = 0
        return cursel

    def vertices_list_selected_item(self, event):
        """
        Display and edit selected vertex parameters.

        :param event: listbox LMB click event.
        :type event: tkinter.Event
        """
        try:
            vertex_num = (self.vertices_list.curselection())[0]
        except IndexError:
            return
        except Exception as message:
            messagebox.showerror("Error while picking shape!", message)
        if (vertex_num < 0):
            return
        else:
            try:
                vertex = self._polygon.points_mod[vertex_num]
            except Exception as message:
                messagebox.showerror("Materials list error", message)
                return
        initialvalue = str(vertex.x) + " " + str(vertex.y)
        input_str = simpledialog.askstring("Input coordinates", "Give vertex coordinates", \
                                           initialvalue = initialvalue)
        try:
            new_x, new_y = input_str.split()
        except AttributeError:
            pass
        except ValueError as e:
            messagebox.showerror("Wrong input!", e)
        else:
            edited_point = self._polygon.points_mod[vertex_num]
            edited_point.x, edited_point.y = float(new_x), float(new_y)
            self._polygon.update_window_positions()
            self._app.main_canvas.delete("all")
            self._app.canvas_refresh()
        finally:
            self.update_vertices_list()
            self.vertices_list.select_clear(0, END)
            self.vertices_list.selection_set(vertex_num)
            self.vertices_list.activate(vertex_num)
            self.vertices_list.focus_set()

    def update_vertices_list(self):
        """
        Update entries in the vertices listbox.
        """
        cursel = self.get_current_selection()
        self.vertices_list.delete(0, END)
        for i, v in enumerate(self._polygon.points_mod):
            self.vertices_list.insert(i, str(i + 1) + ". (" + str(v.x) + ", " + \
                                      str(v.y) + ")")
        self.vertices_list.select_clear(0, END)
        if (cursel >= self.vertices_list.size()):
            self.vertices_list.selection_set(cursel - 1)
            self.vertices_list.activate(cursel)
        else:
            self.vertices_list.selection_set(cursel)
            self.vertices_list.activate(cursel)

    def add_vertex(self):
        """
        Add a vertex to the polygon.
        """
        cursel = self.get_current_selection()
        input_str = simpledialog.askstring("Input coordinates",
                                           "Give vertex coordinates")
        try:
            new_x, new_y = input_str.split()
        except AttributeError:
            pass
        except ValueError as e:
            messagebox.showerror("Wrong input", e)
        else:
            self._polygon.add_vertex(x_mod=float(new_x), y_mod=float(new_y))
            self._app.main_canvas.delete("all")
            self._app.canvas_refresh()
        finally:
            self.update_vertices_list()
            self.vertices_list.select_clear(0, END)
            self.vertices_list.selection_set(cursel)
            self.vertices_list.activate(cursel)
            self.vertices_list.focus_set()

    def delete_vertex(self):
        """
        Delete a vertex from the polygon.
        """
        cursel = self.get_current_selection()
        self._polygon.remove_vertex(cursel)
        self._app.main_canvas.delete("all")
        self._app.canvas_refresh()
        self.update_vertices_list()
        self.vertices_list.select_clear(0, END)
        self.vertices_list.selection_set(cursel)
        self.vertices_list.activate(cursel)
        self.vertices_list.focus_set()

    def apply(self):
        """
        Destroy window upon clicking Apply button.
        """
        self.destroy()
Esempio n. 11
0
class myListBox(Frame):
    def __init__(self,
                 root,
                 items=[],
                 id='',
                 item_select_handler=default_item_select_handler,
                 smode=tki.EXTENDED):
        self.item_count = 0
        self.root = root
        self.item_select_handler = item_select_handler
        Frame.__init__(self, self.root)
        self.id = id
        vscrollbar = Scrollbar(self, orient=tki.VERTICAL)
        vscrollbar.pack(side=tki.RIGHT, fill=tki.Y)
        hscrollbar = Scrollbar(self, orient=tki.HORIZONTAL)
        hscrollbar.pack(side=tki.BOTTOM, fill=tki.X)
        ## mode can be: SINGLE, BROWSE, MULTIPLE, EXTENDED
        ##        selectmode
        ##
        ## Determines how many items can be selected, and how mouse drags affect the selection −
        ##
        ##    BROWSE − Normally, you can only select one line out of a listbox. If you click on an item and then drag to a different line, the selection will follow the mouse. This is the default.
        ##    SINGLE − You can only select one line, and you can't drag the mouse.wherever you click button 1, that line is selected.
        ##    MULTIPLE − You can select any number of lines at once. Clicking on any line toggles whether or not it is selected.
        ##    EXTENDED − You can select any adjacent group of lines at once by clicking on the first line and dragging to the last line.

        self.list = Listbox(self,
                            selectmode=smode,
                            exportselection=0,
                            xscrollcommand=hscrollbar.set,
                            yscrollcommand=vscrollbar.set)
        for i in items:
            assert (type(i) is str)
            self.list.insert(items.index(i), i)
        self.list.pack(fill=tki.BOTH, expand=1)
        self.list.bind('<Double-Button-1>', self.item_select_handler)
        self.list.bind('<1>', self.item_select_handler)
        self.list.bind('<Return>', self.item_select_handler)
        ## DO NOT catch ListboxSelect event, because:
        ##        a) it is not associated with (x_root, y_root) and (x,y) coordinates, so the popup appears always at (0,0) of the main root window
        ##        b) it duplicates the click event catching  self.list.bind( '<1>', self.item_select_handler ) and generates a second event
        ## self.list.bind( '<<ListboxSelect>>', self.item_select_handler )
        hscrollbar.config(command=self.list.xview)
        vscrollbar.config(command=self.list.yview)
        self.pack(side=tki.LEFT, fill=tki.BOTH, expand=1)
        self.current = self.list.curselection()

    def insert_item(self, pos, item):
        self.list.insert(pos, item)
        self.item_count += 1
        self.activate(pos)
        self.index(pos)

    def delete(self, start, end=None):
        assert (type(start) is int)
        if (end is None):
            self.list.delete(start)
            self.item_count -= 1
        else:
            assert ((type(end) is int) or (end == tki.END))
            if (type(end) is str):
                self.list.delete(start, (self.item_count - 1))
                self.item_count -= (self.item_count - start)
            else:
                self.list.delete(start, end)
                self.item_count -= (end - start) + 1

    def select_set(self, i):
        self.list.selection_clear(0, tki.END)
        self.list.select_set(i)

    def activate(self, i):
        self.list.activate(i)

    def index(self, i):
        self.list.index(i)

    def generate_select_event(self, pos=None):
        assert (pos is not None)
        if (pos is not None):
            self.activate(pos)
            self.index(pos)
            self.select_set(pos)
            self.list.event_generate("<<ListboxSelect>>")

##    def poll(self):
##        now = self.list.curselection()
##        if now != self.current:
##            self.list_has_changed( now )
##            self.current = now
##        self.after( 250, self.poll )

    def list_has_changed(self, selection):
        print('widget {0} selection is {1}'.format(self.id, selection))
Esempio n. 12
0
class Combobox_Autocomplete(Entry, object):
    def __init__(self,
                 master,
                 list_of_items=None,
                 autocomplete_function=None,
                 listbox_width=None,
                 listbox_height=7,
                 ignorecase_match=False,
                 startswith_match=True,
                 vscrollbar=True,
                 hscrollbar=True,
                 **kwargs):
        if hasattr(self, "autocomplete_function"):
            if autocomplete_function is not None:
                raise ValueError(
                    "Combobox_Autocomplete subclass has 'autocomplete_function' implemented"
                )
        else:
            if autocomplete_function is not None:
                self.autocomplete_function = autocomplete_function
            else:
                if list_of_items is None:
                    raise ValueError(
                        "If not guiven complete function, list_of_items can't be 'None'"
                    )

                if ignorecase_match:
                    if startswith_match:

                        def matches_function(entry_data, item):
                            return item.startswith(entry_data)
                    else:

                        def matches_function(entry_data, item):
                            return item in entry_data

                    self.autocomplete_function = lambda entry_data: [
                        item for item in self.list_of_items
                        if matches_function(entry_data, item)
                    ]
                else:
                    if startswith_match:

                        def matches_function(escaped_entry_data, item):
                            if re.match(escaped_entry_data, item,
                                        re.IGNORECASE):
                                return True
                            else:
                                return False
                    else:

                        def matches_function(escaped_entry_data, item):
                            if re.search(escaped_entry_data, item,
                                         re.IGNORECASE):
                                return True
                            else:
                                return False

                    def autocomplete_function(entry_data):
                        escaped_entry_data = re.escape(entry_data)
                        return [
                            item for item in self.list_of_items
                            if matches_function(escaped_entry_data, item)
                        ]

                    self.autocomplete_function = autocomplete_function

        self._listbox_height = int(listbox_height)
        self._listbox_width = listbox_width

        self.list_of_items = list_of_items

        self._use_vscrollbar = vscrollbar
        self._use_hscrollbar = hscrollbar

        kwargs.setdefault("background", "white")

        if "textvariable" in kwargs:
            self._entry_var = kwargs["textvariable"]
        else:
            self._entry_var = kwargs["textvariable"] = StringVar()

        Entry.__init__(self, master, **kwargs)

        self._trace_id = self._entry_var.trace('w', self._on_change_entry_var)

        self._listbox = None

        self.bind("<Tab>", self._on_tab)
        self.bind("<Up>", self._previous)
        self.bind("<Down>", self._next)
        self.bind('<Control-n>', self._next)
        self.bind('<Control-p>', self._previous)

        self.bind("<Return>", self._update_entry_from_listbox)
        self.bind("<Escape>", lambda event: self.unpost_listbox())

    def _on_tab(self, event):
        self.post_listbox()
        return "break"

    def _on_change_entry_var(self, name, index, mode):

        entry_data = self._entry_var.get()

        if entry_data == '':
            self.unpost_listbox()
            self.focus()
        else:
            values = self.autocomplete_function(entry_data)
            if values:
                if self._listbox is None:
                    self._build_listbox(values)
                else:
                    self._listbox.delete(0, END)

                    height = min(self._listbox_height, len(values))
                    self._listbox.configure(height=height)

                    for item in values:
                        self._listbox.insert(END, item)

            else:
                self.unpost_listbox()
                self.focus()

    def _build_listbox(self, values):
        listbox_frame = Frame()

        self._listbox = Listbox(listbox_frame,
                                background="white",
                                selectmode=SINGLE,
                                activestyle="none",
                                exportselection=False)
        self._listbox.grid(row=0, column=0, sticky=N + E + W + S)

        self._listbox.bind("<ButtonRelease-1>",
                           self._update_entry_from_listbox)
        self._listbox.bind("<Return>", self._update_entry_from_listbox)
        self._listbox.bind("<Escape>", lambda event: self.unpost_listbox())

        self._listbox.bind('<Control-n>', self._next)
        self._listbox.bind('<Control-p>', self._previous)

        if self._use_vscrollbar:
            vbar = Scrollbar(listbox_frame,
                             orient=VERTICAL,
                             command=self._listbox.yview)
            vbar.grid(row=0, column=1, sticky=N + S)

            self._listbox.configure(
                yscrollcommand=lambda f, l: autoscroll(vbar, f, l))

        if self._use_hscrollbar:
            hbar = Scrollbar(listbox_frame,
                             orient=HORIZONTAL,
                             command=self._listbox.xview)
            hbar.grid(row=1, column=0, sticky=E + W)

            self._listbox.configure(
                xscrollcommand=lambda f, l: autoscroll(hbar, f, l))

        listbox_frame.grid_columnconfigure(0, weight=1)
        listbox_frame.grid_rowconfigure(0, weight=1)

        x = -self.cget("borderwidth") - self.cget("highlightthickness")
        y = self.winfo_height() - self.cget("borderwidth") - self.cget(
            "highlightthickness")

        if self._listbox_width:
            width = self._listbox_width
        else:
            width = self.winfo_width()

        listbox_frame.place(in_=self, x=x, y=y, width=width)

        height = min(self._listbox_height, len(values))
        self._listbox.configure(height=height)

        for item in values:
            self._listbox.insert(END, item)

    def post_listbox(self):
        if self._listbox is not None: return

        entry_data = self._entry_var.get()
        if entry_data == '': return

        values = self.autocomplete_function(entry_data)
        if values:
            self._build_listbox(values)

    def unpost_listbox(self):
        if self._listbox is not None:
            self._listbox.master.destroy()
            self._listbox = None

    def get_value(self):
        return self._entry_var.get()

    def set_value(self, text, close_dialog=False):
        self._set_var(text)

        if close_dialog:
            self.unpost_listbox()

        self.icursor(END)
        self.xview_moveto(1.0)

    def _set_var(self, text):
        self._entry_var.trace_vdelete("w", self._trace_id)
        self._entry_var.set(text)
        self._trace_id = self._entry_var.trace('w', self._on_change_entry_var)

    def _update_entry_from_listbox(self, event):
        if self._listbox is not None:
            current_selection = self._listbox.curselection()

            if current_selection:
                text = self._listbox.get(current_selection)
                self._set_var(text)

            self._listbox.master.destroy()
            self._listbox = None

            self.focus()
            self.icursor(END)
            self.xview_moveto(1.0)

        return "break"

    def _previous(self, event):
        if self._listbox is not None:
            current_selection = self._listbox.curselection()

            if len(current_selection) == 0:
                self._listbox.selection_set(0)
                self._listbox.activate(0)
            else:
                index = int(current_selection[0])
                self._listbox.selection_clear(index)

                if index == 0:
                    index = END
                else:
                    index -= 1

                self._listbox.see(index)
                self._listbox.selection_set(first=index)
                self._listbox.activate(index)

        return "break"

    def _next(self, event):
        if self._listbox is not None:

            current_selection = self._listbox.curselection()
            if len(current_selection) == 0:
                self._listbox.selection_set(0)
                self._listbox.activate(0)
            else:
                index = int(current_selection[0])
                self._listbox.selection_clear(index)

                if index == self._listbox.size() - 1:
                    index = 0
                else:
                    index += 1

                self._listbox.see(index)
                self._listbox.selection_set(index)
                self._listbox.activate(index)
        return "break"


# if __name__ == '__main__':
#     try:
#         from Tkinter import Tk
#     except ImportError:
#         from tkinter import Tk
#
#     list_of_items = ["Cordell Cannata", "Lacey Naples", "Zachery Manigault", "Regan Brunt", "Mario Hilgefort", "Austin Phong", "Moises Saum", "Willy Neill", "Rosendo Sokoloff", "Salley Christenberry", "Toby Schneller", "Angel Buchwald", "Nestor Criger", "Arie Jozwiak", "Nita Montelongo", "Clemencia Okane", "Alison Scaggs", "Von Petrella", "Glennie Gurley", "Jamar Callender", "Titus Wenrich", "Chadwick Liedtke", "Sharlene Yochum", "Leonida Mutchler", "Duane Pickett", "Morton Brackins", "Ervin Trundy", "Antony Orwig", "Audrea Yutzy", "Michal Hepp", "Annelle Hoadley", "Hank Wyman", "Mika Fernandez", "Elisa Legendre", "Sade Nicolson", "Jessie Yi", "Forrest Mooneyhan", "Alvin Widell", "Lizette Ruppe", "Marguerita Pilarski", "Merna Argento", "Jess Daquila", "Breann Bevans", "Melvin Guidry", "Jacelyn Vanleer", "Jerome Riendeau", "Iraida Nyquist", "Micah Glantz", "Dorene Waldrip", "Fidel Garey", "Vertie Deady", "Rosalinda Odegaard", "Chong Hayner", "Candida Palazzolo", "Bennie Faison", "Nova Bunkley", "Francis Buckwalter", "Georgianne Espinal", "Karleen Dockins", "Hertha Lucus", "Ike Alberty", "Deangelo Revelle", "Juli Gallup", "Wendie Eisner", "Khalilah Travers", "Rex Outman", "Anabel King", "Lorelei Tardiff", "Pablo Berkey", "Mariel Tutino", "Leigh Marciano", "Ok Nadeau", "Zachary Antrim", "Chun Matthew", "Golden Keniston", "Anthony Johson", "Rossana Ahlstrom", "Amado Schluter", "Delila Lovelady", "Josef Belle", "Leif Negrete", "Alec Doss", "Darryl Stryker", "Michael Cagley", "Sabina Alejo", "Delana Mewborn", "Aurelio Crouch", "Ashlie Shulman", "Danielle Conlan", "Randal Donnell", "Rheba Anzalone", "Lilian Truax", "Weston Quarterman", "Britt Brunt", "Leonie Corbett", "Monika Gamet", "Ingeborg Bello", "Angelique Zhang", "Santiago Thibeau", "Eliseo Helmuth"]
#
#     root = Tk()
#     root.geometry("300x200")
#
#     combobox_autocomplete = Combobox_Autocomplete(root, list_of_items, highlightthickness=1)
#     combobox_autocomplete.pack()
#
#     combobox_autocomplete.focus()
#
#     root.mainloop()
Esempio n. 13
0
class Pdf_converter:
    def __init__(self):
        self._root = Tk()
        self._root.geometry("500x400")
        self._root.title("IMGPDF")
        self._Elements()
        Grid.rowconfigure(self._root, 0, weight=1)
        Grid.columnconfigure(self._root, 0, weight=1)
        self.supportedfiles = [
            ('PDF files', '*.pdf*'), ('jpg files', '*.jpg*'),
            ('png files', '*.png*'), ('gif files', '*.gif*'),
            ('All files', '*.*')
        ]
        self.openfiles = []
        self._root.mainloop()

    def _Elements(self):
        ##create button
        self._create = Button(self._root,
                              text="Create",
                              command=self._Create_pdf)

        ##lift up
        self._lift = Button(self._root,
                            text="↑ Lift Up",
                            command=self._Lift_up)

        ##push down
        self._push = Button(self._root,
                            text="↓ Push Down",
                            command=self._Push_down)

        ##addfiles
        self._addfiles = Button(self._root,
                                text="Add Files",
                                command=self._Select_files)

        ##scrollbars
        self._hscroll = Scrollbar(self._root, orient=HORIZONTAL)
        self._vscroll = Scrollbar(self._root)
        ##Listwidget / List box
        self._listbox = Listbox(self._root,
                                width=40,
                                xscrollcommand=self._hscroll.set,
                                yscrollcommand=self._vscroll.set)
        self._hscroll.config(command=self._listbox.xview)
        self._vscroll.config(command=self._listbox.yview)

        #packing
        self._listbox.grid(column=0,
                           columnspan=4,
                           row=0,
                           rowspan=6,
                           sticky=N + E + W + S)
        self._hscroll.grid(column=0, row=6, columnspan=4, sticky=W + E)
        self._vscroll.grid(column=4, row=0, rowspan=6, sticky=N + S)
        self._addfiles.grid(column=3, row=7, sticky=W + E)
        self._create.grid(column=2, row=7, sticky=W + E)
        self._push.grid(column=5, row=1, sticky=S + E + W)
        self._lift.grid(column=5, row=0, sticky=N + W + E)

    def _Lift_up(self):
        #"to lift the element up."
        try:
            current = self._listbox.curselection()[0]
            value = self._listbox.get(current)
            if current != 0:
                upper = current - 1
                self._listbox.insert(current, self._listbox.get(upper))
                self._listbox.delete(current + 1)

                self._listbox.insert(upper, value)
                self._listbox.delete(upper + 1)
                self._listbox.selection_set(upper)
                self._listbox.activate(upper)
        except:
            print("Error in Lift Up")

    def _Push_down(self):
        #"to push the item down."
        try:
            current = self._listbox.curselection()[0]
            value = self._listbox.get(current)
            if current < self._listbox.size() - 1:
                lower = current + 1
                self._listbox.insert(current, self._listbox.get(lower))
                self._listbox.delete(current + 1)

                self._listbox.insert(lower, value)
                self._listbox.delete(lower + 1)
                self._listbox.selection_set(lower)
                self._listbox.activate(lower)
        except:
            print("Error in Push Down")

    def _Select_files(self):
        names = askopenfilename(defaultextension=".pdf",
                                filetypes=self.supportedfiles,
                                multiple=True)
        for file in names:
            self._listbox.insert(END, file)

    def _Create_pdf(self):
        #"To create pdf of the images and join then in the given sequence."
        self.final = asksaveasfilename(initialfile="merged.pdf",
                                       defaultextension=".pdf",
                                       filetypes=[('PDF files', '*.pdf*')])
        self._merger()

    def _merger(self):
        file_list = self._listbox.get(0, END)
        newfile = self.final[:-4] + '0.pdf'
        if file_list[0][-4:] == '.jpg' or file_list[0][
                -4:] == '.png' or file_list[0][-4:] == '.gif':
            fname = file_list[0][:-4] + '.pdf'
            image = Image.open(file_list[0])
            pdf = image.convert('RGB')
            pdf.save(newfile)
            image.close()
        elif file_list[0][-4:] == '.pdf':
            pdf = open(file_list[0], 'rb')
            image = pdf.read()
            pdf.close()
            pdf = open(newfile, 'wb')
            pdf.write(image)
            pdf.close()

        for i in range(len(file_list)):
            if i != 0:
                pdfname = self.final[:-4] + '_' + str(i) + '.pdf'
                if file_list[i][-4:] == '.jpg' or file_list[i][
                        -4:] == '.png' or file_list[i][-4:] == '.gif':
                    fname = file_list[i][:-4] + '.pdf'
                    image = Image.open(file_list[i])
                    pdf = image.convert('RGB')
                    pdf.save(pdfname)
                    image.close()
                elif file_list[i][-4:] == '.pdf':
                    pdf = open(file_list[i], 'rb')
                    image = pdf.read()
                    pdf.close()
                    pdf = open(pdfname, 'wb')
                    pdf.write(image)
                    pdf.close()

                pdflist = [newfile, pdfname]
                merger = PdfFileMerger()
                for pdfs in pdflist:
                    pdf = (open(pdfs, 'rb'))
                    self.openfiles.append(pdf)
                    merger.append(self.openfiles[-1])

                newfile = newfile = self.final[:-4] + str(i) + '.pdf'
                with open(newfile, 'wb') as f:
                    merger.write(f)

                self.openfiles[-1].close()
                self.openfiles[-2].close()

                remove(pdfname)
                remove(self.final[:-4] + str(i - 1) + '.pdf')

        pdf = open(newfile, 'rb')
        data = pdf.read()
        pdf.close()
        remove(newfile)
        pdf = open(self.final, 'wb')
        pdf.write(data)
        pdf.close()
Esempio n. 14
0
class App(tkinter.Tk):
    def __init__(self, parent, app_dir):
        tkinter.Tk.__init__(self, parent)
        self.parent = parent

        # var declaration
        self.app_dir = app_dir
        self.filenames = []  # tyoe: list[str]
        self.file_list = None  # type: tkinter.Listbox
        self.output = os.path.join(app_dir, 'output.pdf')  # type: str

        # init
        self.initialize()

    def initialize(self):
        # set the app size
        self.geometry("{}x{}".format(WIDTH, HEIGHT))

        # create frames
        left_frame = Frame(self,
                           bg='cyan',
                           width=WIDTH // 2,
                           height=HEIGHT,
                           pady=3)
        right_frame = Frame(self,
                            bg='lavender',
                            width=WIDTH // 2,
                            height=HEIGHT,
                            pady=3)

        # layout all main containers with some scale
        self.grid_columnconfigure(0, weight=1)
        self.grid_columnconfigure(1, weight=1)
        self.grid_rowconfigure(0, weight=1)

        # stick frames to positions (side by side)
        left_frame.grid(row=0, column=0, sticky='nsew')
        right_frame.grid(row=0, column=1, sticky='nsew')

        # create widgets
        label_pdf = Label(left_frame, text='PDFs')
        self.file_list = Listbox(left_frame)

        label_cmds = Label(right_frame, text='Commands')
        button_import = tkinter.Button(right_frame,
                                       text='Import',
                                       command=self._get_files)
        button_up = tkinter.Button(right_frame,
                                   text='up',
                                   command=self._list_move_up)
        button_down = tkinter.Button(right_frame,
                                     text='Down',
                                     command=self._list_move_down)
        button_remove = tkinter.Button(right_frame,
                                       text='remove',
                                       command=self._list_remove)
        button_merge = tkinter.Button(right_frame,
                                      text='Merge!',
                                      command=self._merge)

        # layout widgets
        label_pdf.grid(row=0, column=0)
        self.file_list.grid(row=1, column=0)

        label_cmds.grid(row=0, column=1)
        button_import.grid(row=1, column=1)
        button_up.grid(row=2, column=1)
        button_down.grid(row=3, column=1)
        button_remove.grid(row=4, column=1)
        button_merge.grid(row=5, column=1)

        self.update_listbox()

    def insert_temp_list(self):
        """ Temp list for debugging """
        self.filenames = ['cat.pdf', 'dog.pdf', 'meow.pdf']
        self.update_listbox()

    def _get_files(self):
        """ Prompt the user for the files that they wish to merge. All files are added to a list """
        # a list of filetype tuples (filename, extension)
        filetypes = [("pdf files", "*.pdf")]

        # Read in the selected files
        filenames = filedialog.askopenfilenames(
            initialdir=self.app_dir,
            title="Select pdf's to merge. Ctrl + click for multiple",
            filetypes=filetypes)

        # add files
        for filename in filenames:
            self.filenames.append(filename)
        self.update_listbox()

    def update_listbox(self):
        """ Redraws the listbox to show self.filenames """
        # delete all elements from list
        self.file_list.delete(0, tkinter.END)

        # add list items. last name only
        for filename in self.filenames:
            self.file_list.insert(tkinter.END, os.path.basename(filename))

    def _list_move_up(self):
        """ Move the selected element up if possible """
        index = self.get_selected_index()
        if (index is not None) and (index != 0):
            up = index - 1
            # swap elements upwards
            list_swap(self.filenames, index, up)
            self.update_listbox()

            # set the cursor position within the list
            self.select_line(up)

    def _list_move_down(self):
        """ Move the selected element down if possible """
        index = self.get_selected_index()
        if (index is not None) and (index != len(self.filenames) - 1):
            down = index + 1
            # swap elements downwards
            list_swap(self.filenames, index, down)
            self.update_listbox()

            # set the cursor position within the list
            self.select_line(down)

    def _list_remove(self):
        """
        Remove the selected item
        * if not selected, nothing happens
        * if possible the selection cursor does not move
        * if you are removing the latest element the selection moves back one
        * if you remove the last element, nothing is selected
        """

        index = self.get_selected_index()

        # ensure something is selected
        if index is None:
            return

        # remove element
        self.filenames.pop(index)
        self.update_listbox()

        # work out where the cursor should be
        max_pos = len(self.filenames)

        if index < max_pos:
            self.select_line(index)
        elif max_pos != 0:
            self.select_line(index - 1)

    def select_line(self, index):
        """ select a line within self.file_list if the index makes sense """
        if index < len(self.filenames):
            self.file_list.activate(index)
            self.file_list.select_set(index)

    def get_selected_index(self):
        """
        Return the index of the element selected in self.file_list.
        None if nothing is selected
        """
        selected = self.file_list.curselection()
        if len(selected) > 0:
            return selected[0]
        return None

    def _merge(self):
        """ Callback for when files all pdf files are ready to be merged """
        # check if any pdfs have been selected
        if len(self.filenames) == 0:
            print('No files have been selected. Nothing that can be done')
            return

        # prompt the user for the output file name
        self.set_output_file_name()

        # Run merge for all the files
        merge_all(self.filenames, self.output)

    def set_output_file_name(self):
        """ Prompts the user to select the output file name """
        # a list of filetype tuples (filename, extension)
        filetypes = [("pdf files", "*.pdf")]

        # Read in the user desired file location
        output = filedialog.asksaveasfilename(initialdir=self.app_dir,
                                              title="Output merged",
                                              filetypes=filetypes)

        # check if the extension is actually pdf (fix shorthanding)
        self.output = output if output.endswith('pdf') else (output + '.pdf')
Esempio n. 15
0
class Player(Frame):
	def __init__(self,master):
		super().__init__(master)
		self.master =master
		mixer.init()
		self.pack()
		if os.path.exists("tracks.pickle"):
			with open ("tracks.pickle", "rb") as f:
				self.playlist =pickle.load(f)
		else:
			self.playlist =[]

		# player state flags
		self.track_index =0
		self.track_paused =True
		self.track_played =False

		self.model_frame()
		self.track_widget()
		self.tracklist_widget()
		self.controls_widget()

	# frames
	def model_frame(self):
		self.track =LabelFrame(self,
				relief =GROOVE
			)
		self.track.configure(
				width =410,
				height =300
			)
		self.track.grid(row=0, column=0,pady=10,padx=10)

		self.tracklist =LabelFrame(self,
				relief =GROOVE
			)
		self.tracklist.configure(
				width =190,
				height =420
			)
		self.tracklist.grid(row=0, column=1,rowspan=3,pady=10,padx=10)

		self.controls =LabelFrame(self,
				font =("times new roman",15,"bold"),
				bg ="white",
				fg ="white",
				bd =0,
				relief =GROOVE
			)
		self.controls.configure(
				width =410,
				height =100
			)
		self.controls.grid(row=1, column=0,pady=10,padx=10)

	# widgets
	def track_widget(self):
		self.canvas =Label(self.track,font =("times new roman",15,"bold"),bg="white", fg ="dodgerblue")
		self.canvas['text'] ="Hit tracks"; 
		self.canvas.configure(width =33, height =1)
		self.canvas.grid(row =0,column =0)

		self.canvas =Label(self.track,image=track_ico) 
		self.canvas.configure(width =300, height =240)
		self.canvas.grid(row =1,column =0)

		self.playing_tune =Label(self.track,font =("Calibri",13),bg="white", fg ="dodgerblue")
		self.playing_tune['text'] ="Musiflix MP3 Player"; 
		self.playing_tune.configure(width =44, height =1)
		self.playing_tune.grid(row =2,column =0)

	def tracklist_widget(self):
		self.listtitle =Label(self.tracklist,font =("times new roman",15,"bold"),bg="white", fg ="dodgerblue")
		self.listtitle['text'] =f"Playlist:  {len(self.playlist)} "
		self.listtitle.configure(width =10, height =1)
		self.listtitle.grid(row =0,column =0)

		self.scrollbar =Scrollbar(self.tracklist,orient =VERTICAL)
		self.scrollbar.grid(row=0, column=1,rowspan =10, sticky="NS")

		self.list =Listbox(self.tracklist, selectmode =SINGLE,
			yscrollcommand =self.scrollbar.set, selectbackground ="sky blue")
		self.track_listing()
		self.list.config(height =22)
		self.list.bind('<Double-1>', self.play_track)
		self.scrollbar.config(command =self.list.yview)
		self.list.grid(row=2, column=0, rowspan =5)

	def track_listing(self):
		for index, track in enumerate(self.playlist):
			self.list.insert(index,os.path.basename(track))

	def controls_widget(self):
		self.tracklister =Button(self.controls, 
			font =("times new roman",15,"bold"),
			bg="white", fg ="dodgerblue", padx =10,pady =5,
			command =self.select_track
			)
		self.tracklister['text'] ="Load tracks"
		self.tracklister.grid(row =0,column =0,padx=10,pady =5)

		self.prevbutton =Button(self.controls,image =prev_icon, command =self.prev_track)
		self.prevbutton.grid(row =0,column =1,pady =5)

		self.pausebutton =Button(self.controls,image =pauseicon, command =self.pause_track)
		self.pausebutton.grid(row =0,column =2,pady =5)

		self.nextbutton =Button(self.controls,image =next_icon, command =self.next_track)
		self.nextbutton.grid(row =0,column =3,pady =5)

		self.volume =DoubleVar()
		self.slider =Scale(self.controls, from_ =0, to =10, orient =HORIZONTAL)
		self.slider['variable'] =self.volume
		self.slider['command'] =self.change_volume
		self.slider.set(3)
		mixer.music.set_volume(0.3)
		self.slider.grid(row =0, column=4,padx=10,pady =5)

	def change_volume(self, event =None):
		self.v =self.volume.get()
		mixer.music.set_volume(self.v/10)


	def select_track(self):
		self.tunes =[]
		directory =filedialog.askdirectory()
		for rooot, dirs, files in os.walk(directory):
			for file in files:
				if os.path.splitext(file)[1] =='.mp3':
					path =(rooot + '/' + file).replace('\\','/')
					self.tunes.append(path)
		with open("tracks.pickle", "wb") as f:
			pickle.dump(self.tunes, f) 
		self.playlist =self.tunes
		self.listtitle['text'] =f"Playlist:  {len(self.playlist)}"
		self.list.delete(0, END)
		self.track_listing()

	def play_track(self, event =None):
		try:
			if event is not None:
				self.track_index =self.list.curselection()[0]
			for i in range(len(self.playlist)):
				self.list.itemconfigure(i,bg="white",fg="black")
			mixer.music.load(self.playlist[self.track_index])
			self.track_paused =False
			self.track_played =True
			self.pausebutton['image'] =playicon
			self.playing_tune.anchor('w')
			self.playing_tune['text'] =os.path.basename(self.playlist[self.track_index])
			self.list.activate(self.track_index)
			self.list.itemconfigure(self.track_index,bg="teal", fg="white")
			mixer.music.play()
		except  Exception as e:
			pass
	def pause_track(self):
		if not self.track_paused:
			try:
				self.track_paused =True
				self.pausebutton['image'] =pauseicon
				mixer.music.pause()
			except Exception as e:
				pass
		else:
			try:
				if not self.track_played:
					self.play_track()
				self.track_paused =False
				self.pausebutton['image'] =playicon
				mixer.music.unpause()
			except Exception as e:
				pass
	def next_track(self):
		if self.track_index > len(self.playlist) -1:
			self.track_index =0
		self.track_index +=1
		self.play_track()

	def prev_track(self):
		if self.track_index < 0:
			self.track_index =len(self.playlist) -1
		self.track_index -=1
		self.play_track()
Esempio n. 16
0
class ShiftApp():  ### In-progress Shift application ###
    def __init__(self, db, job_name):
        self.db = db
        self.events = {}

        self.job_name = job_name
        self.start_time = time.time()
        self.break_start = 0
        self.break_time = 0
        self.id = self.db.add_shift(self.job_name, self.start_time, None,
                                    self.break_time, None)
        self.tasks = {}
        self.task_index = []
        self.cur_task = 0

        self.root = Tk()
        self.root.title(f'Shift - {job_name}')
        self.root.resizable(False, False)
        self.root.overrideredirect(0)

        self.tm1_selection = StringVar(self.root)
        self.tm2_selection = StringVar(self.root)

        self.container = ttk.Frame(self.root)
        self.frame = ttk.Frame(self.container)

        self.job_label = ttk.Label(self.frame, text=f'Job: {job_name}')
        self.elapsed_time_label = ttk.Label(self.frame, width=18)

        self.task_frame = ttk.Frame(self.frame)
        self.task_label = ttk.Label(self.task_frame, text="Tasks:")
        self.tm1_options, self.tm2_options = ('All Job Tasks',
                                              'Shift Tasks Only'), ()
        self.task_menu1 = ttk.OptionMenu(self.frame, self.tm1_selection,
                                         self.tm1_options[0],
                                         *self.tm1_options)
        self.task_entry = ttk.Entry(self.frame)
        self.task_list = Listbox(self.task_frame,
                                 selectmode=SINGLE,
                                 width=20,
                                 height=12,
                                 relief='sunken')
        vbar = ttk.Scrollbar(self.task_frame,
                             orient='vertical',
                             command=self.task_list.yview)
        self.task_list.config(yscrollcommand=vbar.set)
        self.new_task_button = ttk.Button(self.frame,
                                          text="New Task",
                                          command=self.new_task)

        self.button_frame = ttk.Frame(self.frame)
        self.pause_button = ttk.Button(self.button_frame,
                                       text='Pause',
                                       command=self.toggle_break,
                                       width=7)
        # TODO: Add info button
        self.cancel_button = ttk.Button(self.frame,
                                        text='Cancel',
                                        command=self.cancel_prompt)
        self.notes = ScrolledText(self.frame,
                                  undo=True,
                                  width=60,
                                  height=15,
                                  relief='sunken')
        self.report_job_button = ttk.Button(self.frame,
                                            text='Prior Shifts',
                                            command=self.launch_report_edit)
        self.save_button = ttk.Button(self.frame,
                                      text='Stop and Save',
                                      command=self.end_prompt)

        self.job_label.grid(column=2, columnspan=2, row=1, sticky=W, pady=5)
        self.elapsed_time_label.grid(column=4, row=1, sticky=E)
        self.task_menu1.grid(column=1, row=1, sticky=(E, W), padx=(0, 15))
        self.task_entry.grid(column=1, row=2, sticky=(E, W), padx=(0, 15))
        self.task_list.grid(column=1, row=1, sticky=(N, S))
        vbar.grid(column=2, row=1, sticky=(N, S))
        self.task_frame.grid(column=1, row=3, sticky=(N, S), pady=(5, 5))
        self.new_task_button.grid(column=1, row=4, sticky=W)
        self.button_frame.grid(column=2, columnspan=2, row=2, sticky=W)
        self.pause_button.grid(column=2, row=1, sticky=W)
        self.cancel_button.grid(column=4, row=2, sticky=E)
        self.notes.grid(column=2, columnspan=3, row=3, pady=(5, 5))
        self.report_job_button.grid(column=2, row=4, sticky=W)
        self.save_button.grid(column=4, row=4, sticky=E)
        self.frame.grid(column=0, row=0, padx=5, pady=5)
        self.container.grid(column=0, row=0)

        self.root.protocol("WM_DELETE_WINDOW", self.cancel_prompt)
        self.task_menu1.bind("<ButtonRelease-1>",
                             self.filter_tasks)  # filter_tasks clears notes
        self.task_entry.bind("<KeyRelease>", self.filter_tasks)
        self.task_list.bind("<ButtonRelease-1>", self.focus_task)
        self.task_list.bind("<Double-Button-1>", self.copy_task_title)
        self.notes.bind("<Command-Z>", self.edit_undo)

        self.time_counter()
        self.auto_save()
        self.get_tasks()

    def edit_undo(self, event=None):
        try:
            self.notes.edit_undo()
        except TclError as e:
            print(e)

    def get_tasks(self,
                  event=None,
                  **kwargs):  ## Gets set of filtered tasks from db ##
        if "Job" in self.tm1_selection.get():
            kwargs["job_name"] = self.job_name
        else:
            kwargs["shift_id"] = self.id
        tasks = self.db.report_tasks(**kwargs)
        self.tasks.clear()
        for task in tasks:
            self.tasks[task["id"]] = task
        self.task_list.delete(0, END)
        self.cur_task = 0
        self.task_index = []
        self.task_list.insert(END, "Shift Notes")
        self.task_index.append(None)
        for _, task in self.tasks.items():
            self.task_list.insert(END, task['title'])
            self.task_index.append(task["id"])

    def filter_tasks(self, event=None):
        # TODO: set focus to 'Shift Notes'
        search_term = self.task_entry.get()
        if search_term in ('', ' '):
            search_term = None
        self.get_tasks(search_term=search_term)
        notes = self.db.get_shift(self.id)["notes"]
        self.notes.delete("0.0", END)
        self.notes.insert(END, notes)

    def new_task(self):
        task_title = self.task_entry.get()
        if task_title not in ('', ' '):
            task = self.db.add_task(self.id, self.job_name, task_title)
            self.task_entry.delete(0, END)
            self.get_tasks()
            self.task_list.activate(self.task_index.index(task["id"]))

    def focus_task(
            self,
            event=None):  ## displays notes for the currently selected task ##
        if self.task_list.curselection():
            new_cur = self.task_list.curselection()[0]
            if new_cur == self.cur_task:
                return
            notes = self.notes.get(0.0, END).strip('\n')
            if self.cur_task:  # if the notes being displayed belong to a task
                task_id = self.task_index[self.cur_task]
                self.tasks[task_id]["notes"] = notes
            else:
                self.db.update_shift(self.id, notes=notes)
            if new_cur:  # if the new notes to be displayed belong to a task
                task_id = self.task_index[new_cur]
                notes = self.tasks[task_id]["notes"]
            else:
                shift = self.db.report_shifts(shift_id=self.id)[0]
                notes = shift["notes"]
            self.notes.delete('0.0', END)
            self.notes.insert(END, notes)
            self.cur_task = new_cur

    def copy_task_title(
        self,
        event=None
    ):  ## Copies title from current selection in task_list to task_entry ##
        cur = self.task_list.curselection()[0]
        if cur:
            task = self.tasks[self.task_index[cur]]
            self.task_entry.delete(0, END)
            self.task_entry.insert(0, task["title"])
            self.filter_tasks()

    def time_counter(self):
        if not self.break_start:
            elapsed_time = time.gmtime(time.time() - self.start_time -
                                       self.break_time)
            elapsed_hours = time.strftime('%H', elapsed_time)
            elapsed_minutes = time.strftime('%M', elapsed_time)
            elapsed_seconds = time.strftime('%S', elapsed_time)
            self.elapsed_time_label[
                'text'] = f'Elapsed Time: {elapsed_hours}:{elapsed_minutes}:{elapsed_seconds}'
        self.events['time_counter'] = self.root.after(200, self.time_counter)

    def auto_save(self):
        self.save_update()
        self.events['auto_save'] = self.root.after(5000, self.auto_save)

    def save_update(
            self):  ## Commits current state for shift and tasks to db ##
        if self.break_start:
            break_time = self.break_time + (time.time() - self.break_start)
        else:
            break_time = self.break_time
        end_time = time.time()
        notes = self.notes.get(0.0, END).strip('\n')
        if self.cur_task:  # if the notes being displayed belong to a task
            task_id = self.task_index[self.cur_task]
            self.tasks[task_id]["notes"] = notes
            notes = None
        self.db.update_shift(self.id,
                             end_time=end_time,
                             break_time=break_time,
                             notes=notes)
        for _, task in self.tasks.items():
            self.db.update_task(**task)

    def toggle_break(self):
        if not self.break_start:
            self.break_start = time.time()
            self.job_label['text'] = f'{self.job_name} - Paused'
            self.pause_button['text'] = 'Resume'
        else:
            self.break_time += time.time() - self.break_start
            self.break_start = 0
            self.job_label['text'] = self.job_name
            self.pause_button['text'] = 'Pause'

    def end_prompt(self):
        popup = PopConfirm("Save and exit shift?", self.end_shift)
        popup.root.mainloop()

    def cancel_prompt(self):
        popup = PopConfirm("Cancel and delete shift?", self.cancel_shift)
        popup.root.mainloop()

    def end_shift(self):
        self.save_update()
        self.db.complete_shift(self.id)
        self.close()

    def cancel_shift(self):
        self.db.remove_shift(self.id)
        self.close()

    def launch_report_edit(self):
        self.report_edit_window = ReportEditApp(self.db,
                                                job_name=self.job_name)
        self.report_edit_window.root.mainloop()

    def close(self):
        for val in self.events.values():
            self.root.after_cancel(val)
        self.root.destroy()
Esempio n. 17
0
class SettingsFrame(Frame):
    '''
    Frame inheritance class for application settings and controls.
    '''

    def __init__(self, app, *args, **kwargs):
        '''
        Constructor.
        '''

        self.__app = app  # Reference to main application class
        self.__master = self.__app.get_master()  # Reference to root class (Tk)
        Frame.__init__(self, self.__master, *args, **kwargs)

        self._show_advanced = False
        self._settings = {}
        self._ports = ()
        self._port = StringVar()
        self._port_desc = StringVar()
        self._baudrate = IntVar()
        self._databits = IntVar()
        self._stopbits = DoubleVar()
        self._parity = StringVar()
        self._rtscts = IntVar()
        self._xonxoff = IntVar()
        self._protocol = IntVar()
        self._raw = IntVar()
        self._autoscroll = IntVar()
        self._maxlines = IntVar()
        self._webmap = IntVar()
        self._mapzoom = IntVar()
        self._units = StringVar()
        self._format = StringVar()
        self._datalog = IntVar()
        self._record_track = IntVar()
        self._noports = True
        self._validsettings = True
        self._logpath = None
        self._trackpath = None
        self._img_conn = ImageTk.PhotoImage(Image.open(ICON_CONN))
        self._img_disconn = ImageTk.PhotoImage(Image.open(ICON_DISCONN))
        self._img_ubxconfig = ImageTk.PhotoImage(Image.open(ICON_UBXCONFIG))
        self._img_dataread = ImageTk.PhotoImage(Image.open(ICON_LOGREAD))

        self._body()
        self._do_layout()
        self._get_ports()
        self._reset()

    def _body(self):
        '''
        Set up frame and widgets.
        '''

        for i in range(4):
            self.grid_columnconfigure(i, weight=1)
        self.grid_rowconfigure(0, weight=1)

        self.option_add("*Font", self.__app.font_sm)

        # Serial port settings
        self._frm_basic = Frame(self)
        self._lbl_port = Label(self._frm_basic, text="Port")
        self._lbx_port = Listbox(self._frm_basic, border=2,
                                 relief="sunken", bg=ENTCOL,
                                 width=28, height=5, justify=LEFT,
                                 exportselection=False)
        self._scr_portv = Scrollbar(self._frm_basic, orient=VERTICAL)
        self._scr_porth = Scrollbar(self._frm_basic, orient=HORIZONTAL)
        self._lbx_port.config(yscrollcommand=self._scr_portv.set)
        self._lbx_port.config(xscrollcommand=self._scr_porth.set)
        self._scr_portv.config(command=self._lbx_port.yview)
        self._scr_porth.config(command=self._lbx_port.xview)
        self._lbx_port.bind("<<ListboxSelect>>", self._on_select_port)
        self._lbl_baudrate = Label(self._frm_basic, text="Baud rate")
        self._spn_baudrate = Spinbox(self._frm_basic,
                                     values=(BAUDRATES),
                                     width=8, state=READONLY, readonlybackground=ENTCOL,
                                     wrap=True, textvariable=self._baudrate)
        self._btn_toggle = Button(self._frm_basic, text=ADVOFF, width=3,
                                  command=self._toggle_advanced)

        self._frm_advanced = Frame(self)
        self._lbl_databits = Label(self._frm_advanced, text="Data Bits")
        self._spn_databits = Spinbox(self._frm_advanced, values=(8, 7, 6, 5),
                                     width=3, state=READONLY, readonlybackground=ENTCOL,
                                     wrap=True, textvariable=self._databits)
        self._lbl_stopbits = Label(self._frm_advanced, text="Stop Bits")
        self._spn_stopbits = Spinbox(self._frm_advanced, values=(2, 1.5, 1),
                                     width=3, state=READONLY, readonlybackground=ENTCOL,
                                     wrap=True, textvariable=self._stopbits)
        self._lbl_parity = Label(self._frm_advanced, text="Parity")
        self._spn_parity = Spinbox(self._frm_advanced,
                                   values=("None", "Even", "Odd", "Mark", "Space"),
                                   width=6, state=READONLY, readonlybackground=ENTCOL,
                                   wrap=True, textvariable=self._parity)
        self._chk_rts = Checkbutton(self._frm_advanced, text="RTS/CTS",
                                    variable=self._rtscts)
        self._chk_xon = Checkbutton(self._frm_advanced, text="Xon/Xoff",
                                    variable=self._xonxoff)

        self._frm_buttons = Frame(self)
        self._btn_connect = Button(self._frm_buttons, width=45, height=35,
                                  image=self._img_conn,
                                  command=lambda: self.__app.serial_handler.connect())
        self._btn_disconnect = Button(self._frm_buttons, width=45, height=35,
                                     image=self._img_disconn,
                                     command=lambda: self.__app.serial_handler.disconnect(),
                                     state=DISABLED)
        self._btn_connect_file = Button(self._frm_buttons, width=45, height=35,
                                     image=self._img_dataread,
                                     command=lambda: self._on_data_stream())
        self._lbl_status_preset = Label(self._frm_buttons, font=self.__app.font_md2, text='')

        # Other configuration options
        self._frm_options = Frame(self)
        self._lbl_protocol = Label(self._frm_options, text=LBLPROTDISP)
        self._rad_nmea = Radiobutton(self._frm_options, text="NMEA",
                                    variable=self._protocol, value=NMEA_PROTOCOL)
        self._rad_ubx = Radiobutton(self._frm_options, text="UBX",
                                    variable=self._protocol, value=UBX_PROTOCOL)
        self._rad_all = Radiobutton(self._frm_options, text="ALL",
                                    variable=self._protocol, value=MIXED_PROTOCOL)
        self._lbl_consoledisplay = Label(self._frm_options, text=LBLDATADISP)
        self._rad_parsed = Radiobutton(self._frm_options, text="Parsed",
                                    variable=self._raw, value=0)
        self._rad_raw = Radiobutton(self._frm_options, text="Raw",
                                   variable=self._raw, value=1)
        self._lbl_format = Label(self._frm_options, text="Degrees Format")
        self._spn_format = Spinbox(self._frm_options,
                                  values=(DDD, DMS, DMM),
                                  width=6, state=READONLY, readonlybackground=ENTCOL,
                                  wrap=True, textvariable=self._format)
        self._lbl_units = Label(self._frm_options, text="Units")
        self._spn_units = Spinbox(self._frm_options,
                                  values=(UMM, UIK, UI, UMK),
                                  width=13, state=READONLY, readonlybackground=ENTCOL,
                                  wrap=True, textvariable=self._units)
        self._chk_scroll = Checkbutton(self._frm_options, text="Autoscroll",
                                      variable=self._autoscroll)
        self._spn_maxlines = Spinbox(self._frm_options,
                                     values=("100", "200", "500", "1000", "2000"),
                                    width=6, readonlybackground=ENTCOL, wrap=True,
                                    textvariable=self._maxlines, state=READONLY)
        self._chk_webmap = Checkbutton(self._frm_options, text="Web Map  Zoom",
                                      variable=self._webmap)
        self._scl_mapzoom = Scale(self._frm_options, from_=1, to=20, orient=HORIZONTAL,
                                  relief="sunken", bg=ENTCOL, variable=self._mapzoom)
        self._chk_datalog = Checkbutton(self._frm_options, text=LBLDATALOG,
                                        variable=self._datalog,
                                        command=lambda: self._on_data_log())

        self._chk_recordtrack = Checkbutton(self._frm_options, text=LBLTRACKRECORD,
                                        variable=self._record_track,
                                        command=lambda: self._on_record_track())

        self._lbl_ubxconfig = Label(self._frm_options, text=LBLUBXCONFIG)
        self._btn_ubxconfig = Button(self._frm_options, width=45, height=35,
                                     text='UBX', image=self._img_ubxconfig,
                                     command=lambda: self._on_ubx_config(),
                                     state=DISABLED)

    def _do_layout(self):
        '''
        Position widgets in frame.
        '''

        self._frm_basic.grid(column=0, row=0, columnspan=4, sticky=(W, E))
        self._lbl_port.grid(column=0, row=0, sticky=(W))
        self._lbx_port.grid(column=1, row=0, sticky=(W, E), padx=3, pady=3)
        self._scr_portv.grid(column=2, row=0, sticky=(N, S))
        self._scr_porth.grid(column=1, row=1, sticky=(E, W))
        self._lbl_baudrate.grid(column=0, row=2, sticky=(W))
        self._spn_baudrate.grid(column=1, row=2, sticky=(W), padx=3, pady=3)
        self._btn_toggle.grid(column=2, row=2, sticky=(E))

        self._frm_advanced.grid_forget()
        self._lbl_databits.grid(column=0, row=0, sticky=(W))
        self._spn_databits.grid(column=1, row=0, sticky=(W), padx=3, pady=3)
        self._lbl_stopbits.grid(column=2, row=0, sticky=(W))
        self._spn_stopbits.grid(column=3, row=0, sticky=(W), padx=3, pady=3)
        self._lbl_parity.grid(column=0, row=1, sticky=(W))
        self._spn_parity.grid(column=1, row=1, sticky=(W), padx=3, pady=3)
        self._chk_rts.grid(column=2, row=1, sticky=(W))
        self._chk_xon.grid(column=3, row=1, sticky=(W), padx=3, pady=3)

        ttk.Separator(self).grid(column=0, row=2, columnspan=4,
                                            padx=3, pady=3, sticky=(W, E))

        self._frm_buttons.grid(column=0, row=3, columnspan=4, sticky=(W, E))
        self._btn_connect.grid(column=0, row=0, padx=3, pady=3)
        self._btn_connect_file.grid(column=1, row=0, padx=3, pady=3)
        self._btn_disconnect.grid(column=3, row=0, padx=3, pady=3)

        ttk.Separator(self).grid(column=0, row=7, columnspan=4,
                                            padx=3, pady=3, sticky=(W, E))

        self._frm_options.grid(column=0, row=8, columnspan=4, sticky=(W, E))
        self._lbl_protocol.grid(column=0, row=0, padx=3, pady=3, sticky=(W))
        self._rad_nmea.grid(column=1, row=0, padx=0, pady=0, sticky=(W))
        self._rad_ubx.grid(column=2, row=0, padx=0, pady=0, sticky=(W))
        self._rad_all.grid(column=3, row=0, padx=0, pady=0, sticky=(W))
        self._lbl_consoledisplay.grid(column=0, row=1, padx=2, pady=3, sticky=(W))
        self._rad_parsed.grid(column=1, row=1, padx=1, pady=3, sticky=(W))
        self._rad_raw.grid(column=2, row=1, padx=2, pady=3, sticky=(W))
        self._lbl_format.grid(column=0, row=2, padx=3, pady=3, sticky=(W))
        self._spn_format.grid(column=1, row=2, padx=2, pady=3, sticky=(W))
        self._lbl_units.grid(column=0, row=3, padx=3, pady=3, sticky=(W))
        self._spn_units.grid(column=1, row=3, columnspan=3, padx=2, pady=3, sticky=(W))
        self._chk_scroll.grid(column=0, row=4, padx=3, pady=3, sticky=(W))
        self._spn_maxlines.grid(column=1, row=4, columnspan=3, padx=3, pady=3, sticky=(W))
        self._chk_webmap.grid(column=0, row=5, sticky=(W))
        self._scl_mapzoom.grid(column=1, row=5, columnspan=3, sticky=(W))
        self._chk_datalog.grid(column=0, row=6, padx=3, pady=3, sticky=(W))
        self._chk_recordtrack.grid(column=0, row=7, padx=3, pady=3, sticky=(W))

        ttk.Separator(self._frm_options).grid(column=0, row=8, columnspan=4,
                                 padx=3, pady=3, sticky=(W, E))
        self._lbl_ubxconfig.grid(column=0, row=9, padx=3, pady=3, sticky=(W))
        self._btn_ubxconfig.grid(column=1, row=9, padx=3, pady=3, sticky=(W))

    def _on_select_port(self, *args, **kwargs):
        '''
        Get selected port from listbox and set global variable.
        '''

        idx = self._lbx_port.curselection()
        if  idx == "":
            idx = 0
        port_orig = self._lbx_port.get(idx)
        port = port_orig[0:port_orig.find(":")]
        desc = port_orig[port_orig.find(":") + 1:]
        if desc == '':
            desc = "device"
        self._port.set(port)
        self._port_desc.set(desc)

    def _on_ubx_config(self, *args, **kwargs):
        '''
        Open UBX configuration dialog panel.
        '''

        self.__app.ubxconfig()

    def _on_data_log(self):
        '''
        Start or stop data logger
        '''

        if self._datalog.get() == 1:
            self._logpath = self.__app.file_handler.set_logfile_path()
            if self._logpath is not None:
                self.__app.set_status("Data logging enabled: " + self._logpath, "green")
            else:
                self._datalog.set(False)
        else:
            self._logpath = None
            self._datalog.set(False)
#             self.__app.file_handler.close_logfile()
            self.__app.set_status("Data logging disabled", "blue")

    def _on_record_track(self):
        '''
        Start or stop track recorder
        '''

        if self._record_track.get() == 1:
            self._trackpath = self.__app.file_handler.set_trackfile_path()
            if self._trackpath is not None:
                self.__app.set_status("Track recording enabled: " + self._trackpath, "green")
            else:
                self._record_track.set(False)
        else:
            self._trackpath = None
            self._record_track.set(False)
#             self.__app.file_handler.close_trackfile()
            self.__app.set_status("Track recording disabled", "blue")

    def _on_data_stream(self):
        '''
        Start data file streamer
        '''

        self._logpath = self.__app.file_handler.open_logfile_input()
        if self._logpath is not None:
            self.__app.set_status("")
            self.__app.serial_handler.connect_file()

    def _toggle_advanced(self):
        '''
        Toggle advanced serial port settings panel on or off
        '''

        self._show_advanced = not self._show_advanced
        if self._show_advanced:
            self._frm_advanced.grid(column=0, row=1, columnspan=3, sticky=(W, E))
            self._btn_toggle.config(text=ADVON)
        else:
            self._frm_advanced.grid_forget()
            self._btn_toggle.config(text=ADVOFF)

    def _get_ports(self):
        '''
        Populate list of available serial ports using pyserial comports tool.
        If no ports found, disable all connection-dependent widgets.

        Attempt to preselect the first port that has a recognisable
        GPS designation in its description (usually only works on
        Posix platforms - Windows doesn't parse UART device desc or HWID)
        '''

        self._ports = sorted(comports())
        init_idx = 0
        port = ''
        desc = ''
        if len(self._ports) > 0:
            for idx, (port, desc, _) in enumerate(self._ports, 1):
                self._lbx_port.insert(idx, port + ": " + desc)
                for kgp in KNOWNGPS:
                    if kgp in desc:
                        init_idx = idx
                        break
            self._noports = False
        else:
            self._noports = True
            self.set_controls(NOPORTS)
        self._lbx_port.activate(init_idx)
        self._port.set(port)
        self._port_desc.set(desc)

    def _reset(self):
        '''
        Reset settings to defaults.
        '''

        self._baudrate.set(BAUDRATES[4])  # 9600
        self._databits.set(8)
        self._stopbits.set(1)
        self._parity.set("None")
        self._rtscts.set(False)
        self._xonxoff.set(False)
        self._protocol.set(MIXED_PROTOCOL)
        self._format.set(DDD)
        self._units.set(UMM)
        self._autoscroll.set(1)
        self._maxlines.set(300)
        self._raw.set(False)
        self._webmap.set(False)
        self._mapzoom.set(10)
        self._datalog.set(False)
        self._record_track.set(False)

    def set_controls(self, status):
        '''
        ...for the heart of the sun.
        Public method to enable and disable serial port controls
        depending on connection status.
        '''

        self._lbl_port.configure(state=(NORMAL if status == DISCONNECTED else DISABLED))
        self._lbx_port.configure(state=(NORMAL if status == DISCONNECTED else DISABLED))
        self._lbl_baudrate.configure(state=(NORMAL if status == DISCONNECTED else DISABLED))
        self._spn_baudrate.configure(state=(READONLY if status == DISCONNECTED else DISABLED))
        self._lbl_databits.configure(state=(NORMAL if status == DISCONNECTED else DISABLED))
        self._spn_databits.configure(state=(READONLY if status == DISCONNECTED else DISABLED))
        self._lbl_stopbits.configure(state=(NORMAL if status == DISCONNECTED else DISABLED))
        self._spn_stopbits.configure(state=(READONLY if status == DISCONNECTED else DISABLED))
        self._lbl_parity.configure(state=(NORMAL if status == DISCONNECTED else DISABLED))
        self._spn_parity.configure(state=(READONLY if status == DISCONNECTED else DISABLED))
        self._chk_rts.configure(state=(NORMAL if status == DISCONNECTED else DISABLED))
        self._chk_xon.configure(state=(NORMAL if status == DISCONNECTED else DISABLED))
        self._btn_connect.config(state=(DISABLED if status in \
                                        (CONNECTED, CONNECTED_FILE, NOPORTS) \
                                        else NORMAL))
        self._btn_disconnect.config(state=(DISABLED if status in \
                                           (DISCONNECTED, NOPORTS) else NORMAL))
        self._chk_datalog.config(state=(DISABLED if status in \
                                        (CONNECTED, CONNECTED_FILE, NOPORTS) \
                                        else NORMAL))
        self._chk_recordtrack.config(state=(DISABLED if status in \
                                        (CONNECTED, CONNECTED_FILE) \
                                        else NORMAL))
        self._btn_connect_file.config(state=(DISABLED if status in \
                                             (CONNECTED, CONNECTED_FILE) \
                                             else NORMAL))
        self._btn_ubxconfig.config(state=(DISABLED if status in \
                                          (DISCONNECTED, CONNECTED_FILE, NOPORTS) \
                                          else NORMAL))
        self.__app.menu.options_menu.entryconfig(0, state=(DISABLED if status in \
                                          (CONNECTED_FILE, DISCONNECTED, NOPORTS) \
                                          else NORMAL))

    def get_settings(self):
        '''
        Public method returns all settings as a dict.
        '''

        self._settings['port'] = self._port.get()
        self._settings['noports'] = self._noports
        self._settings['port_desc'] = self._port_desc.get()
        self._settings['baudrate'] = self._baudrate.get()
        self._settings['databits'] = self._databits.get()
        self._settings['stopbits'] = self._stopbits.get()
        self._settings['parity'] = self._parity.get()
        self._settings['rtscts'] = self._rtscts.get()
        self._settings['xonxoff'] = self._xonxoff.get()
        self._settings['protocol'] = self._protocol.get()
        self._settings['raw'] = self._raw.get()
        self._settings['autoscroll'] = self._autoscroll.get()
        self._settings['maxlines'] = self._maxlines.get()
        self._settings['webmap'] = self._webmap.get()
        self._settings['mapzoom'] = self._mapzoom.get()
        self._settings['units'] = self._units.get()
        self._settings['format'] = self._format.get()
        self._settings['logpath'] = self._logpath
        self._settings['datalogging'] = self._datalog.get()
        self._settings['recordtrack'] = self._record_track.get()

        return self._settings

    def get_size(self):
        '''
        Get current frame size.
        '''

        self.update_idletasks()  # Make sure we know about any resizing
        return (self.winfo_width(), self.winfo_height())
Esempio n. 18
0
class SettingsForm:
    """TODO: INSERT DOCSTRING."""
    def __init__(self):
        """TODO: INSERT DOCSTRING."""
        self.form = tk.Tk()
        self.form.geometry(INIT_SCREEN_SIZE)
        self.form.minsize(MIN_SCREEN_SIZE[0], MIN_SCREEN_SIZE[1])
        self.form.title(SCREEN_TITLE)

        # Store the last status of the directory path to determine if the
        # directory changed in order to update the file display boxes.
        self.last_dir_path: str = Settings.directory_path

        # Each file in the current directory is stored as the key of a
        # dictionary, with each key mapping to a bool of if that file
        # is enabled or not.
        self.all_files: Dict[str, bool] = {}
        self.load_all_files()

        # Create the main frame to hold all the elements.
        self.frame: Frame = Frame(self.form, background=LIGHT_GRAY)
        # Make the main frame fit the size of the window.
        self.frame.pack(fill=BOTH, expand=1)

        # Track the most recenly selected item in the active files and disabled
        # files listboxes.
        self.sel_item_in_active_files: int = 0
        self.sel_item_in_disabled_files: int = 0

        self.create_widgets()

    def create_widgets(self):
        """Create all form elements, and populate the form.

        This should only be called once when the form is being created.
        """
        #
        # Form Layout Hierarchy:
        #
        #     Main Frame
        #     |---File Frame
        #     |   |---Active Files
        #     |   |---File Button Frame
        #     |   |   |---Activate Button
        #     |   |   |---Disable Button
        #     |   |---Disable Files
        #     |---Content Frame
        #     |   |---Directory Frame
        #     |   |   |---Directory Label
        #     |   |   |---Directory Input
        #     |   |---Font Size Frame
        #     |   |   |---Font Size Label
        #     |   |   |---Font Size Input
        #     |   |---Typeface Frame
        #     |   |   |---Typeface Label
        #     |   |   |---Typeface Input
        #     |   |---Theme Frame
        #     |   |   |---Theme Label
        #     |   |   |---Theme Input
        #     |   |---Display Item Frame
        #     |   |   |---Display Item Label
        #     |   |   |---Display Item Input
        #     |   |---Button Frame
        #     |   |   |---Save Button
        #     |   |   |---Cancel Button
        #

        # ----- FILE SELECTOR -----
        self.file_frame = Frame(self.frame, background=LIGHT_GRAY)
        self.file_frame.pack(fill=BOTH, expand=1, side=LEFT, padx=5, pady=5)

        self.active_files = Listbox(self.file_frame,
                                    relief=FLAT,
                                    foreground=BLACK,
                                    background=WHITE,
                                    highlightthickness=0)
        self.active_files.pack(fill=BOTH, expand=1, padx=5, pady=5)
        self.refresh_active_files()

        self.file_button_frame = Frame(self.file_frame, background=LIGHT_GRAY)
        self.file_button_frame.pack(fill=BOTH, expand=0, padx=5, pady=5)

        self.activate_button = Button(self.file_button_frame,
                                      text='▲',
                                      relief=FLAT,
                                      foreground=BLACK,
                                      background=MEDIUM_GRAY,
                                      command=self.activate_callback,
                                      highlightthickness=0)
        self.activate_button.pack(fill=BOTH,
                                  expand=1,
                                  side=LEFT,
                                  padx=5,
                                  pady=5)

        self.disable_button = Button(self.file_button_frame,
                                     text='▼',
                                     relief=FLAT,
                                     foreground=BLACK,
                                     background=MEDIUM_GRAY,
                                     command=self.disable_callback,
                                     highlightthickness=0)
        self.disable_button.pack(fill=BOTH,
                                 expand=1,
                                 side=RIGHT,
                                 padx=5,
                                 pady=5)

        self.disabled_files = Listbox(self.file_frame,
                                      relief=FLAT,
                                      foreground=BLACK,
                                      background=WHITE,
                                      highlightthickness=0)
        self.disabled_files.pack(fill=BOTH, expand=1, padx=5, pady=5)
        self.refresh_disabled_files()
        # ------------------------------

        self.content_frame = Frame(self.frame, background=LIGHT_GRAY)
        self.content_frame.pack(fill=Y, expand=0, side=RIGHT, padx=5, pady=10)

        # ----- DIRECTORY SETTING -----
        self.directory_frame = Frame(self.content_frame, background=LIGHT_GRAY)
        self.directory_frame.pack(fill=X, expand=0, side=TOP, padx=5, pady=10)

        self.directory_label = Label(self.directory_frame,
                                     text='Directory: ',
                                     font=DEFAULT_FONT,
                                     background=LIGHT_GRAY,
                                     foreground=BLACK)
        self.directory_label.pack(side=LEFT)

        self.directory_input = Entry(self.directory_frame,
                                     text='null',
                                     font=DEFAULT_FONT,
                                     background=WHITE,
                                     relief=FLAT,
                                     width=DEFAULT_WIDTH,
                                     foreground=BLACK,
                                     highlightthickness=0)
        self.directory_input.pack(side=LEFT)
        self.directory_input.insert(0, Settings.directory_path)
        # ------------------------------

        # ----- FONT SIZE SETTING -----
        self.font_size_frame = Frame(self.content_frame, background=LIGHT_GRAY)
        self.font_size_frame.pack(fill=X, expand=0, side=TOP, padx=5, pady=10)

        self.font_size_label = Label(self.font_size_frame,
                                     text='Font Size:',
                                     font=DEFAULT_FONT,
                                     background=LIGHT_GRAY,
                                     foreground=BLACK)
        self.font_size_label.pack(side=LEFT, anchor=SW)

        self.font_size_input = Scale(self.font_size_frame,
                                     orient=HORIZONTAL,
                                     font=DEFAULT_FONT,
                                     background=WHITE,
                                     relief=FLAT,
                                     from_=4,
                                     to=140,
                                     sliderlength=20,
                                     resolution=4,
                                     length=175,
                                     foreground=BLACK,
                                     highlightthickness=0)
        self.font_size_input.pack(side=LEFT)
        self.font_size_input.set(Settings.font_size)
        # ------------------------------

        # ----- TYPEFACE SETTING -----
        self.typeface_frame = Frame(self.content_frame, background=LIGHT_GRAY)
        self.typeface_frame.pack(fill=X, expand=0, side=TOP, padx=5, pady=10)

        self.typeface_label = Label(self.typeface_frame,
                                    text='Typeface: ',
                                    font=DEFAULT_FONT,
                                    background=LIGHT_GRAY,
                                    foreground=BLACK)
        self.typeface_label.pack(side=LEFT)

        self.typeface_input = Entry(self.typeface_frame,
                                    text='Verdana',
                                    font=DEFAULT_FONT,
                                    width=DEFAULT_WIDTH,
                                    background=WHITE,
                                    relief=FLAT,
                                    foreground=BLACK,
                                    highlightthickness=0)
        self.typeface_input.pack(side=LEFT)
        self.typeface_input.insert(0, Settings.typeface)
        # ------------------------------

        # ----- THEME SETTING -----
        self.theme_frame = Frame(self.content_frame, background=LIGHT_GRAY)
        self.theme_frame.pack(fill=X, expand=0, side=TOP, padx=5, pady=10)

        self.theme_label = Label(self.theme_frame,
                                 text='Theme: ',
                                 font=DEFAULT_FONT,
                                 background=LIGHT_GRAY,
                                 foreground=BLACK)
        self.theme_label.pack(side=LEFT)

        self.theme_input = Listbox(self.theme_frame,
                                   font=DEFAULT_FONT,
                                   background=WHITE,
                                   relief=FLAT,
                                   height=len(Settings.theme_names) + 3,
                                   width=DEFAULT_WIDTH + 2,
                                   foreground=BLACK,
                                   highlightthickness=0)
        self.theme_input.pack(side=LEFT)
        self.theme_input.insert(
            END, CURRENT_THEME_STR.format(Settings.current_theme))
        self.theme_input.insert(END, '')
        for theme_name in Settings.theme_names:
            self.theme_input.insert(END, theme_name)
        self.theme_input.select_set(0)
        # ------------------------------

        # ----- ITEM RANGE -----
        self.display_item_frame = Frame(self.content_frame,
                                        background=LIGHT_GRAY)
        self.display_item_frame.pack(fill=X,
                                     expand=0,
                                     side=TOP,
                                     padx=5,
                                     pady=10)

        self.display_item_label = Label(self.display_item_frame,
                                        text='Display Item: ',
                                        font=DEFAULT_FONT,
                                        background=LIGHT_GRAY,
                                        foreground=BLACK)
        self.display_item_label.pack(side=LEFT)

        self.display_item_input = Spinbox(self.display_item_frame,
                                          from_=-1,
                                          to=100,
                                          font=DEFAULT_FONT,
                                          width=DEFAULT_WIDTH - 4,
                                          background=WHITE,
                                          relief=FLAT,
                                          foreground=BLACK,
                                          highlightthickness=0)
        self.display_item_input.pack(side=LEFT)
        self.display_item_input.delete(0, END)
        self.display_item_input.insert(0, Settings.display_item)
        # ------------------------------

        # ----- SAVE AND CANCEL BUTTONS -----
        self.button_frame = Frame(self.content_frame, background=LIGHT_GRAY)
        self.button_frame.pack(fill=X, expand=0, side=BOTTOM, padx=10, pady=10)

        self.save_button = Button(self.button_frame,
                                  text='Save & Quit',
                                  background=MEDIUM_GRAY,
                                  relief=FLAT,
                                  command=self.save_callback,
                                  foreground=BLACK,
                                  highlightthickness=0)
        self.save_button.pack(side=RIGHT, padx=3, pady=3)

        self.cancel_button = Button(self.button_frame,
                                    text='Cancel',
                                    background=MEDIUM_GRAY,
                                    relief=FLAT,
                                    command=self.cancel_callback,
                                    foreground=BLACK,
                                    highlightthickness=0)
        self.cancel_button.pack(side=LEFT, padx=3, pady=3)
        # ------------------------------

    def cancel_callback(self) -> None:
        """Restore the previous saved settings and close the form."""
        FileReader.load_settings()
        self.form.destroy()

    def save_callback(self) -> None:
        """Save the newly updated settings and close the form."""
        FileReader.save_settings()
        self.form.destroy()

    def activate_callback(self) -> None:
        """Take currently selected 'disabled' file and sets it to 'enabled'."""
        # Get and save the index of the currently selected item if it exists,
        # this allows for the next item to be automatically selected after the
        # currently selected item is transfered, allowing for rapid item
        # activation.
        current_selection: tuple = self.disabled_files.curselection()
        if len(current_selection) > 0:
            self.sel_item_in_disabled_files = current_selection[0]

        file: str = str(self.disabled_files.get(ACTIVE))
        if file in self.all_files.keys():
            self.all_files[file] = True
        # Update the file display text boxes.
        self.refresh_active_files()
        self.refresh_disabled_files()
        self.disabled_files.activate(self.sel_item_in_disabled_files)

    def disable_callback(self) -> None:
        """Take currently selected 'enabled' file and sets it to 'disabled'."""
        # Get and save the index of the currently selected item if it exists,
        # this allows for the next item to be automatically selected after the
        # currently selected item is transfered, allowing for rapid item
        # deactivation.
        current_selection: tuple = self.active_files.curselection()
        if len(current_selection) > 0:
            self.sel_item_in_active_files = current_selection[0]

        file: str = str(self.active_files.get(ACTIVE))
        if file in self.all_files.keys():
            self.all_files[file] = False
        # Update the file display text boxes.
        self.refresh_active_files()
        self.refresh_disabled_files()
        self.active_files.activate(self.sel_item_in_active_files)

    def refresh_active_files(self) -> None:
        """Clear and fill active files text box with current active files.

        This refreshes the data in the text box. Replacing the old data with
        the new data, keeping it up to date.
        """
        self.active_files.delete(0, END)
        self.active_files.insert(END, '       active       ')
        self.active_files.insert(END, '--------------------')
        for file in self.all_files:
            if self.all_files[file]:  # File is active.
                self.active_files.insert(END, file)

    def refresh_disabled_files(self) -> None:
        """Clear and fill disabled files text box with current disabled files.

        This refreshes the data in the text box. Replacing the old data with
        the new data, keeping it up to date.
        """
        self.disabled_files.delete(0, END)
        self.disabled_files.insert(END, '      disabled      ')
        self.disabled_files.insert(END, '--------------------')
        for file in self.all_files:
            if not self.all_files[file]:  # File is disabled.
                self.disabled_files.insert(END, file)

    def load_all_files(self) -> None:
        """Load all files from the current directory into self.all_files.

        This also sets the state if the files are active or disabled.
        """
        dir_path: str = Settings.directory_path
        all_files: Dict[str, bool] = {}
        if os.path.exists(dir_path):
            # Loops through all files in the current directory.
            for file in [
                    f for f in os.listdir(dir_path)
                    if os.path.isfile(os.path.join(dir_path, f))
            ]:
                is_active: bool = file in Settings.active_files
                # Add new file (key) and activity status (value) to all_files
                # dict.
                all_files[file] = is_active
        self.all_files = all_files

    def update_directory_path(self) -> str:
        """Return the current directory in the directory input box.

        Update the current working files and file display boxes if
        a new directory was set.

        Returns:
            str: The directory path to be saved to the settings.
        """
        new_dir_path: str = self.directory_input.get()
        # Update the current working files and file display boxes if the
        # directory changed. This is done to always display the files that
        # are in the current directory.
        if self.last_dir_path != Settings.directory_path:
            self.load_all_files()
            self.refresh_active_files()
            self.refresh_disabled_files()
            self.last_dir_path = Settings.directory_path
        # Set the last directory, then return the new directory to be
        # set the the settings. This makes it so that the elements update
        # from the conditional above. This is because the Settings will be
        # updated after this function returns.
        elif new_dir_path != Settings.directory_path:
            self.last_dir_path = Settings.directory_path
            return new_dir_path
        return Settings.directory_path

    def update_theme(self) -> str:
        """Return the current theme in the theme input box.

        Use current theme if new theme isn't valid (i.e. title portion), and
        update the currenly selected theme in the input box.

        Returns:
            str: The name of the new theme to be saved to the settings.
        """
        # Get the current selected theme from the Listbox. If the theme
        # is not valid, set it to the current theme so that a valid theme
        # is always used.
        theme_name: str = str(self.theme_input.get(ACTIVE))
        if theme_name not in Settings.theme_names:
            theme_name = Settings.current_theme
        # Reset the first element of the Listbox which displays the current
        # theme, this shows the user the name of the theme that is currently
        # enabled. This also has the side effect of that element not being
        # able to be selected (which doesn't change anything).
        self.theme_input.delete(0)
        self.theme_input.insert(
            0, CURRENT_THEME_STR.format(Settings.current_theme))

        return theme_name

    def update_settings(self) -> None:
        """Set all of the current form values to the settings."""
        # Get the current directory path.
        dir_path: str = self.update_directory_path()
        # Get the current theme name.
        theme_name: str = self.update_theme()
        # Get all active files.
        active_files: List[str] = [
            f for f in self.all_files if self.all_files[f]
        ]
        # Get the current display item, or 0 if invalid value.
        display_item: int = 0
        try:
            display_item = int(self.display_item_input.get())
        except ValueError:
            pass

        # Update the setings to the new values.
        Settings.set_value({
            "directory_path": dir_path,
            "active_files": active_files,
            "display_item": display_item,
            "font_size": self.font_size_input.get(),
            "typeface": self.typeface_input.get(),
            "current_theme": theme_name,
        })

    def update(self):
        """Update the form screen.

        This is used to update the screen and settings every 'tick' when this
        function is called.
        """
        try:
            self.update_settings()
            self.form.update_idletasks()
            self.form.update()
        except TclError:  # The form has been destroyed (i.e. on exit)
            # Return None so the main form knows this form is no longer active.
            return None
        # Return itself so the main form knows this form is still active.
        return self
Esempio n. 19
0
class TShapesWindow(Frame):
    """
    Class represents auxiliary window containg shapes information.

    :param master: master window object.
    :type master: tkinter.Tk
    :param app: main app object.
    :type app: TApp
    """
    def __init__(self, master, TApp):
        """
        Call the parent class constructor and initialise object variables.
        """
        super().__init__()
        self.TApp = TApp
        self.round_digits = TTicksSettings.ROUND_DIGITS
        self.init_widgets()

    def init_widgets(self):
        """
        Init frame widgets.
        """
        # Listbox
        self.shapes_list = Listbox(self,
                                   exportselection=False,
                                   selectmode=EXTENDED)
        self.grid_columnconfigure(0, weight=1, minsize=300)
        self.grid_rowconfigure(0, weight=1)
        self.shapes_list.grid(row=0,
                              column=0,
                              sticky=NSEW,
                              padx=(5, 25),
                              pady=5)
        self.shapes_list.bind("<<ListboxSelect>>",
                              self.shapes_list_selected_item)

        # Listbox's yscrollbar
        self.shapes_list_scrollbar = Scrollbar(self, orient = VERTICAL, \
                                               command = self.shapes_list.yview)
        self.shapes_list_scrollbar.grid(row=0,
                                        column=0,
                                        sticky=NS + E,
                                        padx=(0, 5),
                                        pady=5)
        self.shapes_list.config(yscrollcommand=self.shapes_list_scrollbar.set)

        # Drop down menu with materials
        self.material_box = Combobox(self, values=["pec", "free_space"])
        self.material_box.grid(row=1, column=0, sticky=EW, padx=5, pady=5)
        self.material_box.bind("<<ComboboxSelected>>",
                               self.assign_material_to_shape)

        # Right click popup menu
        self.init_popup_menu()
        self.shapes_list.bind("<Button-3>", self.show_popoup_menu)

        # Delete key removes selected shape(s)
        self.shapes_list.bind("<Delete>", self.remove_shape)

    def update_list(self, shapes, *, swap=False):
        """
        Update shapes list.

        :param swap: shapes list selection swap toggle.
        :type swap: boolean
        """
        selection = self.shapes_list.curselection()
        try:
            shape_num = selection[0]
        except:
            shape_num = 0
        self.shapes_list.delete(0, END)
        coord_string = ""
        for i, single_shape in enumerate(shapes):
            if (single_shape.type == "Rectangle"):
                coord_string = "(" + str(round(single_shape.point1_mod.x, self.round_digits)) + \
                               ", " + str(round(single_shape.point1_mod.y, self.round_digits)) + \
                               "), (" + str(round (single_shape.point2_mod.x, self.round_digits)) + \
                               ", " + str(round(single_shape.point2_mod.y, self.round_digits)) + ")"
            elif (single_shape.type == "Cylinder"):
                coord_string = "(" + str(round(single_shape.centre_mod.x, self.round_digits)) + \
                                ", " + str(round(single_shape.centre_mod.y, self.round_digits)) + \
                                "), " + str(round(single_shape.radius_mod, self.round_digits))
            elif (single_shape.type == "CylinSector"):
                coord_string = "(" + str(round(single_shape.centre_mod.x, self.round_digits)) + \
                               ", " + str(round(single_shape.centre_mod.y, self.round_digits)) + \
                               "), " + str(round(single_shape.radius_mod, self.round_digits)) + \
                               ", " + str(round(single_shape.start, self.round_digits)) + \
                               ", " + str(round(single_shape.extent, self.round_digits))
            elif (single_shape.type == "Polygon"):
                coord_string = str(len(single_shape.points))
            self.shapes_list.insert(
                i,
                str(i + 1) + ". " + single_shape.type + ": " + coord_string)
            coord_string = ""
        if (not swap):
            self.shapes_list.select_clear(0, END)
            if (shape_num >= self.shapes_list.size()):
                self.shapes_list.selection_set(shape_num - 1)
                self.shapes_list.activate(shape_num)
            else:
                for item in selection:
                    self.shapes_list.selection_set(item)
                self.shapes_list.activate(shape_num)

    def assign_material_to_shape(self, event):
        """
        Assign material to a shape.

        :param event: event evoking this method (listbox select).
        :type event: tkinter.Event
        """
        material = self.material_box.get()
        try:
            shape_num = (self.shapes_list.curselection())[0]
        except:
            return
        else:
            if (shape_num < 0 or material == ""):
                return
            else:
                try:
                    self.TApp.shapes[shape_num].material = material
                except Exception as message:
                    messagebox.showerror("Material assignment error!", message)
                    return

    def shapes_list_selected_item(self, event):
        """
        Handle listbox selection event.

        :param event: event evoking this method (listbox select).
        :type event: tkinter.Event
        """
        # Add multiple selection
        self.shapes_list.focus_force()
        try:
            shape_num = (self.shapes_list.curselection())[0]
            selection = self.shapes_list.curselection()
        except IndexError:
            return
        except Exception as message:
            messagebox.showerror("Error while picking shape!", message)
        if (shape_num < 0):
            return
        else:
            try:
                shape = self.TApp.shapes[shape_num]
            except Exception as message:
                messagebox.showerror("Materials list error", message)
                return

        self.material_box.set(str(shape.material))

        for single_shape in self.TApp.shapes:
            single_shape.width = 1

        for item in selection:
            self.TApp.shapes[item].width = 2
        self.TApp.main_canvas.delete("all")
        for item in selection:
            self.shapes_list.selection_set(item)
        self.TApp.canvas_refresh()

    def init_popup_menu(self):
        """
        Init shapes pane pup-up menu.
        """
        self.popup_menu = Menu(self, tearoff=0)
        self.popup_menu.add_command(label="Edit shape",
                                    command=self.edit_shape)
        self.popup_menu.add_command(label="Change shape colour",
                                    command=self.change_shape_colour)
        self.popup_menu.add_command(label="Remove shape(s)",
                                    command=self.remove_shape)
        self.popup_menu.add_separator()
        self.popup_menu.add_command(label="Add vertex to polygon",
                                    command=self.add_vertex_to_polygon)
        self.popup_menu.add_separator()
        self.popup_menu.add_command(label="Copy shape",
                                    command=self.copy_shape)
        self.popup_menu.add_command(label="Paste shape",
                                    command=self.paste_shape)
        self.popup_menu.add_separator()
        self.popup_menu.add_command(label="Move up",
                                    command=self.move_shape_up)
        self.popup_menu.add_command(label="Move down",
                                    command=self.move_shape_down)
        self.popup_menu.add_command(label="Move to top",
                                    command=self.move_shape_top)
        self.popup_menu.add_command(label="Move to bottom",
                                    command=self.move_shape_bottom)

    def show_popoup_menu(self, event):
        """
        Show shapes list pop-up menu.

        :param event: event evoking this method (RMB click).
        :type event: tkinter.Event
        """
        try:
            self.popup_menu.post(event.x_root, event.y_root)
        finally:
            self.popup_menu.grab_release()

    def move_shape_up(self):
        """
        Move a shape one place up the shapes list.
        """
        try:
            shape_num = (self.shapes_list.curselection())[0]
        except IndexError:
            return
        if (shape_num < 0):
            return
        else:
            try:
                self.TApp.shapes.insert(shape_num - 1,
                                        self.TApp.shapes.pop(shape_num))
                self.update_list(self.TApp.shapes)
                self.TApp.main_canvas.delete("all")
                self.TApp.canvas_refresh(swap=True)
                self.shapes_list.selection_set(shape_num - 1)
                self.shapes_list.activate(shape_num - 1)
            except Exception as message:
                messagebox.showerror("Error while manipulating shapes list!",
                                     message)
                return

    def move_shape_down(self):
        """
        Move a shape one place down the shapes list.
        """
        try:
            shape_num = (self.shapes_list.curselection())[0]
        except IndexError:
            return
        if (shape_num < 0):
            return
        else:
            try:
                self.TApp.shapes.insert(shape_num + 1,
                                        self.TApp.shapes.pop(shape_num))
                self.update_list(self.TApp.shapes)
                self.TApp.main_canvas.delete("all")
                self.TApp.canvas_refresh(swap=True)
                self.shapes_list.selection_set(shape_num + 1)
                self.shapes_list.activate(shape_num + 1)
            except Exception as message:
                messagebox.showerror("Error while manipulating shapes list!",
                                     message)
                return

    def move_shape_top(self):
        """
        Move a shape to the top of the shapes list.
        """
        try:
            shape_num = (self.shapes_list.curselection())[0]
        except IndexError:
            return
        if (shape_num < 0):
            return
        else:
            try:
                self.TApp.shapes.insert(0, self.TApp.shapes.pop(shape_num))
                self.update_list(self.TApp.shapes)
                self.TApp.main_canvas.delete("all")
                self.TApp.canvas_refresh(swap=True)
                self.shapes_list.selection_set(0)
                self.shapes_list.activate(0)
                # self.shapes_list.focus_set ()
            except Exception as message:
                messagebox.showerror("Error while manipulating shapes list!",
                                     message)
                return

    def move_shape_bottom(self):
        """
        Move a shape to the bottom of the shapes list.
        """
        try:
            shape_num = (self.shapes_list.curselection())[0]
        except IndexError:
            return
        if (shape_num < 0):
            return
        else:
            try:
                self.TApp.shapes.append(self.TApp.shapes.pop(shape_num))
                self.update_list(self.TApp.shapes)
                self.TApp.main_canvas.delete("all")
                self.TApp.canvas_refresh(swap=True)
                self.shapes_list.selection_set(END)
                self.shapes_list.activate(END)
            except Exception as message:
                messagebox.showerror("Error while manipulating shapes list!",
                                     message)
                return

    def edit_shape(self):
        """
        Edit selected shape on the shapes list.
        """
        try:
            shape_num = (self.shapes_list.curselection())[0]
        except IndexError:
            return
        if (shape_num < 0):
            return
        else:
            self.TApp.operations.append(TOperation("edit", shape = \
                                                   deepcopy(self.TApp.shapes[shape_num]), \
                                                   num = shape_num))
            if (self.TApp.shapes[shape_num].type == "Rectangle"):
                self.TApp.edit_rectangle(shape_num)
            elif (self.TApp.shapes[shape_num].type == "Cylinder"):
                self.TApp.edit_cylin(shape_num)
            elif (self.TApp.shapes[shape_num].type == "CylinSector"):
                self.TApp.edit_cylin_sector(shape_num)
            elif (self.TApp.shapes[shape_num].type == "Polygon"):
                self.TApp.edit_polygon(shape_num)

    def change_shape_colour(self):
        """
        Change selected shape on the shapes list colour.
        """
        try:
            shape_num = (self.shapes_list.curselection())[0]
        except IndexError:
            return
        if (shape_num < 0):
            return
        else:
            self.TApp.change_shape_colour(shape_num=shape_num)

    def remove_shape(self, event=None):
        """
        Remove selected shape on the shapes list.
        """
        try:
            selection = self.shapes_list.curselection()
        except IndexError:
            return
        if (len(selection) == 0):
            return
        else:
            try:
                for item in reversed(selection):
                    del self.TApp.shapes[item]
                self.update_list(self.TApp.shapes)
                self.TApp.main_canvas.delete("all")
                self.TApp.canvas_refresh()
            except Exception as message:
                messagebox.showerror("Error while manipulating shapes list!",
                                     message)
                return

    def add_vertex_to_polygon(self):
        """
        Add a vertex to selected polygon on the shapes list.
        """
        try:
            shape_num = (self.shapes_list.curselection())[0]
        except IndexError:
            return
        input_str = simpledialog.askstring("Input coordinates",
                                           "Give mew vertex's coordinates")
        point_mod_x, point_mod_y = [float(val) for val in input_str.split()]
        if (self.TApp.shapes[shape_num].type == "Polygon" and shape_num > -1):
            self.TApp.shapes[shape_num].add_vertex(x_mod=point_mod_x,
                                                   y_mod=point_mod_y)
        self.TApp.main_canvas.delete("all")
        self.TApp.canvas_refresh()

    def copy_shape(self):
        """
        Copy selected shape on the shapes list.
        """
        try:
            shape_num = self.shapes_list.curselection()[0]
        except:
            shape_num = -1
        if (shape_num > -1):
            try:
                self.TApp.copy_shape(shape_num=shape_num)
            except Exception as message:
                messagebox.showerror("Error while manipulating shapes list!",
                                     message)

    def paste_shape(self, *, deltax=15, deltay=15):
        """
        Paste selected shape from buffer.
        
        :param deltax: pasted shape offset in x direction in pixels.
        :type deltax: integer
        :param deltay: pasted shape offset in y direction in pixels.
        :type deltay: integer
        """
        self.TApp.paste_ctrl_v(Event())
Esempio n. 20
0
class Player:
    def __init__(self, master):
        self.master = master
        pygame.init()
        pygame.mixer.init()

        #===Empty thread list=====#
        self.threads = []

        #=====show an icon for the player===#
        def get_icon():
            self.winicon = PhotoImage(file="best (2).png")
            master.iconphoto(False, self.winicon)

        #=====run the get_icon on a different thread from the gui=====#

        def icon():
            mythreads = threading.Thread(target=get_icon)
            self.threads.append(mythreads)
            mythreads.start()

        icon()

        #=======all Button symbols and variables======#

        PLAY = "►"
        PAUSE = "║║"
        RWD = "⏮"
        FWD = "⏭"
        STOP = "■"
        UNPAUSE = "||"
        mute = "🔇"
        unmute = u"\U0001F50A"
        vol_mute = 0.0
        vol_unmute = 1

        #==========music playlist listbox=========#
        self.scroll = Scrollbar(master)
        self.play_list = Listbox(master,
                                 font="Sansarif 12 bold",
                                 bd=5,
                                 bg="white",
                                 width=37,
                                 height=19,
                                 selectbackground="black")
        self.play_list.place(x=600, y=77)
        self.scroll.place(x=946, y=80, height=389, width=15)
        self.scroll.config(command=self.play_list.yview)
        self.play_list.config(yscrollcommand=self.scroll.set)

        files = 'best (2).png'
        self.img1 = Image.open(files)
        self.img1 = self.img1.resize((600, 470), Image.ANTIALIAS)
        self.img = ImageTk.PhotoImage(self.img1)
        self.lab = Label(master)
        self.lab.grid(row=0, column=0)
        self.lab["compound"] = LEFT
        self.lab["image"] = self.img

        #=====show the song playing==========#
        self.var = StringVar()
        self.var.set(
            ".............................................................................."
        )
        self.song_title = Label(master,
                                font="Helvetica 12 bold",
                                bg="black",
                                fg="white",
                                width=60,
                                textvariable=self.var)
        self.song_title.place(x=3, y=0)

        # =====add a music list to the listbox======"

        def append_listbox():
            global song_list
            try:
                directory = askdirectory()
                os.chdir(directory)  # it permits to change the current dir
                song_list = os.listdir()
                song_list.reverse()
                for item in song_list:  # it returns the list of files song
                    pos = 0
                    self.play_list.insert(pos, item)
                    pos += 1

                global size
                index = 0
                size = len(song_list)
                self.play_list.selection_set(index)
                self.play_list.see(index)
                self.play_list.activate(index)
                self.play_list.selection_anchor(index)

            except:
                showerror("File selected error",
                          "Please choose a file correctly")

        # =====run the append_listbox function on separate thread====== #

        def add_songs_playlist():
            mythreads = threading.Thread(target=append_listbox)
            self.threads.append(mythreads)
            mythreads.start()

        #=====show music time=========#

        def get_time():
            current_time = pygame.mixer.music.get_pos() / 1000
            formated_time = time.strftime("%H:%M:%S",
                                          time.gmtime(current_time))
            next_one = self.play_list.curselection()
            song = self.play_list.get(next_one)
            song_timer = MP3(song)
            song_length = int(song_timer.info.length)
            format_for_length = time.strftime("%H:%M:%S",
                                              time.gmtime(song_length))
            self.label_time.config(
                text=f"{ format_for_length} / {formated_time}")
            self.progress["maximum"] = song_length
            self.progress["value"] = int(current_time)
            master.after(100, get_time)

        #=====play the music====#

        def Play_music():
            try:
                track = self.play_list.get(ACTIVE)
                pygame.mixer.music.load(track)
                self.var.set(track)
                pygame.mixer.music.play()
                get_time()

                # iterate through all the songs in the playlist
                # there is a bug when closing the window

            except:
                showerror("No Music", "Please load the music you want to play")

        def playAll():
            try:
                index = 0
                for i in range(size):
                    self.play_list.select_clear(0, END)
                    self.play_list.selection_set(index, last=None)
                    self.play_list.see(index)
                    self.play_list.activate(index)
                    self.play_list.selection_anchor(index)
                    track = self.play_list.get(index)
                    pygame.mixer.music.load(track)
                    self.var.set(track)
                    pygame.mixer.music.play()
                    current_song = self.play_list.curselection()
                    song = self.play_list.get(current_song)
                    song_timer = MP3(song)
                    song_length = int(song_timer.info.length) * 1000
                    get_time()
                    index += 1
            except:
                showerror("No songs in playlist", "Please add music")

        def play_all():
            mythreads = threading.Thread(target=playAll)
            self.threads.append(mythreads)
            mythreads.start()

        # ===pause and unpause == #

        def pause_unpause():
            if self.button_pause['text'] == PAUSE:
                pygame.mixer.music.pause()
                self.button_pause['text'] = UNPAUSE

            elif self.button_pause['text'] == UNPAUSE:
                pygame.mixer.music.unpause()
                self.button_pause['text'] = PAUSE

        # ==play the music on a diffent thread from the gui == #

        def play_thread():
            mythreads = threading.Thread(target=Play_music)
            self.threads.append(mythreads)
            mythreads.start()

        master.bind("<space>", lambda x: play_thread())

        # ===stop===

        def stop():
            pygame.mixer.music.stop()

        #====increase and decrease volume when slider is moved()==#

        def volume(x):
            pygame.mixer.music.set_volume(self.volume_slider.get())

        # ====mute and unmute the song while the song plays== #

        def muted():
            if self.button_mute['text'] == unmute:
                pygame.mixer.music.set_volume(vol_mute)
                self.volume_slider.set(vol_mute)
                self.button_mute['fg'] = "red"
                self.button_mute['text'] = mute
            elif self.button_mute['text'] == mute:
                pygame.mixer.music.set_volume(vol_unmute)
                self.volume_slider.set(vol_unmute)
                self.button_mute['fg'] = "white"
                self.button_mute['text'] = unmute

        #===move to the next song===#

        def nextSong():
            try:
                next_one = self.play_list.curselection()
                next_one = next_one[0] + 1
                song = self.play_list.get(next_one)
                pygame.mixer.music.load(song)
                pygame.mixer.music.play()
                self.play_list.select_clear(0, END)
                self.play_list.activate(next_one)
                self.play_list.selection_set(next_one, last=None)
                self.var.set(song)
                get_time()
                self.play_list.see(next_one)
            except:
                showerror("No Next Song", "Please press the previous button")

        def next():
            mythreads = threading.Thread(target=nextSong)
            self.threads.append(mythreads)
            mythreads.start()

        #===move to the previous song===#

        def prevSong():
            try:
                next_one = self.play_list.curselection()
                next_one = next_one[0] - 1
                song = self.play_list.get(next_one)
                pygame.mixer.music.load(song)
                pygame.mixer.music.play()
                self.play_list.select_clear(0, END)
                self.play_list.activate(next_one)
                self.play_list.selection_set(next_one, last=None)
                self.var.set(song)
                get_time()
                self.play_list.see(next_one)
            except:
                showerror("No previous Song", "Please press the Next button")

        def prev():
            mythreads = threading.Thread(target=prevSong)
            self.threads.append(mythreads)
            mythreads.start()

        self.master.bind('<Left>', lambda x: prev())
        self.master.bind('<Right>', lambda x: next())

        #=====exit the application=====#

        def exit():
            MsgBox = askquestion(
                'Exit Application',
                'Are you sure you want to exit the music player.',
                icon='warning')
            if MsgBox == 'yes':
                master.quit()
                master.after(100, exit)
            else:
                showinfo('Return', 'Continue playing your awesome music')
            return

        #=====Help window=====#

        def help():
            top = Toplevel()
            top.title("Help")
            top.geometry("350x554+500+80")
            top.resizable(width=0, height=0)
            user_manual = [
                " MUSIC PLAYER USER MANUAL: \n", "1. play button =  ( ► )",
                "2. pause button = ║║ ", "3. unpause symbol = ||",
                "4. next button = ⏭ ", "5. previous button = ⏮",
                "6. mute button = '\U0001F50A' ", "7. unmute symbol = 🔇",
                "8. stop button = ■ ",
                "\n\n| Made by manucho | Copyright @ 2021 |\n"
            ]
            for i in user_manual:
                manual = Label(top,
                               text=i,
                               width=50,
                               height=3,
                               font="Helvetica, 11",
                               bg="black",
                               fg="white")
                manual.pack(side=TOP, fill=BOTH)

        #==============================================================================================#
        #   THis part contains the menu, volume slider , music playlist label and the volume slider  #
        #===============================================================================================#

        self.menu = Menu(
            self.lab,
            font="helvetica, 3",
        )
        master.config(menu=self.menu)
        self.menu.add_command(label="HELP", command=help)
        self.menu.add_command(label="EXIT", command=exit)

        self.separator = ttk.Separator(self.lab, orient='horizontal')
        self.separator.place(relx=0, rely=0.87, relwidth=1, relheight=1)
        self.button_play = Button(master,
                                  text=PLAY,
                                  width=5,
                                  bd=5,
                                  bg="black",
                                  fg="white",
                                  font="Helvetica, 15",
                                  command=play_thread)
        self.button_play.place(x=150, y=415)
        self.button_stop = Button(master,
                                  text=STOP,
                                  width=5,
                                  bd=5,
                                  font="Helvetica, 15",
                                  bg="black",
                                  fg="white",
                                  command=stop)
        self.button_stop.place(x=225, y=415)
        self.button_prev = Button(master,
                                  text=FWD,
                                  width=5,
                                  bd=5,
                                  font="Helvetica, 15",
                                  bg="black",
                                  fg="white",
                                  command=next)
        self.button_prev.place(x=300, y=415)

        self.buttonPlayall = Button(self.master,
                                    text='\U0001F500',
                                    bg='black',
                                    fg='white',
                                    font='Helvetica, 15',
                                    bd=5,
                                    width=3,
                                    command=play_all)
        self.buttonPlayall.place(x=375, y=415)

        self.button_next = Button(master,
                                  text=RWD,
                                  width=5,
                                  bd=5,
                                  bg="black",
                                  fg="white",
                                  font="Helvetica, 15",
                                  command=prev)
        self.button_next.place(x=10, y=415)
        self.button_pause = Button(master,
                                   text=PAUSE,
                                   width=4,
                                   bd=5,
                                   font="Helvetica, 15",
                                   bg="black",
                                   fg="white",
                                   command=pause_unpause)
        self.button_pause.place(x=85, y=415)

        self.button_mute = Button(master,
                                  text=unmute,
                                  width=2,
                                  bd=5,
                                  font="Helvetica, 15",
                                  bg="black",
                                  fg="white",
                                  command=muted)
        self.button_mute.place(x=430, y=415)

        self.label_playlist = Label(master,
                                    text=u"♫ Music Playlist ♫ ",
                                    width=31,
                                    font="Helvetica, 15")
        self.label_playlist.place(x=610, y=5)

        self.button_load_music = Button(
            master,
            text="♫ Click Here To Load The Music ♫",
            width=43,
            bd=5,
            font="Helvetica, 10",
            bg="black",
            fg="white",
            command=add_songs_playlist)
        self.button_load_music.place(x=605, y=45)

        self.style = ttk.Style()

        self.style.configure("myStyle.Horizontal.TScale", background="#505050")

        self.volume_slider = ttk.Scale(self.lab,
                                       from_=0,
                                       to=1,
                                       orient=HORIZONTAL,
                                       value=1,
                                       length=120,
                                       command=volume,
                                       style="myStyle.Horizontal.TScale")
        self.volume_slider.place(x=475, y=424)

        self.progress = ttk.Progressbar(self.lab,
                                        orient=HORIZONTAL,
                                        value=0,
                                        length=453,
                                        mode='determinate')
        self.progress.place(x=0, y=385)

        self.label_time = Label(master,
                                text="00:00:00 / 00:00:00",
                                width=17,
                                font="Helvetica, 10",
                                bg="black",
                                fg="white")
        self.label_time.place(x=460, y=387)
Esempio n. 21
0
class SettingsFrame(Frame):
    """
    Frame inheritance class for application settings and controls.
    """
    def __init__(self, app, *args, **kwargs):
        """
        Constructor
        """

        self.__app = app  # Reference to main application class
        self.__master = self.__app.get_master()  # Reference to root class (Tk)
        Frame.__init__(self, self.__master, *args, **kwargs)

        #  Initialise up key variables
        self._image_num = 0
        self._image_name = "image"
        self._settype = StringVar()
        self._zoom = DoubleVar()
        self._radius = DoubleVar()
        self._exponent = IntVar()
        self._zx_off = DoubleVar()
        self._zy_off = DoubleVar()
        self._cx_off = DoubleVar()
        self._cy_off = DoubleVar()
        self._maxiter = IntVar()
        self._zx_coord = DoubleVar()
        self._zy_coord = DoubleVar()
        self._theme = StringVar()
        self._shift = IntVar()
        self._themes = None
        self._filename = StringVar()
        self._filepath = None
        self._frames = IntVar()
        self._zoominc = DoubleVar()
        self._autoiter = IntVar()
        self._autosave = IntVar()
        self._validsettings = True

        self.body()

    def body(self):
        """
        Set up frame and widgets.
        """

        # Create settings panel widgets
        # pylint: disable=W0108
        self.lbl_settype = Label(self, text=LBLMODE)
        self.spn_settype = Spinbox(
            self,
            values=("BurningShip", "Tricorn", "Julia", "Mandelbrot"),
            width=8,
            bg=GOOD,
            wrap=True,
            textvariable=self._settype,
        )
        self.lbl_zoom = Label(self, text=LBLZOOM)
        self.ent_zoom = Entry(
            self,
            border=2,
            relief="sunken",
            width=12,
            bg=GOOD,
            justify=RIGHT,
            textvariable=self._zoom,
        )
        self.lbl_zoominc = Label(self, text=LBLZOOMINC, justify=LEFT)
        self.ent_zoominc = Entry(self,
                                 width=5,
                                 border=2,
                                 bg=GOOD,
                                 justify=RIGHT,
                                 textvariable=self._zoominc)
        self.lbl_zx_off = Label(self, text=LBLZXOFF)
        self.ent_zx_off = Entry(
            self,
            border=2,
            relief="sunken",
            width=12,
            bg=GOOD,
            justify=RIGHT,
            textvariable=self._zx_off,
        )
        self.lbl_zy_off = Label(self, text=LBLZYOFF)
        self.ent_zy_off = Entry(
            self,
            border=2,
            relief="sunken",
            width=12,
            bg=GOOD,
            justify=RIGHT,
            textvariable=self._zy_off,
        )
        self.lbl_cx_off = Label(self, text=LBLCX)
        self.ent_cx_off = Entry(
            self,
            border=2,
            relief="sunken",
            width=12,
            bg=GOOD,
            justify=RIGHT,
            textvariable=self._cx_off,
            state=DISABLED,
        )
        self.lbl_cy_off = Label(self, text=LBLCY)
        self.ent_cy_off = Entry(
            self,
            border=2,
            relief="sunken",
            width=12,
            bg=GOOD,
            justify=RIGHT,
            textvariable=self._cy_off,
            state=DISABLED,
        )
        self.lbl_niter = Label(self, text=LBLITER, justify=LEFT)
        self.ent_maxiter = Entry(
            self,
            border=2,
            relief="sunken",
            bg=GOOD,
            width=8,
            justify=RIGHT,
            textvariable=self._maxiter,
        )
        self.chk_autoiter = Checkbutton(self,
                                        text="Auto",
                                        variable=self._autoiter,
                                        onvalue=1,
                                        offvalue=0)
        self.lbl_theme = Label(self, text=LBLTHEME, justify=LEFT)
        self.lbl_radius = Label(self, text=LBLRAD, justify=LEFT)
        self.ent_radius = Entry(
            self,
            border=2,
            relief="sunken",
            bg=GOOD,
            width=8,
            justify=RIGHT,
            textvariable=self._radius,
        )
        self.lbl_exp = Label(self, text=LBLEXP)
        self.spn_exp = Spinbox(
            self,
            border=2,
            relief="sunken",
            bg=GOOD,
            width=4,
            from_=2,
            to=20,
            wrap=True,
            textvariable=self._exponent,
        )
        self.sep_1 = ttk.Separator(
            self,
            orient=HORIZONTAL,
        )
        self.lbx_theme = Listbox(
            self,
            border=2,
            relief="sunken",
            bg=GOOD,
            width=6,
            height=5,
            justify=LEFT,
            exportselection=False,
        )
        self.lbl_shift = Label(self, text=LBLSHIFT, justify=LEFT)
        self.scl_shift = Scale(
            self,
            from_=0,
            to=100,
            orient=HORIZONTAL,
            variable=self._shift,
            border=2,
            relief="sunken",
            sliderlength=20,
            troughcolor=GOOD,
        )
        self.scrollbar = Scrollbar(self, orient=VERTICAL)
        self.lbx_theme.config(yscrollcommand=self.scrollbar.set)
        self.scrollbar.config(command=self.lbx_theme.yview)
        self.lbx_theme.select_set(0)
        self.lbx_theme.event_generate("<<ListboxSelect>>")
        self.lbl_coords = Label(self, text="Re, Im", fg="grey")
        self.btn_plot = Button(
            self,
            text=BTNPLOT,
            width=8,
            fg="green",
            command=lambda: self.__app.frm_fractal.plot(),
        )
        self.btn_cancel = Button(
            self,
            text=BTNCAN,
            width=8,
            command=lambda: self.__app.frm_fractal.cancel_press(),
        )
        self.btn_reset = Button(self, text=BTNRST, width=8, command=self.reset)
        self.ent_save = Entry(
            self,
            textvariable=self._filename,
            width=6,
            border=2,
            relief="sunken",
            bg=GOOD,
            justify=LEFT,
        )
        self._filename.set(self._image_name + str(self._image_num))
        self.btn_save = Button(self,
                               text=BTNSAVE,
                               width=8,
                               command=self.save_image)
        self.lbl_auto = Label(self, text=LBLAUTO, justify=LEFT)
        self.btn_autozoom = Button(
            self,
            text=BTNZOOM,
            width=8,
            command=lambda: self.__app.frm_fractal.animate_zoom(),
        )
        self.btn_autospin = Button(
            self,
            text=BTNSPIN,
            width=8,
            command=lambda: self.__app.frm_fractal.animate_spin(),
            state=DISABLED,
        )
        self.chk_autosave = Checkbutton(self,
                                        text=BTNSAVE,
                                        variable=self._autosave,
                                        onvalue=1,
                                        offvalue=0)
        self.lbl_frames = Label(self, text=FRMSTXT)
        self.ent_frames = Entry(self,
                                width=5,
                                border=2,
                                bg=GOOD,
                                justify=RIGHT,
                                textvariable=self._frames)

        # Get list of available themes
        for idx, theme in enumerate(THEMES):
            self.lbx_theme.insert(idx, theme)

        self.body_arrange()  # Position all widgets in frame

        self.reset()  # Reset all settings to their defaults

        self.set_traces(
        )  # Trace entry variables for validation and event handling

    def body_arrange(self):
        """
        Position widgets in frame
        """

        # Position all widgets in their parent frames
        self.btn_plot.grid(column=0,
                           row=1,
                           ipadx=3,
                           ipady=3,
                           sticky=(W),
                           padx=3,
                           pady=3)
        self.btn_cancel.grid(column=1,
                             row=1,
                             ipadx=3,
                             ipady=3,
                             sticky=(W),
                             padx=3,
                             pady=3)
        self.btn_reset.grid(column=2,
                            row=1,
                            ipadx=3,
                            ipady=3,
                            sticky=(W),
                            padx=3,
                            pady=3)
        self.ent_save.grid(column=0,
                           row=2,
                           columnspan=2,
                           sticky=(W, E),
                           padx=3,
                           pady=3)
        self.btn_save.grid(column=2,
                           row=2,
                           ipadx=3,
                           ipady=3,
                           sticky=(W),
                           padx=3,
                           pady=3)
        self.lbl_auto.grid(column=0, row=3, sticky=(W))
        self.btn_autozoom.grid(column=1,
                               row=3,
                               ipadx=3,
                               ipady=3,
                               sticky=(W),
                               padx=3,
                               pady=3)
        self.btn_autospin.grid(column=2,
                               row=3,
                               ipadx=3,
                               ipady=3,
                               sticky=(W),
                               padx=3,
                               pady=3)
        self.lbl_frames.grid(column=0, row=4, sticky=(W))
        self.ent_frames.grid(column=1, row=4, sticky=(W), padx=3, pady=3)
        self.chk_autosave.grid(column=2, row=4, sticky=(W), padx=3, pady=3)
        self.sep_1.grid(column=0, row=5, columnspan=3, pady=5, sticky=(W, E))
        self.lbl_settype.grid(column=0, row=6, sticky=(W))
        self.spn_settype.grid(column=1,
                              row=6,
                              columnspan=2,
                              sticky=(W, E),
                              padx=3,
                              pady=3)
        self.lbl_zoom.grid(column=0, row=7, sticky=(W))
        self.ent_zoom.grid(column=1,
                           row=7,
                           columnspan=2,
                           sticky=(W, E),
                           padx=3,
                           pady=3)
        self.lbl_zoominc.grid(column=0, row=8, sticky=(W))
        self.ent_zoominc.grid(column=1, row=8, sticky=(W), padx=3, pady=3)
        self.lbl_zx_off.grid(column=0, row=9, sticky=(W))
        self.ent_zx_off.grid(column=1,
                             row=9,
                             columnspan=2,
                             sticky=(W, E),
                             padx=3,
                             pady=3)
        self.lbl_zy_off.grid(column=0, row=10, sticky=(W))
        self.ent_zy_off.grid(column=1,
                             row=10,
                             columnspan=2,
                             sticky=(W, E),
                             padx=3,
                             pady=3)
        self.lbl_cx_off.grid(column=0, row=11, sticky=(W))
        self.ent_cx_off.grid(column=1,
                             row=11,
                             columnspan=2,
                             sticky=(W, E),
                             padx=3,
                             pady=3)
        self.lbl_cy_off.grid(column=0, row=12, sticky=(W))
        self.ent_cy_off.grid(column=1,
                             row=12,
                             columnspan=2,
                             sticky=(W, E),
                             padx=3,
                             pady=3)
        self.lbl_niter.grid(column=0, row=13, sticky=(W))
        self.ent_maxiter.grid(column=1, row=13, sticky=(W), padx=3, pady=3)
        self.chk_autoiter.grid(column=2, row=13, sticky=(W), padx=3, pady=3)
        self.lbl_radius.grid(column=0, row=14, sticky=(W))
        self.ent_radius.grid(column=1, row=14, sticky=(W), padx=3, pady=3)
        self.lbl_exp.grid(column=0, row=15, sticky=(W))
        self.spn_exp.grid(column=1, row=15, sticky=(W), padx=3, pady=3)
        self.lbl_theme.grid(column=0, row=16, sticky=(W))
        self.lbx_theme.grid(column=1,
                            row=16,
                            padx=3,
                            pady=3,
                            columnspan=2,
                            sticky=(N, S, W, E))
        self.scrollbar.grid(column=2, row=16, sticky=(N, S, E))
        self.lbl_shift.grid(column=0, row=17, sticky=(W))
        self.scl_shift.grid(column=1,
                            row=17,
                            columnspan=2,
                            padx=3,
                            pady=3,
                            sticky=(W, E))
        self.lbx_theme.bind("<<ListboxSelect>>", self.get_sel_theme)

    def set_traces(self):
        """
        Set up entry variable traces for validation and event handling
        """

        self._validsettings = True
        self._settype.trace("w", self.val_settings)
        self._zoom.trace("w", self.val_settings)
        self._zx_off.trace("w", self.val_settings)
        self._zy_off.trace("w", self.val_settings)
        self._cx_off.trace("w", self.val_settings)
        self._cy_off.trace("w", self.val_settings)
        self._maxiter.trace("w", self.val_settings)
        self._radius.trace("w", self.val_settings)
        self._exponent.trace("w", self.val_settings)
        self._filename.trace("w", self.val_settings)
        self._frames.trace("w", self.val_settings)
        self._zoominc.trace("w", self.val_settings)

    def val_settings(self, *args, **kwargs):
        """
        Validate all user-entered settings.
        (A personal choice but I find this user experience more intuitive
        than the standard validatecommand method for Entry widgets)
        """

        self._validsettings = True
        self.__app.set_status("")

        if self.is_float(self.ent_zoom.get()) and self._zoom.get() > 0:
            flg = GOOD
        else:
            flg = BAD
        self.flag_entry(self.ent_zoom, flg)

        if self.is_float(self.ent_zx_off.get()):
            flg = GOOD
        else:
            flg = BAD
        self.flag_entry(self.ent_zx_off, flg)

        if self.is_float(self.ent_zy_off.get()):
            flg = GOOD
        else:
            flg = BAD
        self.flag_entry(self.ent_zy_off, flg)

        if self.is_float(self.ent_cx_off.get()):
            flg = GOOD
        else:
            flg = BAD
        self.flag_entry(self.ent_cx_off, flg)

        if self.is_float(self.ent_cy_off.get()):
            flg = GOOD
        else:
            flg = BAD
        self.flag_entry(self.ent_cy_off, flg)

        if self.is_integer(self.ent_maxiter.get()) and self._maxiter.get() > 0:
            flg = GOOD
        else:
            flg = BAD
        self.flag_entry(self.ent_maxiter, flg)

        if self.is_float(self.ent_radius.get()) and self._radius.get() > 0:
            flg = GOOD
        else:
            flg = BAD
        self.flag_entry(self.ent_radius, flg)

        if self.is_integer(self.spn_exp.get()) and self._exponent.get() > 1:
            flg = GOOD
        else:
            flg = BAD
        self.flag_entry(self.spn_exp, flg)

        if self.is_integer(self.ent_frames.get()) and self._frames.get() > 0:
            flg = GOOD
        else:
            flg = BAD
        self.flag_entry(self.ent_frames, flg)

        if self.is_float(self.ent_zoominc.get()) and self._zoominc.get() > 0:
            flg = GOOD
        else:
            flg = BAD
        self.flag_entry(self.ent_zoominc, flg)

        if self.is_filename(self.ent_save.get()):
            flg = GOOD
        else:
            flg = BAD
        self.flag_entry(self.ent_save, flg)

        if self.spn_settype.get() in {"Mandelbrot", "Tricorn", "BurningShip"}:
            self.btn_autospin.config(state=DISABLED)
            self.ent_cx_off.config(state=DISABLED)
            self.ent_cy_off.config(state=DISABLED)
            self._cx_off.set(0)
            self._cy_off.set(0)
            flg = GOOD
        elif self.spn_settype.get() == "Julia":
            self.btn_autospin.config(state=NORMAL)
            self.ent_cx_off.config(state=NORMAL)
            self.ent_cy_off.config(state=NORMAL)
            flg = GOOD
        else:
            flg = BAD
        self.flag_entry(self.spn_settype, flg)

    def flag_entry(self, ent, flag):
        """
        Flag entry field as valid or invalid and set global validity status flag.
        This flag is used throughout to determine whether functions can proceed
        or not.
        """

        ent.config(bg=flag)
        if flag == BAD:
            self._validsettings = False
            self.__app.set_status(VALERROR, "red")

    def is_float(self, flag):
        """
        Validate if entry is a float.
        """

        try:
            float(flag)
            return True
        except ValueError:
            return False

    def is_integer(self, flag):
        """
        Validate if entry is a positive integer.
        """

        try:
            int(flag)
            if int(flag) > 0:
                return True
            return False
        except ValueError:
            return False

    def is_filename(self, flag):
        """
        Validate if entry represents a valid filename using a regexp.
        """

        return match("^[\w\-. ]+$", flag) and flag != ""

    def reset(self):
        """
        Reset settings to defaults.
        """

        self._settype.set("Mandelbrot")
        self._zoom.set(0.75)
        self._zx_off.set(-0.5)
        self._zy_off.set(0.0)
        self._cx_off.set(0.0)
        self._cy_off.set(0.0)
        self._maxiter.set(128)
        self._radius.set(2.0)
        self._exponent.set(2)
        self._frames.set(10)
        self._zoominc.set(2.0)
        self._autoiter.set(1)
        self._autosave.set(0)
        self._theme.set("Default")
        self._filename.set("image0")
        self._shift.set(0)
        self.set_sel_theme()

        self.__app.set_status(SETINITTXT)

    def get_sel_theme(self, *args, **kwargs):
        """
        Get selected theme from listbox and set global variable.
        """

        idx = self.lbx_theme.curselection()
        if idx == "":
            idx = 0
        self._theme.set(self.lbx_theme.get(idx))

    def set_sel_theme(self):
        """
        Lookup index of selected theme and highlight that listbox position.
        NB: this requires 'exportselection=False' option to be set on listbox to
        work properly.
        """

        for idx, theme in enumerate(THEMES):
            if theme == self._theme.get():
                self.lbx_theme.activate(idx)
                self.lbx_theme.see(idx)
                break

    def get_settings(self):
        """
        Return all current settings as a dict.
        """

        if not self._validsettings:
            settings = {"valid": self._validsettings}
            return settings

        settings = {
            "settype": self._settype.get(),
            "zoom": self._zoom.get(),
            "zxoffset": self._zx_off.get(),
            "zyoffset": self._zy_off.get(),
            "cxoffset": self._cx_off.get(),
            "cyoffset": self._cy_off.get(),
            "maxiter": self._maxiter.get(),
            "autoiter": self._autoiter.get(),
            "autosave": self._autosave.get(),
            "radius": self._radius.get(),
            "exponent": self._exponent.get(),
            "theme": self._theme.get(),
            "shift": self._shift.get(),
            "filepath": self._filepath,
            "filename": self._filename.get(),
            "frames": self._frames.get(),
            "zoominc": self._zoominc.get(),
            "valid": self._validsettings,
        }
        return settings

    def update_settings(self, **kwargs):
        """
        Update settings from keyword parms.
        """

        if "settype" in kwargs:
            self._settype.set(kwargs["settype"])
        if "zoom" in kwargs:
            self._zoom.set(kwargs["zoom"])
        if "zxoffset" in kwargs:
            self._zx_off.set(kwargs["zxoffset"])
        if "zyoffset" in kwargs:
            self._zy_off.set(kwargs["zyoffset"])
        if "cxoffset" in kwargs:
            self._cx_off.set(kwargs["cxoffset"])
        if "cyoffset" in kwargs:
            self._cy_off.set(kwargs["cyoffset"])
        if "maxiter" in kwargs:
            self._maxiter.set(kwargs["maxiter"])
        if "autoiter" in kwargs:
            self._autoiter.set(kwargs["autoiter"])
        if "autosave" in kwargs:
            self._autosave.set(kwargs["autosave"])
        if "radius" in kwargs:
            self._radius.set(kwargs["radius"])
        if "exponent" in kwargs:
            self._exponent.set(kwargs["exponent"])
        if "filepath" in kwargs:
            self._filepath.set(kwargs["filepath"])
        if "filename" in kwargs:
            self._filename.set(kwargs["filename"])
        if "frames" in kwargs:
            self._frames.set(kwargs["frames"])
        if "zoominc" in kwargs:
            self._zoominc.set(kwargs["zoominc"])
        if "theme" in kwargs:
            self._theme.set(kwargs["theme"])
            self.set_sel_theme()
        if "shift" in kwargs:
            self._shift.set(kwargs["shift"])

    def set_filepath(self):
        """
        Sets filepath for saved files for the duration of this session.
        """

        default = os.getcwd()  # Default _filepath is current working directory
        if self._filepath is None:
            self._filepath = filedialog.askdirectory(title=SAVETITLE,
                                                     initialdir=default,
                                                     mustexist=True)
            if self._filepath == "":
                self._filepath = None  # User cancelled

        return self._filepath

    def save_image(self):
        """
        Save image as PNG file to selected filepath and automatically increment default
        image name. NB: currently this will overwrite any existing file of the same
        name without warning.
        """

        # Bug out if the settings are invalid
        settings = self.__app.frm_settings.get_settings()
        if not settings["valid"]:
            return

        # Check if image has been created
        image = self.__app.frm_fractal.mandelbrot.get_image()
        if image is None:
            self.__app.set_status(NOIMGERROR, "red")
            return

        # Set _filename and path
        if self.set_filepath() is None:  # User cancelled
            return
        fname = self._filename.get()
        fqname = self._filepath + "/" + fname

        # Save the image along with its metadata
        try:
            # image.write(fqname + ".png", format="png")
            image.save(fqname + ".png", format="png")
            self.save_metadata()
        except OSError:
            self.__app.set_status(SAVEERROR, "red")
            self._filepath = None
            return

        self._image_num += 1
        self._filename.set(self._image_name + str(self._image_num))
        self.__app.set_status(IMGSAVETXT + fqname + ".png", "green")

        # Return focus to image frame
        self.__app.frm_fractal.focus_set()

    def save_metadata(self):
        """
        Save json file containing meta data associated with image,
        allowing it to be imported and reproduced.
        """

        if self._filepath is None:
            if self.set_filepath() is None:  # User cancelled
                return

        fname = self._filename.get()
        fqname = self._filepath + "/" + fname
        filename = fqname + ".json"
        createtime = strftime("%b %d %Y %H:%M:%S %Z", gmtime())

        jsondata = {
            MODULENAME: {
                "filename": fqname + ".png",
                "created": createtime,
                "settype": self._settype.get(),
                "zoom": self._zoom.get(),
                "zoominc": self._zoominc.get(),
                "frames": self._frames.get(),
                "escradius": self._radius.get(),
                "exponent": self._exponent.get(),
                "maxiter": self._maxiter.get(),
                "zxoffset": self._zx_off.get(),
                "zyoffset": self._zy_off.get(),
                "cxoffset": self._cx_off.get(),
                "cyoffset": self._cy_off.get(),
                "theme": self._theme.get(),
                "shift": self._shift.get(),
            }
        }

        try:
            with open(filename, "w") as outfile:
                dump(jsondata, outfile)
        except OSError:
            self.__app.set_status(METASAVEERROR, "red")
            self._filepath = None

        # Return focus to image frame
        self.__app.frm_fractal.focus_set()

    def import_metadata(self):
        """
        Update settings from imported json metadata file.
        """

        # Select and read file
        try:
            default = os.getcwd()
            filepath = filedialog.askopenfilename(
                initialdir=default,
                title=SELTITLE,
                filetypes=(("json files", "*.json"), ("all files", "*.*")),
            )
            if filepath == "":  # User cancelled
                return
            with open(filepath, "r") as infile:
                jsondata = infile.read()
        except OSError:
            self.__app.set_status(OPENFILEERROR, "red")
            return

        # Parse file
        try:

            settings = loads(jsondata).get(MODULENAME)

            # Set plot parameters
            self._settype.set(settings.get("settype", "Mandelbrot"))
            self._zoom.set(settings.get("zoom", 1))
            self._zoominc.set(settings.get("zoominc", 2.0))
            self._frames.set(settings.get("frames", 10))
            self._radius.set(settings.get("escradius", 2.0))
            self._exponent.set(settings.get("exponent", 2))
            self._maxiter.set(settings.get("maxiter", 256))
            self._zx_off.set(settings.get("zxoffset", 0))
            self._zy_off.set(settings.get("zyoffset", 0))
            self._cx_off.set(settings.get("cxoffset", 0))
            self._cy_off.set(settings.get("cyoffset", 0))
            self._theme.set(settings.get("theme", "Default"))
            self._shift.set(settings.get("shift", 0))

        except OSError:
            self.__app.set_status(BADJSONERROR, "red")
            return

        self.set_sel_theme()

        fbase = os.path.basename(filepath)
        filename, fileext = os.path.splitext(fbase)
        self.__app.set_status(
            "Metadata file " + filename + fileext + METAPROMPTTXT, "green")

        # Return focus to image frame
        self.__app.frm_fractal.focus_set()
Esempio n. 22
0
class SearchGUI:

    def update_db(self):
        for user in self.users_dict.values():
            Q = Query()
            users_db.update(user, Q.user_id == user['user_id'])

    def add_user_history(self, index, history):
        self.users_dict[index]['history'].append(history)
        self.update_db()

    def add_user_selection(self, index, selection):
        self.users_dict[index]['selections'].append(selection)
        self.update_db()

    def get_selected_user(self):
        selection = self.users_listbox.curselection()
        if len(selection) > 0:
            index = selection[0]
            return index, self.users_dict[index]
        elif self.results_user is not None:
            return self.results_user, self.users_dict[self.results_user]
        else:
            return None, None

    def selections_release_year_function(self):
        index, user = self.get_selected_user()
        if index is not None and user is not None:
            years = []
            selections = user['selections']
            if len(selections) <= 0:
                return []
            for selection in selections:
                source = selection['_source']
                years.append(source['release_year'])
            return [{
                "exp": {
                    "release_year": {
                        "origin": sum(years) / len(years),
                        "offset": 2,
                        "scale": stdev(years),
                        "decay": 0.5
                    }
                },
                "weight": 1
            }]
        else:
            return []

    def selections_description_function(self):
        index, user = self.get_selected_user()
        if index is not None and user is not None:
            descriptions = []
            selections = user['selections']
            if len(selections) <= 0:
                return []
            for selection in selections:
                source = selection['_source']
                descriptions.append(source['description'])
            desc = ' '.join(descriptions)
            return [{
                "filter": {
                    "match": {
                        "description": {
                            "query": desc,
                            "auto_generate_synonyms_phrase_query": True
                        }
                    }
                },
                "weight": 2
            }]
        else:
            return []

    def history_function(self):
        index, user = self.get_selected_user()
        if index is not None and user is not None:
            if user['user_id'] < 0:
                return []
            queries = []
            history = user['history']
            if len(history) <= 0:
                return []
            for entry in history:
                queries.append(entry['query'])
            tmp = ' '.join(queries)
            return [{
                "filter": {
                    "multi_match": {
                        "query": tmp,
                        "type": "best_fields",
                        "fields": ["title", "description", "cast", "director"]
                    }
                },
                "weight": 1
            }]
        else:
            return []

    def selections_listed_in_functions(self):
        index, user = self.get_selected_user()
        if index is not None and user is not None:
            selections = user['selections']
            if len(selections) <= 0:
                return []
            listed_in = dict()
            nbr_selections = len(selections)
            for selection in selections:
                source = selection['_source']
                categories = source['listed_in'].split(', ')
                for category in categories:
                    if category in listed_in:
                        listed_in[category] = listed_in.get(category) + 1
                    else:
                        listed_in[category] = 1
            return [{
                "filter":
                    {"match_phrase":
                        {
                            "listed_in": c
                        }
                    },
                "weight": (listed_in[c] / nbr_selections) * 4
            } for c in listed_in.keys()]
        else:
            return {}

    def selections_type_functions(self):
        index, user = self.get_selected_user()
        if index is not None and user is not None:
            selections = user['selections']
            if len(selections) <= 0:
                return []
            movies = 0
            tv_shows = 0
            nbr_selections = len(selections)
            for selection in selections:
                source = selection['_source']
                category = source['type']
                if category == 'Movie':
                    movies += 1
                else:
                    tv_shows += 1
            if movies > tv_shows:
                movies_percentage = movies / (movies + tv_shows)
                if movies_percentage > 0.75:
                    return [{
                        "filter": {
                            "match": {
                                "type": 'Movie'
                            }
                        },
                        "weight": movies_percentage * 2
                    }]
            else:
                tv_shows_percentage = tv_shows / (movies + tv_shows)
                if tv_shows_percentage > 0.75:
                    return [{"filter": {"match": {"type": 'TV Show'}}, "weight": tv_shows_percentage * 2}]
        return []

    def search(self, query):
        index, user = self.get_selected_user()
        if index is not None and user is not None:

            functions = self.selections_listed_in_functions() \
                        + self.selections_type_functions() \
                        + self.selections_release_year_function() \
                        + self.selections_description_function() \
                        + self.history_function()
            self.error_message.set("")
            body = get_dsl(query, functions)
            # print(body)
            response = es.search(body=body, index="netflix")
            hits = response['hits']['hits']
            timestamp = datetime.now().timestamp()
            self.add_user_history(index, {'timestamp': timestamp, 'query': query})
            self.update_result(index, hits)
            self.update_shown_profile()
        else:
            self.error_message.set("select a user before searching")

    def update_result(self, index, results):
        nbr_items = self.result_listbox.size()
        self.result_listbox.delete(0, nbr_items)
        self.results_user = index
        self.results.clear()
        for index, result in enumerate(results):
            source = result['_source']
            score = float(result['_score'])
            self.results.insert(index, result)
            # self.result_listbox.insert(index, "%.3f \t %s \t %s \t %s"%(score, str(source['release_year']), source['title'], source['listed_in']))
            self.result_listbox.insert(index, "%s \t %s \t\t %s \t %s \t %s"% (source['release_year'], source['type'],
                                                                                source['title'], source['description'],
                                                                                     source['listed_in']))
            if index < 20:
                print("%s \t %s \t %s \t %s \t %s" % (
                    source['title'], source['type'], source['release_year'], source['listed_in'],
                    source['description']))

    def update_shown_profile(self):
        index, user = self.get_selected_user()
        if index is not None and user is not None:
            nbr_history = self.history_listbox.size()
            self.history_listbox.delete(0, nbr_history)
            for index, result in enumerate(user['history']):
                self.history_listbox.insert(index, "%s \t\t %s" % (result['timestamp'], result['query']))

            nbr_selections = self.selections_listbox.size()
            self.selections_listbox.delete(0, nbr_selections)
            for index, result in enumerate(user['selections']):
                source = result['_source']
                self.selections_listbox.insert(index, "%s \t %s \t\t %s \t %s \t %s"% (source['release_year'], source['type'],
                                                                                source['title'], source['description'],
                                                                                     source['listed_in']))

    def select(self):
        selection = self.result_listbox.curselection()
        user_index = self.results_user
        if len(selection) > 0 and user_index is not None:
            item = self.results[selection[0]]
            self.add_user_selection(user_index, item)
            self.update_shown_profile()
        else:
            self.error_message.set("perform a search first")

    def update_users(self):
        users = users_db.all()
        nbr_items = self.users_listbox.size()
        self.users_listbox.delete(0, nbr_items)
        for index, result in enumerate(users):
            self.users_dict[index] = result
            self.users_listbox.insert(index, "%s \t\t %s" % (result['user_id'], result['name']))

    def __init__(self, master):
        self.master = master
        master.title("Search engine")

        self.users_dict = dict()

        self.results_user = None
        self.results = list()

        self.users_listbox = Listbox(self.master, selectmode="SINGLE", width=200)
        self.users_listbox.grid(column=0, row=0, columnspan=10)

        self.update_users()
        self.users_listbox.activate(0)

        self.query = StringVar()
        self.entry = Entry(self.master, textvariable=self.query, width=160)
        self.entry.grid(column=0, row=1, columnspan=10)

        Button(self.master, command=lambda: self.search(self.query.get()), text="Search", width=20).grid(column=0,
                                                                                                         row=2,
                                                                                                         columnspan=10)

        Label(self.master, text="Results").grid(column=0, row=3, columnspan=10)
        self.result_listbox = Listbox(self.master, selectmode="SINGLE", width=200)
        self.result_listbox.grid(column=0, row=4, columnspan=10)

        Button(self.master, command=lambda: self.select(), text="Select", width=40).grid(column=0,
                                                                                         row=5,
                                                                                         columnspan=10)

        Label(self.master, text="History").grid(column=0, row=6, columnspan=5)
        self.history_listbox = Listbox(self.master, selectmode="SINGLE", width=100)
        self.history_listbox.grid(column=0, row=7, columnspan=5)

        Label(self.master, text="Selections").grid(column=5, row=6, columnspan=5)
        self.selections_listbox = Listbox(self.master, selectmode="SINGLE", width=100)
        self.selections_listbox.grid(column=5, row=7, columnspan=5)

        self.error_message = StringVar()
        Label(self.master, textvariable=self.error_message, fg="red").grid(column=0, row=8, columnspan=10)
Esempio n. 23
0
class MainView(Frame):
    def __init__(self, root, model: Model):
        super().__init__(root)
        root.columnconfigure(0, weight=1)
        root.rowconfigure(0, weight=1)
        self.model = model
        self.__init_components()
        self.grid(sticky='nsew')
        self.__bind_action_events()

    def __init_components(self):
        # Instanciar widgets
        self.panel_form = Labelframe(self, text='Tarea')
        self.panel_tasks = Labelframe(self, text='Tareas por hacer')
        self.panel_complete_tasks = Labelframe(self, text='Tareas completas')

        self.label_name = Label(self.panel_form, text='Nombre:')
        self.label_description = Label(self.panel_form, text='Descripción:')
        self.entry_name = Entry(self.panel_form)
        self.entry_description = Entry(self.panel_form)

        self.btn_modify_task = Button(self.panel_form,
                                      text='Editar tarea',
                                      state=DISABLED,
                                      command=self.__modify_task)
        self.btn_new_task = Button(self.panel_form,
                                   text='Nueva tarea',
                                   command=self.__new_task)
        self.btn_delete_task = Button(self.panel_form,
                                      text='Eliminar tarea',
                                      state=DISABLED,
                                      command=self.__delete_task)
        self.btn_clear_form = Button(self.panel_form,
                                     text='Limpiar campos',
                                     command=self.__clear_form)
        self.btn_complete_task = Button(self.panel_form,
                                        text='Completar tarea',
                                        state=DISABLED,
                                        command=self.__complete_task)

        self.scroll_tasks = Scrollbar(self.panel_tasks, orient=VERTICAL)
        self.scroll_complete_tasks = Scrollbar(self.panel_complete_tasks,
                                               orient=VERTICAL)
        self.list_tasks = Listbox(self.panel_tasks,
                                  selectmode=SINGLE,
                                  height=10,
                                  width=25,
                                  yscrollcommand=self.scroll_tasks.set)
        self.list_complete_tasks = Listbox(
            self.panel_complete_tasks,
            selectmode=SINGLE,
            height=10,
            width=25,
            yscrollcommand=self.scroll_complete_tasks.set)

        # Posicionar los widgets
        # Panel de formulario de tareas
        self.panel_form.pack(fill='both',
                             expand='yes',
                             padx=10,
                             pady=5,
                             ipadx=5,
                             ipady=5)
        self.panel_form.columnconfigure(0, weight=1)
        self.panel_form.rowconfigure(0, weight=1)

        self.label_name.grid(row=0, column=0, padx=5, sticky='w')
        self.entry_name.grid(row=0, column=1, padx=5, sticky='w')
        self.label_description.grid(row=1,
                                    column=0,
                                    padx=5,
                                    pady=5,
                                    sticky='w')
        self.entry_description.grid(row=1,
                                    column=1,
                                    padx=5,
                                    pady=10,
                                    sticky='w')

        # Botones
        self.btn_modify_task.grid(row=2, column=0, ipady=4, sticky='we')
        self.btn_new_task.grid(row=2, column=1, ipady=4, sticky='we')
        self.btn_delete_task.grid(row=3, column=0, ipady=4, sticky='we')
        self.btn_clear_form.grid(row=3, column=1, ipady=4, sticky='we')
        self.btn_complete_task.grid(row=4,
                                    column=0,
                                    columnspan=2,
                                    ipady=4,
                                    sticky='we')

        config_list = {
            'fill': 'both',
            'expand': 'yes',
            'padx': 10,
            'pady': 5,
            'ipadx': 5,
            'ipady': 5
        }

        # Panel de lista de tareas pendientes
        self.panel_tasks.pack(config_list)
        self.panel_tasks.columnconfigure(0, weight=20)
        self.panel_tasks.columnconfigure(1, weight=1)
        self.list_tasks.grid(row=0, column=0, sticky='we')
        self.scroll_tasks.configure(command=self.list_tasks.yview)
        self.scroll_tasks.grid(row=0, column=1, sticky='ns')

        # Panel de lista de tareas completas
        self.panel_complete_tasks.pack(config_list)
        self.panel_complete_tasks.columnconfigure(0, weight=20)
        self.panel_complete_tasks.columnconfigure(1, weight=1)
        self.list_complete_tasks.grid(row=0, column=0, sticky='we')
        self.scroll_complete_tasks.configure(
            command=self.list_complete_tasks.yview)
        self.scroll_complete_tasks.grid(row=0, column=1, sticky='ns')

    def __bind_action_events(self):
        # self.btn_new_task.bind('<Button>', self.__new_task)
        # self.btn_modify_task.bind('<Button>', self.__modify_task)
        # self.btn_delete_task.bind('<Button>', self.__delete_task)
        # self.btn_complete_task.bind('<Button>', self.__complete_task)

        self.list_tasks.bind('<<ListboxSelect>>', self.__select_task)

    def __new_task(self):
        log_info('Botón {} pulsado'.format(
            self.btn_new_task.config('text')[-1]))

        name_value = self.entry_name.get()
        description_value = self.entry_description.get()

        if name_value:
            self.model.new_task(name_value, description_value)
            self.update_tables()
        else:
            messagebox.showwarning('AVISO', 'Complete el campo de nombre')

    def __modify_task(self):
        index = self.__selected_task()

        name_value = self.entry_name.get()
        description_value = self.entry_description.get()

        if index != -1:
            task = self.model.get_task(self.model.tasks[index].get_id())
            complete = self.model.modify_task(task.get_id(), name_value,
                                              description_value)

            if complete:
                messagebox.showinfo('Aviso',
                                    'Tarea: {} editada'.format(task.name))

        self.update_tables()

    def __delete_task(self):
        index = self.__selected_task()

        if index != -1:
            task = self.model.get_task(self.model.tasks[index].get_id())
            self.model.delete_task(task.get_id())
            self.update_tables()

    def __complete_task(self):
        index = self.__selected_task()

        if index != -1:
            task = self.model.get_task(self.model.tasks[index].get_id())
            task.close_todo()
            complete = self.model.modify_task(task.get_id(), task.name,
                                              task.description)

            if complete:
                messagebox.showinfo('Aviso',
                                    'Tarea: {} completa'.format(task.name))

        self.update_tables()

    def __clear_form(self):
        self.clear_form()
        self.__change_state_btn(DISABLED)

    def __select_task(self, event):
        self.clear_form()
        index = self.__selected_task()

        if index != -1:
            task = self.model.get_task(self.model.tasks[index].get_id())
            self.set_form(task)
            self.__change_state_btn(NORMAL)

    def __change_state_btn(self, state: str):
        self.btn_new_task.config(
            state=NORMAL if state == DISABLED else DISABLED)
        self.btn_delete_task.config(state=state)
        self.btn_modify_task.config(state=state)
        self.btn_complete_task.config(state=state)

    def __selected_task(self):
        try:
            return self.list_tasks.curselection()[0]
        except IndexError:
            self.__change_state_btn(DISABLED)
            self.list_complete_tasks.activate(-1)
            return -1

    def update_tables(self):
        log_info('Actualizando tablas')
        self.list_tasks.delete(0, END)
        self.list_complete_tasks.delete(0, END)

        for index in range(len(self.model.tasks)):
            self.list_tasks.insert(index, self.model.tasks[index].name)

        for index in range(len(self.model.complete_tasks)):
            self.list_complete_tasks.insert(
                index, self.model.complete_tasks[index].name)

    def clear_form(self):
        self.entry_name.delete(0, END)
        self.entry_description.delete(0, END)

    def set_form(self, task: Task):
        if task is not None:
            self.entry_name.insert(0, task.name)
            self.entry_description.insert(0, task.description)
        else:
            log_error('No se encontró la tarea seleccionada')
class AutocompleteEntry(Entry):
    def __init__(self, autocompleteList, *args, **kwargs):

        # Listbox length
        if 'listboxLength' in kwargs:
            self.listboxLength = kwargs['listboxLength']
            del kwargs['listboxLength']
        else:
            self.listboxLength = 8

        # Custom matches function
        if 'matchesFunction' in kwargs:
            self.matchesFunction = kwargs['matchesFunction']
            del kwargs['matchesFunction']
        else:

            def matches(fieldValue, acListEntry):
                pattern = re.compile('.*' + re.escape(fieldValue) + '.*',
                                     re.IGNORECASE)
                return re.match(pattern, acListEntry)

            self.matchesFunction = matches

        Entry.__init__(self, *args, **kwargs)
        self.focus()

        self.autocompleteList = autocompleteList

        self.var = self["textvariable"]
        if self.var == '':
            self.var = self["textvariable"] = StringVar()

        self.var.trace('w', self.changed)
        self.bind("<Right>", self.selection)
        self.bind("<Up>", self.moveUp)
        self.bind("<Down>", self.moveDown)

        self.listboxUp = False

    def changed(self, name, index, mode):
        if self.var.get() == '':
            if self.listboxUp:
                self.listbox.destroy()
                self.listboxUp = False
        else:
            words = self.comparison()
            if words:
                if not self.listboxUp:
                    self.listbox = Listbox(width=self["width"],
                                           height=self.listboxLength)
                    self.listbox.bind("<Button-1>", self.selection)
                    self.listbox.bind("<Right>", self.selection)
                    self.listbox.place(x=self.winfo_x(),
                                       y=self.winfo_y() + self.winfo_height())
                    self.listboxUp = True

                self.listbox.delete(0, END)
                for w in words:
                    self.listbox.insert(END, w)
            else:
                if self.listboxUp:
                    self.listbox.destroy()
                    self.listboxUp = False

    def selection(self, event):
        if self.listboxUp:
            self.var.set(self.listbox.get(ACTIVE))
            self.listbox.destroy()
            self.listboxUp = False
            self.icursor(END)

    def moveUp(self, event):
        if self.listboxUp:
            if self.listbox.curselection() == ():
                index = '0'
            else:
                index = self.listbox.curselection()[0]

            if index != '0':
                self.listbox.selection_clear(first=index)
                index = str(int(index) - 1)

                self.listbox.see(index)  # Scroll!
                self.listbox.selection_set(first=index)
                self.listbox.activate(index)

    def moveDown(self, event):
        if self.listboxUp:
            if self.listbox.curselection() == ():
                index = '0'
            else:
                index = self.listbox.curselection()[0]

            if index != END:
                self.listbox.selection_clear(first=index)
                index = str(int(index) + 1)

                self.listbox.see(index)  # Scroll!
                self.listbox.selection_set(first=index)
                self.listbox.activate(index)

    def comparison(self):
        return [
            w for w in self.autocompleteList
            if self.matchesFunction(self.var.get(), w)
        ]
class Combobox_Autocomplete(Entry, object):
    def __init__(self, master, list_of_items=None, autocomplete_function=None,
                 listbox_width=None, listbox_height=7, ignorecase_match=False,
                 startswith_match=True, vscrollbar=True, hscrollbar=True, **kwargs):
        if hasattr(self, "autocomplete_function"):
            if autocomplete_function is not None:
                raise ValueError(
                    "Combobox_Autocomplete subclass has 'autocomplete_function' implemented")
        else:
            if autocomplete_function is not None:
                self.autocomplete_function = autocomplete_function
            else:
                if list_of_items is None:
                    raise ValueError(
                        "If not given complete function, list_of_items can't be 'None'")
                elif ignorecase_match:
                    if startswith_match:
                        def matches_function(entry_data, item):
                            return item.startswith(entry_data)
                    else:
                        def matches_function(entry_data, item):
                            return item in entry_data
                    self.autocomplete_function = lambda entry_data: [
                        item for item in self.list_of_items if matches_function(entry_data, item)]
                else:
                    if startswith_match:
                        def matches_function(escaped_entry_data, item):
                            if re.match(escaped_entry_data, item, re.IGNORECASE):
                                return True
                            else:
                                return False
                    else:
                        def matches_function(escaped_entry_data, item):
                            if re.search(escaped_entry_data, item, re.IGNORECASE):
                                return True
                            else:
                                return False
                    def autocomplete_function2(entry_data):
                        escaped_entry_data = re.escape(entry_data)
                        return [item for item in self.list_of_items if matches_function(escaped_entry_data, item)]
                    self.autocomplete_function = autocomplete_function2
        self._listbox_height = int(listbox_height)
        self._listbox_width = listbox_width
        self.list_of_items = list_of_items
        self._use_vscrollbar = vscrollbar
        self._use_hscrollbar = hscrollbar
        kwargs.setdefault("background", "white")
        if "textvariable" in kwargs:
            self._entry_var = kwargs["textvariable"]
        else:
            self._entry_var = kwargs["textvariable"] = StringVar()
        Entry.__init__(self, master, **kwargs)
        self._trace_id = self._entry_var.trace('w', self._on_change_entry_var)
        self._listbox = None
        self.bind("<Tab>", self._on_tab)
        self.bind("<Up>", self._previous)
        self.bind("<Down>", self._next)
        self.bind('<Control-n>', self._next)
        self.bind('<Control-p>', self._previous)
        self.bind("<Return>", self._update_entry_from_listbox)
        self.bind("<Escape>", lambda event: self.unpost_listbox())
    def _on_tab(self, event):
        self.post_listbox()
        return "break"
    def _on_change_entry_var(self, name, index, mode):
        entry_data = self._entry_var.get()
        if entry_data == '':
            self.unpost_listbox()
            self.focus()
        else:
            values = self.autocomplete_function(entry_data)
            if values:
                if self._listbox is None:
                    self._build_listbox(values)
                else:
                    self._listbox.delete(0, END)
                    height = min(self._listbox_height, len(values))
                    self._listbox.configure(height=height)
                    for item in values:
                        self._listbox.insert(END, item)
            else:
                self.unpost_listbox()
                self.focus()
    def _build_listbox(self, values):
        listbox_frame = Frame()
        self._listbox = Listbox(listbox_frame, background="white",
                                selectmode=SINGLE, activestyle="none",
                                exportselection=False)
        self._listbox.grid(row=0, column=0, sticky=N+E+W+S)
        self._listbox.bind("<ButtonRelease-1>",
                           self._update_entry_from_listbox)
        self._listbox.bind("<Return>", self._update_entry_from_listbox)
        self._listbox.bind("<Escape>", lambda event: self.unpost_listbox())
        self._listbox.bind('<Control-n>', self._next)
        self._listbox.bind('<Control-p>', self._previous)
        if self._use_vscrollbar:
            vbar = Scrollbar(listbox_frame, orient=VERTICAL,
                             command=self._listbox.yview)
            vbar.grid(row=0, column=1, sticky=N+S)
            self._listbox.configure(
                yscrollcommand=lambda f, l: autoscroll(vbar, f, l))
        elif self._use_hscrollbar:
            hbar = Scrollbar(listbox_frame, orient=HORIZONTAL,
                             command=self._listbox.xview)
            hbar.grid(row=1, column=0, sticky=E+W)
            self._listbox.configure(
                xscrollcommand=lambda f, l: autoscroll(hbar, f, l))
            listbox_frame.grid_columnconfigure(0, weight=1)
            listbox_frame.grid_rowconfigure(0, weight=1)
            x = -self.cget("borderwidth") - self.cget("highlightthickness")
            y = self.winfo_height()-self.cget("borderwidth") - \
            self.cget("highlightthickness")
        elif self._listbox_width:
            width = self._listbox_width
        else:
            width = self.winfo_width()
        listbox_frame.place(in_=self, x=x, y=y, width=width)
        height = min(self._listbox_height, len(values))
        self._listbox.configure(height=height)
        for item in values:
            self._listbox.insert(END, item)
    def post_listbox(self):
        if self._listbox is not None:
            return
        entry_data = self._entry_var.get()
        if entry_data == '':
            return
        values = self.autocomplete_function(entry_data)
        if values:
            self._build_listbox(values)
    def unpost_listbox(self):
        if self._listbox is not None:
            self._listbox.master.destroy()
            self._listbox = None
    def get_value(self):
        return self._entry_var.get()
    def set_value(self, text, close_dialog=False):
        self._set_var(text)
        if close_dialog:
            self.unpost_listbox()
        self.icursor(END)
        self.xview_moveto(1.0)
    def _set_var(self, text):
        self._entry_var.trace_vdelete("w", self._trace_id)
        self._entry_var.set(text)
        self._trace_id = self._entry_var.trace('w', self._on_change_entry_var)
    def _update_entry_from_listbox(self, event):
        if self._listbox is not None:
            current_selection = self._listbox.curselection()
            if current_selection:
                text = self._listbox.get(current_selection)
                self._set_var(text)
            self._listbox.master.destroy()
            self._listbox = None
            self.focus()
            self.icursor(END)
            self.xview_moveto(1.0)
        return "break"
    def _previous(self, event):
        if self._listbox is not None:
            current_selection = self._listbox.curselection()
            if len(current_selection) == 0:
                self._listbox.selection_set(0)
                self._listbox.activate(0)
            else:
                index = int(current_selection[0])
                self._listbox.selection_clear(index)
                if index == 0:
                    index = END
                else:
                    index -= 1
                self._listbox.see(index)
                self._listbox.selection_set(first=index)
                self._listbox.activate(index)
        return "break"
    def _next(self, event):
        if self._listbox is not None:
            current_selection = self._listbox.curselection()
            if len(current_selection) == 0:
                self._listbox.selection_set(0)
                self._listbox.activate(0)
            else:
                index = int(current_selection[0])
                self._listbox.selection_clear(index)
                if index == self._listbox.size() - 1:
                    index = 0
                else:
                    index += 1
                self._listbox.see(index)
                self._listbox.selection_set(index)
                self._listbox.activate(index)
        return "break"
Esempio n. 26
0
class MyGUI:
    def __init__(self, master):
        # Create the main window widget.

        self.sleep = True
        self.DATA = []
        self.colors = {
            'white': '#FFFFFF',
            'blue': '#2B547E',
            'black': '#000000',
            'red': '#FF3346',
            'green': '#306754',
            'grey': '#E5E4E2',
            'hex': '#9bcbff',
            'button_color': '#C0C0C0'
        }

        self.check = 0
        self.chosenSong = ''
        self.chosenId = 0
        self.POP = []
        self.CHILL = []
        self.DANCE = []
        self.check_pop = IntVar()
        self.check_chill = IntVar()
        self.check_dance = IntVar()
        self.master = master
        self.master.title('Music Player')
        self.master.configure(bg=self.colors['hex'])
        self.master.geometry('850x600')
        self.f_name = ''
        self.imagePath = tk.PhotoImage(file='Logo.png')
        self.rewindImg = tk.PhotoImage(file='rewind.png')
        self.playImage = tk.PhotoImage(file='play.png')
        self.pauseImage = tk.PhotoImage(file='pause.png')
        self.nextImage = tk.PhotoImage(file='unpause.png')
        self.image = tk.Label(master, image=self.imagePath, borderwidth=0, bg=self.colors['hex'])

        # widgets
        self.file_name_label = Label(
            master, fg=self.colors['black'], bg=self.colors['button_color'],
            text='Enter a name for your file: ',
            width=57, font='Helvetica 10 bold')

        self.pop = Checkbutton(
            master, fg=self.colors['black'], bg=self.colors['hex'],
            text='POP', highlightbackground=self.colors['black'],
            variable=self.check_pop)

        self.chill = Checkbutton(
            master, fg=self.colors['black'], bg=self.colors['hex'],
            text='CHILL', highlightbackground=self.colors['black'],
            variable=self.check_chill)

        self.dance = Checkbutton(
            master, fg=self.colors['black'], bg=self.colors['hex'],
            text='DANCE', highlightbackground=self.colors['black'],
            variable=self.check_dance)

        self.file_name = Text(
            master, fg=self.colors['blue'],
            bg=self.colors['grey'], width=57, height=1)

        self.explorer_label1 = Button(
            master, fg=self.colors['grey'], bg=self.colors['blue'],
            width=30, text='Download Tracks/Show Genres', command=self.download)

        self.explorer = Listbox(
            master, fg=self.colors['blue'], bg=self.colors['grey'],
            width=70, height=15, highlightcolor=self.colors['green'])

        self.explorer2 = Listbox(
            master, fg=self.colors['blue'], bg=self.colors['grey'],
            width=70, height=15, highlightcolor=self.colors['green'])

        self.search_btn = Button(
            master, fg=self.colors['grey'], bg=self.colors['blue'],
            width=30, text='Search', command=self.showGenre)

        self.delete_button = Button(
            master, fg=self.colors['white'],
            bg=self.colors['red'], text='DELETE', width=31,
            highlightbackground=self.colors['black'], command=self.delete)

        self.stop_button = Button(
            master, fg=self.colors['grey'], image=self.pauseImage,
            bg=self.colors['green'], text='PAUSE', width=80, font='Helvetica 10 bold',
            highlightbackground=self.colors['black'], command=self.stop)

        self.unpause_button = Button(
            master, fg=self.colors['grey'], image=self.playImage,
            bg=self.colors['green'], text='PAUSE', width=80, font='Helvetica 10 bold',
            highlightbackground=self.colors['black'], command=self.unpause)

        self.play_button = Button(
            master, image=self.playImage, fg=self.colors['grey'],
            bg=self.colors['green'], text='PLAY', width=80,
            highlightbackground=self.colors['black'], command=self.play)

        self.status_label = Label(
            master, fg=self.colors['grey'], bg=self.colors['black'],
            width=60, text='Hello')
        self.clear_button = Button(
            master, fg=self.colors['grey'],
            bg=self.colors['green'], text='CLEAR',
            width=15, highlightbackground=self.colors['black'], command=self.clear)

        self.rewind_button = Button(
            master, image=self.rewindImg, fg=self.colors['grey'],
            bg=self.colors['green'], text='REWIND', width=80,
            highlightbackground=self.colors['black'], command=self.rewind)

        self.next_button = Button(
            master, image=self.nextImage, fg=self.colors['grey'],
            bg=self.colors['green'], text='REWIND', width=80,
            highlightbackground=self.colors['black'], command=self.nextSelection)

        # grid
        self.image.grid(row=0, sticky=W + E)
        self.explorer.grid(row=7, sticky=W, padx=20)
        self.explorer2.grid(row=7, sticky=E, padx=20)
        self.play_button.grid(row=8, sticky=W, padx=100, pady=20)
        self.delete_button.grid(row=8, sticky=E, padx=20, pady=20)
        self.search_btn.grid(row=6, sticky=E, padx=20)
        self.status_label.grid(row=13, sticky=E + W, padx=20)
        self.rewind_button.grid(row=8, sticky=W, padx=20, pady=20)
        self.next_button.grid(row=8, sticky=W, padx=180, pady=20)
        self.file_name.grid(row=2, sticky=E, padx=20)
        self.displayAllData()

        if self.checkingConnection():
            self.file_name_label.grid(row=2, sticky=W, padx=20)
            self.file_name.grid(row=2, sticky=E, padx=20)
            self.pop.grid(row=3, sticky=W, padx=100, pady=5)
            self.chill.grid(row=3, pady=5)
            self.dance.grid(row=3, sticky=E, padx=100, pady=5)
            self.explorer_label1.grid(row=6, sticky=W, padx=20)
            self.clear_button.grid(row=8, sticky=W, padx=350, pady=20)

    # search_for_Genre
    def showGenre(self):
        keywords = self.file_name.get('1.0', END).strip()
        if self.check_pop.get() == 1 or keywords == 'POP':
            self.explorer.delete(0, 'end')
            self.getAllPopSongs()
        elif self.check_chill.get() == 1 or keywords == 'CHILL':
            self.explorer.delete(0, 'end')
            self.getAllChillSongs()
        elif self.check_dance.get() == 1 or keywords == 'DANCE':
            self.explorer.delete(0, 'end')
            self.getAllDanceSongs()

        elif keywords == 'ALL':
            self.explorer.delete(0, 'end')
            self.displayAllData()
        else:
            self.explorer.delete(0, 'end')
            self.search(keywords)

    # download

    def download(self):
        self.POP = []
        self.CHILL = []
        self.DANCE = []
        self.f_name = self.file_name.get('1.0', END).strip()
        options = {
            'default_search': 'ytsearch1',
            'quiet': True
        }
        ydl = YoutubeDL(options)
        search_result = ydl.extract_info(self.f_name, download=False)
        songs = search_result["entries"]
        self.downloadSong(songs[0]['id'])
        obj = {
            'ID': songs[0]['id'],
            'Title': self.f_name,
            'Creator': songs[0]['creator'],
            'Duration': songs[0]['duration'],
            'Alternative Title': songs[0]['alt_title']
        }
        if self.check_dance.get() == 1:
            self.DANCE.append(obj)
        elif self.check_chill.get() == 1:
            self.CHILL.append(obj)
        elif self.check_pop.get() == 1:
            self.POP.append(obj)
        self.saveData(obj)
        self.showGenre()

    def play(self):
        self.check = self.check + 1
        try:
            self.clear()
            self.displayIn4()
            self.chosenId = ''
        except Exception as FormatError:
            self.explorer2.insert("0", 'Format Error')
        chosenSong = self.explorer.get(ACTIVE).strip()
        self.chosenId = self.searchReturnId(chosenSong)
        os.environ['PYGAME_HIDE_SUPPORT_PROMPT'] = "hide"
        mixer.init()
        mixer.music.load("D:\\MusicPlayer\\musicPlayer\\musicdownloads\\" + self.chosenId + ".mp3")
        if self.check == 1:
            self.play_button.grid_forget()
            self.stop_button.grid(row=8, sticky=W, padx=100, pady=20)
            mixer.music.play()

    def rewind(self):
        mixer.music.rewind()

    def stop(self):

        self.check = self.check + 1
        if self.check % 2 == 0:
            self.unpause_button.grid(row=8, sticky=W, padx=100, pady=20)
            mixer.music.pause()
            self.stop_button.grid_forget()

    def unpause(self):

        self.check = self.check + 1
        if self.check % 2 != 0:
            self.stop_button.grid(row=8, sticky=W, padx=100, pady=20)
            self.unpause_button.grid_forget()
            mixer.music.unpause()

    def delete(self):
        deleting = self.explorer.get(ACTIVE).strip()
        dataPop = []
        dataChill = []
        dataDance = []
        allData = []
        a = {}
        allData = self.getAlldata()
        for item in range(len(allData)):
            if allData[item]['Title'] == deleting:
                a = allData[item]
        allData.remove(a)
        with open('data.json', 'w', encoding="utf8") as data_file:
            jsonData = json.dumps(allData)
            data_file.write(jsonData)
        openPop = open('pop.json')
        dataPop = json.load(openPop)
        openPop.close()
        tempK = {}
        for k in (dataPop):
            if k == a:
                tempK = k
                dataPop.remove(tempK)
        with open('pop.json', 'w', encoding="utf8") as pop_file:
            popData = json.dumps(dataPop)
            pop_file.write(popData)
        openChill = open('chill.json')
        dataChill = json.load(openChill)
        openChill.close()
        tempC = {}
        for c in (dataChill):
            if c == a:
                tempC = c
                dataChill.remove(tempC)
        with open('chill.json', 'w', encoding="utf8") as chill_file:
            chillData = json.dumps(dataChill)
            chill_file.write(chillData)
        openDance = open('dance.json')
        dataDance = json.load(openDance)
        openDance.close()
        tempD = {}
        for d in (dataDance):
            if d == a:
                tempD = d
                dataChill.remove(tempD)
        with open('dance.json', 'w', encoding="utf8") as dance_file:
            danceData = json.dumps(dataDance)
            dance_file.write(danceData)

    def saveData(self, obj):
        self.DATA.append(obj)
        data = []
        input_data = open('data.json')
        data = json.load(input_data)
        data = data + self.DATA
        input_data.close()
        with open('data.json', 'w', encoding="utf8") as data_file:
            jsonData = json.dumps(data)
            data_file.write(jsonData)

    def sort(self, arr):
        n = len(arr)
        # Traverse through all array elements
        for i in range(n):
            # Last i elements are already in place
            for j in range(0, n - i - 1):
                # traverse the array from 0 to n-i-1
                # Swap if the element found is greater
                # than the next element
                if arr[j]['Title'] > arr[j + 1]['Title']:
                    arr[j], arr[j + 1] = arr[j + 1], arr[j]

    def clear(self):
        self.file_name.delete('1.0', END)
        self.check_pop.set(0)
        self.check_dance.set(0)
        self.check_chill.set(0)
        self.explorer2.delete('0', END)

    def search(self, name):
        dataSearching = self.getAlldata()
        l = 0
        r = len(dataSearching) - 1
        self.sort(dataSearching)
        while l <= r:
            mid = int(l + (r - l) / 2);
            # Check if x is present at mid
            if dataSearching[mid]['Title'] == name:
                self.explorer.insert(0, dataSearching[mid]['Title'])
                break
            # If x is greater, ignore left half
            elif dataSearching[mid]['Title'] < name:
                l = mid +1
            # If x is smaller, ignore right half
            else:
                r = mid - 1

    def checkingConnection(self):
        try:
            urlopen('https://www.google.com', timeout=1)
            return True
        except urllib.error.URLError as Error:
            print(Error)
            return False

    def searchReturnId(self, name):
        dataSearchingID = self.getAlldata()
        l = 0
        r = len(dataSearchingID) - 1
        self.sort(dataSearchingID)
        while l <= r:
            mid = (l + (r - l) // 2);
            # Check if x is present at mid
            if dataSearchingID[mid]['Title'] == name:
                return dataSearchingID[mid]["ID"]
            # If x is greater, ignore left half
            elif dataSearchingID[mid]['Title'] < name:
                l = mid + 1
            # If x is smaller, ignore right half
            else:
                r = mid - 1

    def displayAllData(self):
        allData = self.getAlldata()
        self.sort(allData)
        for a in range(len(allData)):
            self.explorer.insert(len(allData), allData[a]['Title'])

    def downloadSong(self, id):
        options = {
            # specify the path to download
            'outtmpl': 'musicdownloads/%(id)s',
            'postprocessors': [{
                'key': 'FFmpegExtractAudio',  # Tách lấy audio
                'preferredcodec': 'mp3',  # Format ưu tiên là mp3
                'preferredquality': '192',  # Chất lượng bitrate
            }]
        }
        ydl = YoutubeDL(options)
        # download() có thể truyền vào 1 str hoặc 1 list
        ydl.download(["https://www.youtube.com/watch?v={}".format(id)])

    def displayIn4(self):
        string = self.explorer.get(ACTIVE).strip()
        data = self.getAlldata()
        obj = {}
        for x in (data):
            if x['Title'] == string:
                obj = x
                break
        values = obj.values()
        for k, v in obj.items():
            self.explorer2.insert(len(values), k + ": " + str(v))

    def getAlldata(self):
        allData = []
        input_AllData = open('data.json')
        allData = json.load(input_AllData)
        input_AllData.close()

        return allData

    def nextSelection(self):
        if self.sleep:
            sleep(2)
        self.check = 0
        selection_indices = self.explorer.curselection()
        # default next selection is the beginning
        next_selection = 0
        # make sure at least one item is selected
        if len(selection_indices) > 0:
            # Get the last selection, remember they are strings for some reason
            # so convert to int
            last_selection = int(selection_indices[-1])
            # clear current selections
            self.explorer.selection_clear(selection_indices)
            # Make sure we're not at the last item
            if last_selection < self.explorer.size() - 1:
                next_selection = last_selection + 1
            self.explorer.activate(next_selection)
            self.explorer.selection_set(next_selection)
            self.play()

    def getAllChillSongs(self):
        chillLst = []
        input_chill = open('chill.json')
        chillLst = json.load(input_chill)
        chillLst = chillLst + self.CHILL
        input_chill.close()
        with open('chill.json', 'w', encoding="utf8") as chill_file:
            jsonChill = json.dumps(chillLst)
            chill_file.write(jsonChill)
            self.sort(chillLst)
        for y in range(len(chillLst)):
            self.explorer.insert(len(chillLst), chillLst[y]['Title'])

    def getAllDanceSongs(self):
        danceLst = []
        input_dance = open('dance.json')
        danceLst = json.load(input_dance)
        danceLst = danceLst + self.DANCE
        input_dance.close()
        with open('dance.json', 'w', encoding="utf8") as dance_file:
            jsonDance = json.dumps(danceLst)
            dance_file.write(jsonDance)
        self.sort(danceLst)
        for d in range(len(danceLst)):
            self.explorer.insert(len(danceLst), danceLst[d]['Title'])

    def getAllPopSongs(self):
        popLst = []
        input_pop = open('pop.json')
        popLst = json.load(input_pop)
        danceLst = popLst + self.DANCE
        input_pop.close()
        with open('dance.json', 'w', encoding="utf8") as dance_file:
            jsonDance = json.dumps(popLst)
            dance_file.write(jsonDance)
        self.sort(popLst)
        for d in range(len(popLst)):
            self.explorer.insert(len(popLst), popLst[d]['Title'])