示例#1
0
    def _sortPlaylist(self, btn: TkButtonImgHoverBg, atr: str):
        #If click on another sort btn
        if btn != self.__btn_sort_active[0]:
            self.__btn_sort_active[0].set_img(0)  #Previous btn to normal
            if btn == self.btn_sorttitle:
                btn.set_img(
                    1)  #Set title btn to up, the others are set automatically
            self.__btn_sort_active = [btn, 1]  #Status is updated
            self.playlist.sortBy(atr, False)
            config.playlist["orderby"] = [atr, 1]

        #If click on the same sort btn
        else:
            #If the btn was in up
            if self.__btn_sort_active[1] == 1:
                if btn == self.btn_sorttitle:
                    btn.set_img(
                        2
                    )  #Set title btn to down, the others are set automatically
                self.__btn_sort_active[1] = 2  #Status is updated
                self.playlist.sortBy(atr, True)
                config.playlist["orderby"] = [atr, 2]

            #If the btn was in down
            elif self.__btn_sort_active[1] == 2:
                self.btn_sorttitle.set_img(
                    1
                )  #Set title btn to down, the others are set automatically
                self.__btn_sort_active = [self.btn_sorttitle,
                                          1]  #Status is updated
                self.playlist.sortBy("title", False)
                config.playlist["orderby"] = ["title", 1]
示例#2
0
    def __init__(self, playlist: Playlist, event, *args, **kwargs):

        self.playlist = playlist
        self.playlist_handler = playlist.master.playlist_control.playlist_handler_set

        song_id = int(playlist.identify_row(event.y))
        self.song = self.playlist.getSongById(song_id)

        coord = playlist.bbox(song_id)
        self.__coord_y = coord[1]

        colors = self.__colorItemTV()

        #highlightthickness=1 -> With outline
        super().__init__(self.playlist,
                         width=coord[2] - ROW_HEIGHT,
                         height=coord[3],
                         background=colors[0],
                         highlightthickness=1,
                         *args,
                         **kwargs)
        self.place(x=25, y=coord[1])

        #___

        self.entry_edit_song = Entry(self,
                                     width=45,
                                     background=colors[0],
                                     foreground=colors[1],
                                     borderwidth=0)
        self.entry_edit_song.grid(row=0, column=0, padx=(7, 7))

        self.entry_edit_song.insert(0, self.song.name)
        self.entry_edit_song.icursor(5)
        self.entry_edit_song.focus()

        #___

        self.separator = Separator(self, orient="vertical")
        self.separator.grid(row=0, column=1, sticky="ns", pady=2)

        #___

        self.btn_rename = TkButtonImgHoverBg(
            self,
            command=self._rename,
            imgs=(PhotoImage(data=b64img.btn_TV_edit_rename), ),
            bg=colors[0],
            bg_on_hover=config.colors["BTN_BG_HOVER"])
        self.btn_rename.grid(row=0, column=2)

        #___

        self.btn_move = TkButtonImgHoverBg(
            self,
            command=self._move,
            imgs=(PhotoImage(data=b64img.btn_TV_edit_move), ),
            bg=colors[0],
            bg_on_hover=config.colors["BTN_BG_HOVER"])
        self.btn_move.grid(row=0, column=3, padx=2)

        #___

        self.btn_delete = TkButtonImgHoverBg(
            self,
            command=self._del,
            imgs=(PhotoImage(data=b64img.btn_TV_edit_delete), ),
            bg=colors[0],
            bg_on_hover=config.colors["BTN_BG_HOVER"])
        self.btn_delete.grid(row=0, column=4)

        #___

        #Destroy when click in TV
        self.playlist.bind_all("<Button-1>", self._destroyLabel)
        #Destroy when scroll in TV
        self.playlist.bind("<MouseWheel>", self._destroyLabel)
        #Destroy when right click to open new label in TV
        self.playlist.bind("<Button-3>", self._destroyLabel)
示例#3
0
class LabelEditSong(Frame):
    def __init__(self, playlist: Playlist, event, *args, **kwargs):

        self.playlist = playlist
        self.playlist_handler = playlist.master.playlist_control.playlist_handler_set

        song_id = int(playlist.identify_row(event.y))
        self.song = self.playlist.getSongById(song_id)

        coord = playlist.bbox(song_id)
        self.__coord_y = coord[1]

        colors = self.__colorItemTV()

        #highlightthickness=1 -> With outline
        super().__init__(self.playlist,
                         width=coord[2] - ROW_HEIGHT,
                         height=coord[3],
                         background=colors[0],
                         highlightthickness=1,
                         *args,
                         **kwargs)
        self.place(x=25, y=coord[1])

        #___

        self.entry_edit_song = Entry(self,
                                     width=45,
                                     background=colors[0],
                                     foreground=colors[1],
                                     borderwidth=0)
        self.entry_edit_song.grid(row=0, column=0, padx=(7, 7))

        self.entry_edit_song.insert(0, self.song.name)
        self.entry_edit_song.icursor(5)
        self.entry_edit_song.focus()

        #___

        self.separator = Separator(self, orient="vertical")
        self.separator.grid(row=0, column=1, sticky="ns", pady=2)

        #___

        self.btn_rename = TkButtonImgHoverBg(
            self,
            command=self._rename,
            imgs=(PhotoImage(data=b64img.btn_TV_edit_rename), ),
            bg=colors[0],
            bg_on_hover=config.colors["BTN_BG_HOVER"])
        self.btn_rename.grid(row=0, column=2)

        #___

        self.btn_move = TkButtonImgHoverBg(
            self,
            command=self._move,
            imgs=(PhotoImage(data=b64img.btn_TV_edit_move), ),
            bg=colors[0],
            bg_on_hover=config.colors["BTN_BG_HOVER"])
        self.btn_move.grid(row=0, column=3, padx=2)

        #___

        self.btn_delete = TkButtonImgHoverBg(
            self,
            command=self._del,
            imgs=(PhotoImage(data=b64img.btn_TV_edit_delete), ),
            bg=colors[0],
            bg_on_hover=config.colors["BTN_BG_HOVER"])
        self.btn_delete.grid(row=0, column=4)

        #___

        #Destroy when click in TV
        self.playlist.bind_all("<Button-1>", self._destroyLabel)
        #Destroy when scroll in TV
        self.playlist.bind("<MouseWheel>", self._destroyLabel)
        #Destroy when right click to open new label in TV
        self.playlist.bind("<Button-3>", self._destroyLabel)

    #______________________________________________________________________________________

    def _destroyLabel(self, event=None):
        #Do nothing if left click in LabelEditSong
        if event and str(event.widget).startswith(str(self)):
            return

        #New label if it is the right click
        if event and event.num == 3:
            LabelEditSong(self.playlist, event)
        #Unbind all and bind right btn by default
        else:
            self.playlist.unbind("<Button-1>")
            self.playlist.bind("<MouseWheel>", self.playlist._motionItem)
            self.playlist.bind(
                "<Button-3>",
                lambda event: LabelEditSong(self.playlist, event))
        self.destroy()

    #___

    def __isTheSongPlaying(self) -> bool:
        return self.playlist.getSongPlayingId() == self.song.id

    def __colorItemTV(self) -> Tuple[str, str]:
        #Is the focused itemTV
        if self.playlist.focus() and int(
                self.playlist.focus()) == self.song.id:
            return (config.colors["TV_BG_SELECT"],
                    config.colors["TV_FG_SELECT"])

        #Is not the focused itemTV but is playing
        elif self.__isTheSongPlaying():
            return (config.colors["TV_BG"], config.colors["TV_FG_PLAYING"])

        #Is just hovered
        else:
            return (config.colors["TV_BG_HOVER"], config.colors["TV_FG_HOVER"])

    #___

    def __checkImpediments(self, msg_error: str) -> bool:
        if self.__isTheSongPlaying():
            messagebox.showerror(
                msg_error, _("Action not allowed with a song that is playing"))

        elif not os.path.exists(config.playlist["path"]):
            messagebox.showwarning(msg_error,
                                   _("The folder does not to exist"))
            self.playlist_handler.delPlaylist(config.general["playlist"])

        elif not os.path.exists(self.song.path):
            messagebox.showerror(msg_error, _("The song does not to exist"))
            self.playlist - self.song

        else:
            return False
        return True

    #___

    def _rename(self):
        song_name_new = self.entry_edit_song.get()
        if validEntryText(song_name_new, text_original=self.song.name):

            if not self.__checkImpediments(_("Rename failed")):
                song_path_new = os.path.join(
                    config.playlist["path"],
                    song_name_new + self.song.extension)
                try:
                    os.rename(self.song.path, song_path_new)
                    #Refresh in TV
                    self.song.path = song_path_new
                    self.playlist.move(self.song,
                                       self.playlist.index(self.song.id))
                except:
                    messagebox.showerror(_("Rename failed"),
                                         _("Unknown action not allowed"))

        self._destroyLabel()

    def _move(self):
        tk_main_w = Widget.nametowidget(self, '.')
        coord_x = tk_main_w.winfo_x() + 250
        coord_y = tk_main_w.winfo_y() + self.__coord_y + 150

        self.menu = Menu(self,
                         bg=config.colors["BG"],
                         activebackground=config.colors["TV_BG_HOVER"],
                         activeforeground=config.colors["FG"],
                         tearoff=False)

        for playlist in config.user_config["Playlists"]:
            if playlist != config.general["playlist"]:
                #https://stackoverflow.com/questions/11723217/python-lambda-doesnt-remember-argument-in-for-loop
                func_get_set_playlist = lambda playlist=playlist: self.__move(
                    playlist)
                self.menu.add_command(label=playlist,
                                      command=func_get_set_playlist)

        self.menu.tk_popup(coord_x, coord_y)

    def __move(self, playlist: str):
        if not self.__checkImpediments(_("Move failed")):
            playlist_path = config.user_config["Playlists"][playlist]["path"]

            if not os.path.exists(playlist_path):
                messagebox.showwarning(_("Move failed"),
                                       _("Destination folder does not exist"))
                self.playlist_handler.delPlaylist(playlist, in_tv=False)

            else:
                try:
                    shutil.copy2(src=self.song.path, dst=playlist_path)
                except:
                    messagebox.showerror(_("Move failed"),
                                         _("Unknown action not allowed"))

        self._destroyLabel()

    def _del(self):
        if not self.__checkImpediments(_("Delete failed")):
            try:
                os.remove(self.song.path)
                self.playlist - self.song
            except:
                messagebox.showerror(_("Delete failed"),
                                     _("Unknown action not allowed"))

        self._destroyLabel()
示例#4
0
    def __init__(self, w: PlaylistControl, *args, **kwargs):

        self.playlist = w.playlist
        self.playlist_handler_set = w.playlist_handler_set

        super().__init__(w,
                         title="Playlist Control Panel",
                         geometry="200x205",
                         bg_bar=config.colors["BG_WIDGET_GREY"],
                         bg=config.colors["BG"],
                         *args,
                         **kwargs)

        #___

        self.entry_playlist = Entry(self.w)
        self.entry_playlist.grid(row=0, column=0, padx=(5, 0), pady=(5, 0))

        self.entry_playlist.insert(0, config.general["playlist"])

        #___

        self.btn_save_playlist_name = TkButtonImgHoverBg(
            self.w,
            command=self._renamePlaylist,
            imgs=(PhotoImage(data=b64img.btn_TV_edit_rename), ),
            bg=config.colors["BG"],
            bg_on_hover=config.colors["BTN_BG_HOVER"])
        self.btn_save_playlist_name.grid(row=0,
                                         column=1,
                                         sticky="nsew",
                                         pady=(5, 0))

        #___

        self.btn_delete_playlist = TkButtonImgHoverBg(
            self.w,
            command=self._delPlaylist,
            imgs=(PhotoImage(data=b64img.btn_TV_edit_delete), ),
            bg=config.colors["BG"],
            bg_on_hover=config.colors["BTN_BG_HOVER"])
        self.btn_delete_playlist.grid(row=0,
                                      column=2,
                                      sticky="nsew",
                                      padx=(0, 5),
                                      pady=(5, 0))

        #___

        self.frame_path = TkFrameInfo(self.w,
                                      text=_("Path:"),
                                      lbl_width=5,
                                      info_width=25,
                                      info_bg=config.colors["BG"])
        self.frame_path.grid(row=1,
                             column=0,
                             columnspan=3,
                             padx=5,
                             pady=(10, 5))

        self.frame_path.insert(config.playlist["path"])

        #___

        self.frame_size = TkFrameInfo(self.w,
                                      text=_("Size on disk:"),
                                      lbl_width=18,
                                      info_width=10,
                                      info_bg=config.colors["BG"])
        self.frame_size.grid(row=2, column=0, columnspan=3, padx=5)

        playlist_size_MB = sum(
            map(lambda song: os.path.getsize(song.path),
                self.playlist.getAllSongs())) // (1024 * 1024)
        self.frame_size.insert(f"{playlist_size_MB} MB")

        #___

        self.frame_num = TkFrameInfo(self.w,
                                     text=_("Number of songs:"),
                                     lbl_width=18,
                                     info_width=10,
                                     info_bg=config.colors["BG"])
        self.frame_num.grid(row=3,
                            column=0,
                            columnspan=3,
                            padx=5,
                            pady=(5, 10))

        playlist_len = len(self.playlist.getAllSongs())
        self.frame_num.insert(playlist_len)

        #___

        self.btn_add_songs = TkButtonTextHoverFg(
            self.w,
            command=self._addSongs,
            text=_("----- Add songs -----"),
            bg=config.colors["BG"],
            fg=config.colors["FG"],
            fg_on_hover="blue")
        self.btn_add_songs.grid(row=4,
                                column=0,
                                columnspan=3,
                                sticky="nsew",
                                padx=5)

        #___

        self.btn_open_folder = TkButtonImgHoverBg(
            self.w,
            command=lambda: os.system(
                config.CMD_TO_OPEN_EXPLORER.format(config.playlist["path"])),
            imgs=(PhotoImage(data=b64img.btn_openfolder), ),
            bg=config.colors["BG"],
            bg_on_hover=config.colors["BTN_BG_HOVER"])
        self.btn_open_folder.grid(row=5,
                                  column=0,
                                  columnspan=3,
                                  sticky="nsew",
                                  padx=5,
                                  pady=10)
示例#5
0
class TopLevelPlaylistEdit(TkPopup):
    def __init__(self, w: PlaylistControl, *args, **kwargs):

        self.playlist = w.playlist
        self.playlist_handler_set = w.playlist_handler_set

        super().__init__(w,
                         title="Playlist Control Panel",
                         geometry="200x205",
                         bg_bar=config.colors["BG_WIDGET_GREY"],
                         bg=config.colors["BG"],
                         *args,
                         **kwargs)

        #___

        self.entry_playlist = Entry(self.w)
        self.entry_playlist.grid(row=0, column=0, padx=(5, 0), pady=(5, 0))

        self.entry_playlist.insert(0, config.general["playlist"])

        #___

        self.btn_save_playlist_name = TkButtonImgHoverBg(
            self.w,
            command=self._renamePlaylist,
            imgs=(PhotoImage(data=b64img.btn_TV_edit_rename), ),
            bg=config.colors["BG"],
            bg_on_hover=config.colors["BTN_BG_HOVER"])
        self.btn_save_playlist_name.grid(row=0,
                                         column=1,
                                         sticky="nsew",
                                         pady=(5, 0))

        #___

        self.btn_delete_playlist = TkButtonImgHoverBg(
            self.w,
            command=self._delPlaylist,
            imgs=(PhotoImage(data=b64img.btn_TV_edit_delete), ),
            bg=config.colors["BG"],
            bg_on_hover=config.colors["BTN_BG_HOVER"])
        self.btn_delete_playlist.grid(row=0,
                                      column=2,
                                      sticky="nsew",
                                      padx=(0, 5),
                                      pady=(5, 0))

        #___

        self.frame_path = TkFrameInfo(self.w,
                                      text=_("Path:"),
                                      lbl_width=5,
                                      info_width=25,
                                      info_bg=config.colors["BG"])
        self.frame_path.grid(row=1,
                             column=0,
                             columnspan=3,
                             padx=5,
                             pady=(10, 5))

        self.frame_path.insert(config.playlist["path"])

        #___

        self.frame_size = TkFrameInfo(self.w,
                                      text=_("Size on disk:"),
                                      lbl_width=18,
                                      info_width=10,
                                      info_bg=config.colors["BG"])
        self.frame_size.grid(row=2, column=0, columnspan=3, padx=5)

        playlist_size_MB = sum(
            map(lambda song: os.path.getsize(song.path),
                self.playlist.getAllSongs())) // (1024 * 1024)
        self.frame_size.insert(f"{playlist_size_MB} MB")

        #___

        self.frame_num = TkFrameInfo(self.w,
                                     text=_("Number of songs:"),
                                     lbl_width=18,
                                     info_width=10,
                                     info_bg=config.colors["BG"])
        self.frame_num.grid(row=3,
                            column=0,
                            columnspan=3,
                            padx=5,
                            pady=(5, 10))

        playlist_len = len(self.playlist.getAllSongs())
        self.frame_num.insert(playlist_len)

        #___

        self.btn_add_songs = TkButtonTextHoverFg(
            self.w,
            command=self._addSongs,
            text=_("----- Add songs -----"),
            bg=config.colors["BG"],
            fg=config.colors["FG"],
            fg_on_hover="blue")
        self.btn_add_songs.grid(row=4,
                                column=0,
                                columnspan=3,
                                sticky="nsew",
                                padx=5)

        #___

        self.btn_open_folder = TkButtonImgHoverBg(
            self.w,
            command=lambda: os.system(
                config.CMD_TO_OPEN_EXPLORER.format(config.playlist["path"])),
            imgs=(PhotoImage(data=b64img.btn_openfolder), ),
            bg=config.colors["BG"],
            bg_on_hover=config.colors["BTN_BG_HOVER"])
        self.btn_open_folder.grid(row=5,
                                  column=0,
                                  columnspan=3,
                                  sticky="nsew",
                                  padx=5,
                                  pady=10)

    #__________________________________________________

    def _delPlaylist(self):
        self.bell()
        state_delete = messagebox.askyesnocancel(
            _("Delete"),
            _("Do you also want to delete the playlist from the path?"))

        if state_delete is None: return

        self.playlist_handler_set.delPlaylist(config.general["playlist"])

        if state_delete:
            shutil.rmtree(config.playlist["path"])

        self.destroy()

    def _renamePlaylist(self):
        playlist_name_new = self.entry_playlist.get()
        if validEntryText(playlist_name_new,
                          text_original=config.general["playlist"]):
            try:
                playlist_path_new = os.path.join(
                    os.path.dirname(config.playlist["path"]),
                    playlist_name_new)
                os.rename(config.playlist["path"], playlist_path_new)

                self.playlist_handler_set.renamePlaylist(
                    playlist_name_new, playlist_path_new)
                self.frame_path.insert(config.playlist["path"])
            except:
                messagebox.showerror(_("Rename failed"),
                                     _("Unknown action not allowed"))

    def _addSongs(self):
        songs_path = filedialog.askopenfilenames(title=_("Select"))
        if not songs_path: return

        for song_path in songs_path:
            try:
                song_name: str = os.path.basename(song_path)

                if not song_name.endswith(config.SUPPORTED_SONG_FORMATS):
                    messagebox.showerror(_("Load failed"),
                                         _("Sound format not supported "))
                    continue

                song_path_new = os.path.join(config.playlist["path"],
                                             song_name)
                shutil.copy2(src=song_path, dst=config.playlist["path"])

                self.playlist + Song(song_path_new)
                self.frame_size.insert(
                    int(self.frame_size.get()[:-3]) +
                    (os.path.getsize(song_path_new) // (1024 * 1024)))
                self.frame_num.insert(int(self.frame_num.get()) + 1)
            except:
                messagebox.showerror(_("Load failed"),
                                     _("Unknown action not allowed"))
示例#6
0
    def __init__(self, w, *args, **kwargs):
        self.EMPTY_SEARCH_TEXT = _(
            "Search song...")  #After defined _ by gettext

        self.playlist = w.playlist

        super().__init__(w, *args, **kwargs)

        #___

        self.playlist_handler_edit = TkButtonImgHoverBg(
            self,
            command=lambda: TopLevelPlaylistEdit(self)
            if config.general["playlist"] != "" else None,
            imgs=(PhotoImage(data=b64img.btn_configplaylist), ),
            bg=config.colors["BG"],
            bg_on_hover=config.colors["BTN_BG_HOVER"])
        self.playlist_handler_edit.grid(row=0, column=0, sticky="nsew")

        #___

        self.playlist_handler_set = PlaylistHandlerSet(self)
        self.playlist_handler_set.grid(row=0,
                                       column=1,
                                       sticky="nsew",
                                       padx=(5, 8),
                                       pady=5)

        #___

        #When the text is changed, the search function will be called
        self.state_entry_search = StringVar()
        self.state_entry_search.trace('w', self._search)

        self.entry_search = Entry(self,
                                  width=15,
                                  textvariable=self.state_entry_search)
        self.entry_search.grid(row=0, column=2, sticky="nsew", pady=5)

        self.entry_search.insert(0, self.EMPTY_SEARCH_TEXT)
        self.entry_search.bind("<FocusIn>", self._entryFocusEnter)
        self.entry_search.bind("<FocusOut>", self._entryFocusLeave)

        #___

        self.btn_search = TkButtonImgHoverBg(
            self,
            command=self._entryClear,
            imgs=(PhotoImage(data=b64img.btn_quitsearch), ),
            bg=config.colors["BG"],
            bg_on_hover=config.colors["BTN_BG_HOVER"])
        self.btn_search.grid(row=0,
                             column=3,
                             sticky="nsew",
                             padx=(0, 5),
                             pady=5)

        #___

        self.btn_sorttitle = TkButtonImgHoverBg(
            self,
            command=lambda: self._sortPlaylist(self.btn_sorttitle, "title"),
            imgs=(PhotoImage(data=b64img.btn_sorttitle),
                  PhotoImage(data=b64img.btn_sorttitle_up),
                  PhotoImage(data=b64img.btn_sorttitle_down)),
            bg=config.colors["BG"],
            bg_on_hover=config.colors["BTN_BG_HOVER"])
        self.btn_sorttitle.grid(row=0, column=4, sticky="nsew")

        #___

        self.btn_sortdate = TkButtonImgHoverBg(
            self,
            command=lambda: self._sortPlaylist(self.btn_sortdate, "date"),
            imgs=(PhotoImage(data=b64img.btn_sortdate),
                  PhotoImage(data=b64img.btn_sortdate_up),
                  PhotoImage(data=b64img.btn_sortdate_down)),
            bg=config.colors["BG"],
            bg_on_hover=config.colors["BTN_BG_HOVER"],
            change_img_on_click=True)
        self.btn_sortdate.grid(row=0, column=5, sticky="nsew")

        #___

        self.btn_sorttime = TkButtonImgHoverBg(
            self,
            command=lambda: self._sortPlaylist(self.btn_sorttime, "time"),
            imgs=(PhotoImage(data=b64img.btn_sorttime),
                  PhotoImage(data=b64img.btn_sorttime_up),
                  PhotoImage(data=b64img.btn_sorttime_down)),
            bg=config.colors["BG"],
            bg_on_hover=config.colors["BTN_BG_HOVER"],
            change_img_on_click=True)
        self.btn_sorttime.grid(row=0, column=6, sticky="nsew")

        #___

        self.btn_sorttitle.set_img(1)
        self.__btn_sort_active: Tuple[TkButtonImgHoverBg,
                                      str] = [self.btn_sorttitle, 1]
示例#7
0
class PlaylistControl(Frame):
    def __init__(self, w, *args, **kwargs):
        self.EMPTY_SEARCH_TEXT = _(
            "Search song...")  #After defined _ by gettext

        self.playlist = w.playlist

        super().__init__(w, *args, **kwargs)

        #___

        self.playlist_handler_edit = TkButtonImgHoverBg(
            self,
            command=lambda: TopLevelPlaylistEdit(self)
            if config.general["playlist"] != "" else None,
            imgs=(PhotoImage(data=b64img.btn_configplaylist), ),
            bg=config.colors["BG"],
            bg_on_hover=config.colors["BTN_BG_HOVER"])
        self.playlist_handler_edit.grid(row=0, column=0, sticky="nsew")

        #___

        self.playlist_handler_set = PlaylistHandlerSet(self)
        self.playlist_handler_set.grid(row=0,
                                       column=1,
                                       sticky="nsew",
                                       padx=(5, 8),
                                       pady=5)

        #___

        #When the text is changed, the search function will be called
        self.state_entry_search = StringVar()
        self.state_entry_search.trace('w', self._search)

        self.entry_search = Entry(self,
                                  width=15,
                                  textvariable=self.state_entry_search)
        self.entry_search.grid(row=0, column=2, sticky="nsew", pady=5)

        self.entry_search.insert(0, self.EMPTY_SEARCH_TEXT)
        self.entry_search.bind("<FocusIn>", self._entryFocusEnter)
        self.entry_search.bind("<FocusOut>", self._entryFocusLeave)

        #___

        self.btn_search = TkButtonImgHoverBg(
            self,
            command=self._entryClear,
            imgs=(PhotoImage(data=b64img.btn_quitsearch), ),
            bg=config.colors["BG"],
            bg_on_hover=config.colors["BTN_BG_HOVER"])
        self.btn_search.grid(row=0,
                             column=3,
                             sticky="nsew",
                             padx=(0, 5),
                             pady=5)

        #___

        self.btn_sorttitle = TkButtonImgHoverBg(
            self,
            command=lambda: self._sortPlaylist(self.btn_sorttitle, "title"),
            imgs=(PhotoImage(data=b64img.btn_sorttitle),
                  PhotoImage(data=b64img.btn_sorttitle_up),
                  PhotoImage(data=b64img.btn_sorttitle_down)),
            bg=config.colors["BG"],
            bg_on_hover=config.colors["BTN_BG_HOVER"])
        self.btn_sorttitle.grid(row=0, column=4, sticky="nsew")

        #___

        self.btn_sortdate = TkButtonImgHoverBg(
            self,
            command=lambda: self._sortPlaylist(self.btn_sortdate, "date"),
            imgs=(PhotoImage(data=b64img.btn_sortdate),
                  PhotoImage(data=b64img.btn_sortdate_up),
                  PhotoImage(data=b64img.btn_sortdate_down)),
            bg=config.colors["BG"],
            bg_on_hover=config.colors["BTN_BG_HOVER"],
            change_img_on_click=True)
        self.btn_sortdate.grid(row=0, column=5, sticky="nsew")

        #___

        self.btn_sorttime = TkButtonImgHoverBg(
            self,
            command=lambda: self._sortPlaylist(self.btn_sorttime, "time"),
            imgs=(PhotoImage(data=b64img.btn_sorttime),
                  PhotoImage(data=b64img.btn_sorttime_up),
                  PhotoImage(data=b64img.btn_sorttime_down)),
            bg=config.colors["BG"],
            bg_on_hover=config.colors["BTN_BG_HOVER"],
            change_img_on_click=True)
        self.btn_sorttime.grid(row=0, column=6, sticky="nsew")

        #___

        self.btn_sorttitle.set_img(1)
        self.__btn_sort_active: Tuple[TkButtonImgHoverBg,
                                      str] = [self.btn_sorttitle, 1]

    #__________________________________________________

    def _entryFocusEnter(self, _event):
        #Delete default text
        if self.entry_search.get() == self.EMPTY_SEARCH_TEXT:
            self.entry_search.delete(0, "end")

    def _entryFocusLeave(self, _event):
        #Delete text and insert default text if is invalid text
        if not validEntryText(self.entry_search.get()):
            self.entry_search.delete(0, "end")
            self.entry_search.insert(0, self.EMPTY_SEARCH_TEXT)
            config.playlist["filter"] = ""

    def _entryClear(self):
        #Delete text and insert default text if there is no focus
        if self.entry_search.get() != self.EMPTY_SEARCH_TEXT:
            self.entry_search.delete(0, "end")
            config.playlist["filter"] = ""
            if self.focus_get() != self.entry_search:
                self.entry_search.insert(0, self.EMPTY_SEARCH_TEXT)

    def _search(self, *_event):
        song_name = self.state_entry_search.get()
        if song_name != self.EMPTY_SEARCH_TEXT:
            self.playlist.filterName(song_name)
            config.playlist["filter"] = song_name

    def setSearch(self, song_name: str):
        if validEntryText(song_name):
            self.entry_search.delete(0, "end")
            self.entry_search.insert(0, song_name)
        else:
            self._entryClear()

    #___

    def _sortPlaylist(self, btn: TkButtonImgHoverBg, atr: str):
        #If click on another sort btn
        if btn != self.__btn_sort_active[0]:
            self.__btn_sort_active[0].set_img(0)  #Previous btn to normal
            if btn == self.btn_sorttitle:
                btn.set_img(
                    1)  #Set title btn to up, the others are set automatically
            self.__btn_sort_active = [btn, 1]  #Status is updated
            self.playlist.sortBy(atr, False)
            config.playlist["orderby"] = [atr, 1]

        #If click on the same sort btn
        else:
            #If the btn was in up
            if self.__btn_sort_active[1] == 1:
                if btn == self.btn_sorttitle:
                    btn.set_img(
                        2
                    )  #Set title btn to down, the others are set automatically
                self.__btn_sort_active[1] = 2  #Status is updated
                self.playlist.sortBy(atr, True)
                config.playlist["orderby"] = [atr, 2]

            #If the btn was in down
            elif self.__btn_sort_active[1] == 2:
                self.btn_sorttitle.set_img(
                    1
                )  #Set title btn to down, the others are set automatically
                self.__btn_sort_active = [self.btn_sorttitle,
                                          1]  #Status is updated
                self.playlist.sortBy("title", False)
                config.playlist["orderby"] = ["title", 1]

    def sortPlaylistForced(self, atr: str, order: int):
        if atr == "date":
            self.btn_sortdate.set_img(order)
            self.btn_sorttitle.set_img(0)
            self.btn_sorttime.set_img(0)
            self.__btn_sort_active[0] = self.btn_sortdate

        elif atr == "time":
            self.btn_sorttime.set_img(order)
            self.btn_sorttitle.set_img(0)
            self.btn_sortdate.set_img(0)
            self.__btn_sort_active[0] = self.btn_sorttime

        else:
            self.btn_sorttitle.set_img(order)
            self.btn_sortdate.set_img(0)
            self.btn_sorttime.set_img(0)
            self.__btn_sort_active[0] = self.btn_sorttitle

        self.__btn_sort_active[1] = order
        self.playlist.sortBy(atr, order -
                             1)  #0(False) if order==1 | 1(True) if order==2