Exemple #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()
Exemple #2
0
    def initUI(self):
        self.parent.title("TVstream manager")
        self.stytle = ttk.Style()
        self.pack(fill=BOTH, expand=1)        
        self.columnconfigure(0, weight=1, pad=2)
        self.columnconfigure(2, weight=1, pad=2)
        self.columnconfigure(4,  pad=7)
        #self.rowconfigure(3, weight=1)
        #self.rowconfigure(4, weight=1, pad=7)

        lbll = Label(self, text="Lingua")
        lbll.grid(row=0,column=0,sticky=W, pady=4, padx=5)

        lble = Label(self, text="Emittenti")
        lble.grid(row=0,column=2,sticky=W, pady=1, padx=5)

        global langlst
        scrollang = Scrollbar(self)
        langlst = Listbox(self,font='Arial 9',yscrollcommand=scrollang.set)
        scrollang.config(command = langlst.yview)
        
        for i in lingue:
            langlst.insert(END, i)
        langlst.focus_set()
        
        langlst.bind("<<ListboxSelect>>", self.onSelectLang)  
        langlst.grid(row=1,column=0, columnspan=2, padx=6,sticky=E+W+S+N)
        scrollang.grid(row=1,column=1, sticky=E+S+N)

        global emitlst
        scrollemit = Scrollbar(self)
        emitlst = Listbox(self,font='Arial 9',yscrollcommand=scrollemit.set)
        scrollemit.config(command = emitlst.yview )
        emitlst.bind("<<ListboxSelect>>", self.onSelectEmittente)
        emitlst.grid(row=1,column=2, columnspan=2, padx=5,sticky=E+W+S+N)
        scrollemit.grid(row=1,column=3,sticky=E+S+N)

        lbltxt = Label(self, text="Output log")
        lbltxt.grid(row=2,column=0, columnspan=3, sticky=W, pady=4, padx=5)
        
        global area
        area = Text(self,height=10,font='Arial 9')
        area.grid(row=3, column=0, columnspan=5, rowspan=1, padx=5, sticky=E+W+S+N)
        scrolltxt = Scrollbar(self)
        scrolltxt.config(command = area.yview)
        scrolltxt.grid(row=3,column=4, columnspan=1, rowspan=1, sticky=E+N+S)
        
        play = Button(self, text='Play', command=self.playUrl,
               bg='gray', fg='black')
        play.grid(row=1,column=4,padx=4,sticky=E+W)
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)
Exemple #4
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()
Exemple #5
0
class PiScreen(tkinter.Frame):
    def __init__(self, master: 'tkinter.Tk'):
        global client, status, theme
        # host = '192.168.1.120'
        host = 'localhost'
        if sys.platform.startswith('linux'):
            host = 'localhost'
        client.connect(host, 6600)
        tkinter.Frame.__init__(self, master, padx=0, pady=0)
        self.pack()
        self.place(height=240, width=320, x=0, y=0)
        status = client.status()
        self.volume = int(status["volume"])

        self.screen_data = {
            "1": [
                "QUEUE", "PLAYLISTS", "LIBRARY", "SETUP", "CLEAR PLAYLIST",
                "RANDOM " + status['random'], "REPEAT " + status['repeat'],
                "SINGLE " + status['single'], "CONSUME " + status['consume']
            ],
            "1.1": {
                "ACTION": "QUEUE"
            },
            "1.2": {
                "ACTION": "PLAYLISTS"
            },
            "1.3": ["ARTISTS", "ALBUMS", "GENRES"],
            "1.3.1": {
                "ACTION": "ARTISTS"
            },
            "1.3.2": {
                "ACTION": "ALBUMS"
            },
            "1.3.3": {
                "ACTION": "GENRES"
            },
            "1.4": ["UPDATE LIBRARY", "THEMES"],
            "1.4.1": {
                "ACTION": "UPDATE_LIBRARY"
            },
            "1.4.2": {
                "ACTION": "THEMES"
            },
            "1.5": {
                "ACTION": "CLEAR"
            },
            "1.6": {
                "ACTION": "RANDOM"
            },
            "1.7": {
                "ACTION": "REPEAT"
            },
            "1.8": {
                "ACTION": "SINGLE"
            },
            "1.9": {
                "ACTION": "CONSUME"
            }
        }

        self.screen_format = {"1.Q": "SONG", "1.P": "PLAYLIST"}

        self.current_song_var = tkinter.StringVar()
        self.footer_text_var = tkinter.StringVar()

        # Screens
        self.playerScreen = Canvas(self,
                                   width=320,
                                   height=240,
                                   bg=theme['PLAYER']['background'],
                                   borderwidth=0,
                                   highlightthickness=0)

        self.menuScreen = Frame(self, width=320, height=240, bg="white")
        self.menuScreen.place(height=240, width=320, x=0, y=0)

        # Menu Screen items
        self.headerFrame = Frame(self.menuScreen,
                                 width=320,
                                 height=20,
                                 bg=theme['HEADER']['background'])
        self.headerFrame.pack(side=tkinter.TOP, fill=X)

        self.currentSongLabel = Label(self.headerFrame,
                                      font=(theme['HEADER']['font'], 12,
                                            'bold'),
                                      bg=theme['HEADER']['background'],
                                      foreground=theme['HEADER']['foreground'],
                                      textvariable=self.current_song_var,
                                      justify=tkinter.LEFT,
                                      anchor=tkinter.W)
        self.currentSongLabel.place(x=0,
                                    y=0,
                                    width=300,
                                    height=20,
                                    anchor=tkinter.NW)

        self.volumeLabel = Label(self.headerFrame,
                                 font=(theme['HEADER']['font'], 10, 'bold'),
                                 bg=theme['HEADER']['background'],
                                 foreground=theme['HEADER']['foreground'],
                                 text='')
        self.volumeLabel.place(x=300, y=0, anchor=tkinter.NW)

        self.mainFrame = Frame(self.menuScreen, width=320, height=200)
        self.mainFrame.pack(side=tkinter.TOP, fill=Y)

        self.listbox = Listbox(self.mainFrame,
                               selectmode=tkinter.SINGLE,
                               font=(theme['MAIN']['font'], 11),
                               bg=theme['MAIN']['background'],
                               fg=theme['MAIN']['foreground'],
                               height=10,
                               activestyle="none",
                               borderwidth=0,
                               highlightthickness=0,
                               selectbackground=theme['MAIN']['selected'],
                               selectforeground=theme['MAIN']['foreground'])
        self.listbox.bind("<Key>", self.handle_keys)
        self.listbox.configure(width=320, height=11)
        self.listbox.pack(side=tkinter.TOP,
                          expand=1,
                          ipadx=0,
                          ipady=0,
                          padx=0,
                          pady=0)
        self.listbox.focus_set()

        self.footer = Label(self.menuScreen,
                            textvariable=self.footer_text_var,
                            font=(theme['FOOTER']['font'], 10, 'bold'),
                            bg=theme['FOOTER']['background'],
                            foreground=theme['FOOTER']['foreground'],
                            justify=tkinter.LEFT,
                            anchor=tkinter.W)
        self.footer.configure(width=320, height=1)
        self.footer.pack(side=tkinter.BOTTOM)

        self.focus_set()
        self.bind("<Key>", self.handle_keys)
        self.screen = "1"
        self.show_screen()
        self.tick()

    def tick(self):
        global awayCount, keyMode, footerMessage, footerMessageCount
        self.update_header()
        if keyMode != 'PLAYER':
            awayCount += 1
            if awayCount > 120:
                awayCount = 0
                self.screen = ''
                self.show_screen()
        else:
            awayCount = 0

        if footerMessage == self.footer_text_var.get():
            footerMessageCount += 1
            if footerMessageCount > 8:
                footerMessageCount = 0
                self.footer_text_var.set("")
        else:
            footerMessage = self.footer_text_var.get()
            footerMessageCount = 0

        self.after(800, self.tick)

    def update_header(self):
        global status, keyMode, songChanged, currentSong, songName, songTicker, minTickerLength, songTickerCount
        status = client.status()
        self.volume = int(status["volume"])
        self.volumeLabel.configure(text=status["volume"])
        if status["state"] == "play":
            currentSong = client.currentsong()
            song = currentSong["artist"] + " - " + currentSong["title"]
            if songName != song:
                songChanged = True
                songName = song
                if keyMode != 'PLAYER':  # song changed, refresh ui
                    if len(songName) >= minTickerLength:
                        songTicker = True
                        songTickerCount = -1
                    else:
                        songTicker = False
                        songTickerCount = 0
            if keyMode != 'PLAYER':
                if songTicker:
                    songTickerCount += 1
                    if songTickerCount == len(songName) + 5:
                        songTickerCount = 0
                song = songName + "     "
                new_song = song[songTickerCount:] + song[:songTickerCount]
                self.current_song_var.set(new_song)
            elif keyMode == 'PLAYER':
                self.show_player()
        else:
            if songName != '':
                self.current_song_var.set('')
                songName = ''
                songChanged = True
                if keyMode == 'PLAYER':
                    self.show_player()

    def show_screen(self):
        global keyMode
        if self.screen == '':
            keyMode = 'PLAYER'
            self.menuScreen.place_forget()
            self.playerScreen.place(height=240, width=320, x=0, y=0)
            self.show_player()
            self.update()
            self.screen = '1'
            return
        self.listbox.delete(0, self.listbox.size() - 1)
        format_name = "string"
        if self.screen in self.screen_format:
            format_name = self.screen_format[self.screen]
        if isinstance(self.screen_data[self.screen], list):
            for item in self.screen_data[self.screen]:
                if format_name == "string":
                    if not item:
                        self.listbox.insert(tkinter.END, "")
                    else:
                        self.listbox.insert(tkinter.END, item[:36])
                if format_name == "SONG":
                    songname = ''
                    if 'artist' in item:
                        songname = item['artist'][:18]
                    songname += " - "
                    if 'title' in item:
                        max = 36 - len(songname)
                        songname += item['title'][:max]
                    self.listbox.insert(tkinter.END, songname)
                if format_name == "PLAYLIST":
                    playlist_name = ''
                    if isinstance(item, str):
                        playlist_name = item
                    else:
                        playlist_name = item['playlist']
                    self.listbox.insert(tkinter.END, playlist_name)

        self.listbox.select_set(0)  # This only sets focus on the first item.
        self.listbox.event_generate("<<ListboxSelect>>")
        self.update()
        return

    def show_player(self):
        global image, bg, songChanged, volumeChanged
        if songChanged or image is None:
            if sys.platform.startswith('linux'):
                process = subprocess.Popen(
                    "./coverart.sh", shell=True,
                    stdout=subprocess.PIPE).stdout.read()
            else:
                process = "./icons/ic_album_white_48dp.png"
            image = ImageTk.PhotoImage(
                Image.open(process).resize((136, 136), Image.ANTIALIAS))
        if bg is None:
            process = "./icons/bg.png"
            if 'img_background' in theme['PLAYER']:
                process = theme['PLAYER']['img_background']
            bg = ImageTk.PhotoImage(
                Image.open(process).resize((320, 240), Image.ANTIALIAS))
        if icon_random is None:
            self.load_icons()

        if status["state"] == "play":
            if songChanged:
                self.playerScreen.delete(tkinter.ALL)
                self.playerScreen.create_image(160, 120, image=bg)

                self.playerScreen.create_rectangle(
                    10, 10, 150, 150, fill=theme['PLAYER']['foreground'])
                self.playerScreen.create_image(80, 80, image=image)

                self.playerScreen.create_image(178, 132, image=icon_random)
                self.playerScreen.create_image(224, 132, image=icon_repeat)
                self.playerScreen.create_image(270, 132, image=icon_single)
                self.playerScreen.create_rectangle(
                    298,
                    146,
                    308,
                    92,
                    fill=theme['PLAYER']['background'],
                    outline=theme['PLAYER']['foreground'],
                    width=1)
                self.playerScreen.create_line(
                    303,
                    144,
                    303,
                    144 - int(self.volume / 2),
                    fill=theme['PLAYER']['foreground'],
                    width=7)

                self.playerScreen.create_text(
                    10,
                    160,
                    text=currentSong['artist'],
                    anchor=tkinter.NW,
                    fill=theme['PLAYER']['foreground'],
                    font=(theme['PLAYER']['font'], 14, 'bold'))
                self.playerScreen.create_text(
                    10,
                    185,
                    text=currentSong['title'],
                    anchor=tkinter.NW,
                    fill=theme['PLAYER']['foreground'],
                    font=(theme['PLAYER']['font'], 12, 'bold'))
                self.playerScreen.create_text(
                    10,
                    210,
                    text=currentSong['album'],
                    anchor=tkinter.NW,
                    fill=theme['PLAYER']['foreground'],
                    font=(theme['PLAYER']['font'], 10, 'bold'))
            else:
                time = str(status['time']).split(":")
                played = int((float(time[0]) / float(time[1])) * 320)
                if played < 3:  # bug
                    self.playerScreen.create_rectangle(
                        0, 236, 320, 240, fill=theme['PLAYER']['background'])
                self.playerScreen.create_rectangle(
                    0, 236, played, 240, fill=theme['PLAYER']['foreground'])
            if volumeChanged:
                volumeChanged = False
                self.playerScreen.create_rectangle(
                    298,
                    146,
                    308,
                    92,
                    fill=theme['PLAYER']['background'],
                    outline=theme['PLAYER']['foreground'],
                    width=1)
                self.playerScreen.create_line(
                    303,
                    144,
                    303,
                    144 - int(self.volume / 2),
                    fill=theme['PLAYER']['foreground'],
                    width=7)
        else:  # Blank Screen
            self.playerScreen.delete(tkinter.ALL)
            self.playerScreen.create_image(160, 120, image=bg)
            self.playerScreen.create_text(
                20,
                20,
                text=theme['PLAYER']['default_message'],
                anchor=tkinter.NW,
                fill=theme['PLAYER']['foreground'],
                font=(theme['PLAYER']['font'], 20, 'bold'))
        songChanged = False
        return

    def handle_keys(self, event):
        global config, client, selectedAlbum, selectedArtist, selectedGenre
        global keyMode, textEntry, textBackAction, textSaveAction, awayCount, theme_name
        global albums, artists, queue, songs, playlists, status, genres, songChanged, volumeChanged

        awayCount = 0
        keycode = str(event.keycode)
        # self.footer_text_var.set(str("Key Pressed : "+keycode))
        if keyMode == 'PLAYER' and keycode != config["PISCREEN_KEYS"]["vol_up"] \
                and keycode != config["PISCREEN_KEYS"]["vol_down"] \
                and keycode != config["PISCREEN_KEYS"]["play"] \
                and keycode != config["PISCREEN_KEYS"]["next"] \
                and keycode != config["PISCREEN_KEYS"]["prev"] \
                and keycode != config["PISCREEN_KEYS"]["power"] \
                and keycode != config["PISCREEN_KEYS"]["left"]:
            keyMode = 'MENU'
            self.playerScreen.place_forget()
            self.menuScreen.place(height=240, width=320, x=0, y=0)
            self.show_screen()
            self.update()
            return
        if keyMode == 'TEXT':
            if keycode == config["PISCREEN_KEYS"]["back"]:  # back
                keyMode = 'MENU'
                self.run_command(textBackAction)
            if keycode == config["PISCREEN_KEYS"]["ok"]:  # ok
                keyMode = 'MENU'
                self.run_command(textSaveAction)
            if event.keysym in '0123456789-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ':
                textEntry += event.keysym
                self.footer_text_var.set(str("Entry : " + textEntry))
            return
        # self.footer.configure(text=str('Key Pressed ' + str(event.keycode)))
        if keycode == config["PISCREEN_KEYS"]["menu"]:
            if self.screen == "1.P":
                selection = int(self.listbox.curselection()[0]) + 1
                if selection > 1:
                    self.footer_text_var.set(
                        str("Press 1 + OK to Delete Playlist"))
                    keyMode = 'TEXT'
                    textBackAction = "PLAYLISTS"
                    textSaveAction = "DELETE_PLAYLIST"
            if self.screen == "1.Q":
                self.footer_text_var.set(str("Press OK to remove Song"))
                keyMode = 'TEXT'
                textBackAction = "QUEUE"
                textSaveAction = "DELETE_SONG"
            return
        if keycode == config["PISCREEN_KEYS"]["down"]:  # down
            if self.listbox.size() > 0:
                selection = int(self.listbox.curselection()[0])
                count = self.listbox.size()
                if selection < (count - 1):
                    self.listbox.select_clear(selection)
                    self.listbox.selection_set(selection + 1)
                    self.listbox.event_generate("<<ListboxSelect>>")
            return
        if keycode == config["PISCREEN_KEYS"]["up"]:  # up
            if self.listbox.size() > 0:
                selection = int(self.listbox.curselection()[0])
                if selection > 0:
                    self.listbox.select_clear(selection)
                    self.listbox.selection_set(selection - 1)
                    self.listbox.event_generate("<<ListboxSelect>>")
            return
        if keycode == config["PISCREEN_KEYS"]["left"] or keycode == config[
                "PISCREEN_KEYS"]["back"]:  # left or escape
            if self.screen != "1":
                menu = self.screen.rsplit(".", maxsplit=1)
                new_screen = menu[0]
                self.screen = new_screen
                self.show_screen()
            else:
                self.screen = ''
                songChanged = True
                self.show_screen()
            return
        if keycode == config["PISCREEN_KEYS"]["right"] or keycode == config[
                "PISCREEN_KEYS"]["ok"]:  # right or return
            if self.listbox.size() > 0:
                selection = int(self.listbox.curselection()[0]) + 1
                new_screen = self.screen + "." + str(selection)
                if new_screen in self.screen_data:
                    if type(self.screen_data[new_screen]) is list:
                        self.screen = new_screen
                        self.show_screen()
                    else:
                        self.run_command(
                            self.screen_data[new_screen]["ACTION"])
                else:
                    if str(new_screen).startswith("1.Q."):
                        menu = new_screen.rsplit(".", maxsplit=1)
                        client.playid(int(queue[int(menu[1]) - 1]["id"]))
                        return
                    if str(new_screen).startswith("1.P."):
                        menu = new_screen.rsplit(".", maxsplit=1)
                        if menu[1] == "1":
                            keyMode = 'TEXT'
                            textBackAction = 'PLAYLISTS'
                            textSaveAction = 'SAVE_PLAYLIST'
                            textEntry = ''
                            self.footer_text_var.set(
                                'Back to Cancel, Ok to Save')
                        else:
                            playlist = playlists[int(menu[1]) - 1]['playlist']
                            client.clear()
                            client.load(playlist)
                            client.play()
                        return
                    if str(new_screen).startswith("1.3.A"):
                        if new_screen.count(".") == 3:
                            menu = new_screen.rsplit(".", maxsplit=1)
                            selectedArtist = artists[int(menu[1]) - 1]
                            albums = []
                            albums = client.list("album", selectedArtist)
                            albums[:0] = ["Add All"]
                            self.footer_text_var.set("SELECTED Artist " +
                                                     selectedArtist)
                            self.screen = new_screen
                            self.screen_data[new_screen] = albums
                            self.show_screen()
                            return
                        elif new_screen.count(".") == 4:
                            menu = new_screen.rsplit(".", maxsplit=1)
                            if menu[1] == "1":  # add all
                                client.findadd("artist", selectedArtist)
                                self.footer_text_var.set("Added All for " +
                                                         selectedArtist)
                                self.screen = menu[0].rsplit(".",
                                                             maxsplit=1)[0]
                                self.show_screen()
                            else:
                                selectedAlbum = albums[int(menu[1]) - 1]
                                songs = client.list("title", "album",
                                                    selectedAlbum, "artist",
                                                    selectedArtist)
                                songs[:0] = ["Add All"]
                                self.screen = new_screen
                                self.screen_data[new_screen] = songs
                                self.show_screen()
                                self.footer_text_var.set("Album Selected " +
                                                         selectedAlbum)
                            return
                        elif new_screen.count(".") == 5:
                            menu = new_screen.rsplit(".", maxsplit=1)
                            if menu[1] == "1":  # add all
                                client.findadd("album", selectedAlbum,
                                               "artist", selectedArtist)
                                self.footer_text_var.set("Added All for " +
                                                         selectedAlbum + "/" +
                                                         selectedArtist)
                                self.screen = menu[0].rsplit(".",
                                                             maxsplit=1)[0]
                                self.show_screen()
                            else:
                                selected_song = songs[int(menu[1]) - 1]
                                client.findadd("title", selected_song, "album",
                                               selectedAlbum, "artist",
                                               selectedArtist)
                                self.footer_text_var.set("Added " +
                                                         selected_song + "/" +
                                                         selectedAlbum + "/" +
                                                         selectedArtist)
                            return
                    if str(new_screen).startswith("1.3.B"):
                        menu = new_screen.rsplit(".", maxsplit=1)
                        if new_screen.count(".") == 3:
                            selectedAlbum = albums[int(menu[1]) - 1]
                            songs = client.list("title", "album",
                                                selectedAlbum)
                            songs[:0] = ["Add All"]
                            self.screen = new_screen
                            self.screen_data[new_screen] = songs
                            self.show_screen()
                            self.footer_text_var.set("Album Selected " +
                                                     selectedAlbum)
                        if new_screen.count(".") == 4:
                            if menu[1] == "1":  # add all
                                client.findadd("album", selectedAlbum)
                                self.footer_text_var.set(
                                    "Added All for album " + selectedAlbum)
                                self.screen = menu[0].rsplit(".",
                                                             maxsplit=1)[0]
                                self.show_screen()
                            else:
                                selected_song = songs[int(menu[1]) - 1]
                                client.findadd("title", selected_song, "album",
                                               selectedAlbum)
                                self.footer_text_var.set("Added " +
                                                         selected_song + "/" +
                                                         selectedAlbum)
                        return
                    if str(new_screen).startswith("1.3.C"):
                        menu = new_screen.rsplit(".", maxsplit=1)
                        if new_screen.count(".") == 3:
                            selectedGenre = genres[int(menu[1]) - 1]
                            songs = client.list("title", "genre",
                                                selectedGenre)
                            self.screen = new_screen
                            self.screen_data[new_screen] = songs
                            self.show_screen()
                            self.footer_text_var.set("Genre Selected " +
                                                     selectedAlbum)
                        if new_screen.count(".") == 4:
                            selected_song = songs[int(menu[1]) - 1]
                            client.findadd("title", selected_song, "genre",
                                           selectedGenre)
                            self.footer_text_var.set("Added " + selected_song +
                                                     selectedGenre)
                        return
                    if str(new_screen).startswith("1.4.T"):
                        menu = new_screen.rsplit(".", maxsplit=1)
                        theme_name = themes[int(menu[1]) - 1]
                        self.footer_text_var.set("Applying Theme " +
                                                 theme_name)
                        self.apply_theme()
            return
        if keycode == config["PISCREEN_KEYS"]["vol_up"]:
            if self.volume < 100:
                self.volume += 1
                client.setvol(self.volume)
                volumeChanged = True
                self.footer_text_var.set("Volume Up")
            else:
                self.footer_text_var.set("Volume Max!!")
            return
        if keycode == config["PISCREEN_KEYS"]["vol_down"]:
            if self.volume > 0:
                self.volume -= 1
                client.setvol(self.volume)
                volumeChanged = True
                self.footer_text_var.set("Volume Down")
            else:
                self.footer_text_var.set("Volume Zero!!")
            return
        if keycode == config["PISCREEN_KEYS"]["play"]:
            if status["state"] == "play":
                client.pause()
                self.footer_text_var.set("Paused")
            else:
                client.play()
                self.footer_text_var.set("Playing")
            return
        if keycode == config["PISCREEN_KEYS"]["next"]:
            client.next()
            self.footer_text_var.set("Next Song")
            return
        if keycode == config["PISCREEN_KEYS"]["prev"]:
            client.previous()
            self.footer_text_var.set("Previous Song")
            return
        if keycode == config["PISCREEN_KEYS"]["home"]:
            self.screen = ''
            self.show_screen()
            return
        if keycode == config["PISCREEN_KEYS"]["power"]:
            if sys.platform.startswith('linux'):
                call("sudo nohup shutdown -h now", shell=True)
            else:
                self.footer_text_var.set("Can't PowerOff from remote")
            return
        self.footer_text_var.set("UNKNOWN " + keycode)

    def run_command(self, action):
        global client, keyMode, textEntry, status
        global albums, artists, queue, songs, playlists, genres, themes
        if action == "QUEUE":
            local_queue = client.playlistinfo()
            queue.clear()
            for item in local_queue:
                queue.append(item)
            self.screen = "1.Q"
            self.screen_data["1.Q"] = queue
            self.footer_text_var.set("Right to play Song, Menu to delete")
            self.show_screen()
        elif action == "PLAYLISTS":
            playlists = client.listplaylists()
            playlists[:0] = ["SAVE PLAYLIST"]
            self.screen = "1.P"
            self.screen_data["1.P"] = playlists
            self.footer_text_var.set("Right to play Playlist, Menu to delete")
            self.show_screen()
        elif action == "ARTISTS":
            artists = client.list("artist")
            self.screen = "1.3.A"
            self.screen_data["1.3.A"] = artists
            self.show_screen()
        elif action == "ALBUMS":
            albums = client.list("album")
            self.screen = "1.3.B"
            self.screen_data["1.3.B"] = albums
            self.show_screen()
        elif action == "GENRES":
            genres = client.list("genre")
            self.screen = "1.3.C"
            self.screen_data["1.3.C"] = genres
            self.show_screen()
        elif action == "UPDATE_LIBRARY":
            self.footer_text_var.set("Updating library")
            client.update()
        elif action == "THEMES":
            self.footer_text_var.set("Select Theme")
            themes = ["default", "foofighters", "light"]
            self.screen = "1.4.T"
            self.screen_data["1.4.T"] = themes
            self.show_screen()
        elif action == "SAVE_PLAYLIST":
            keyMode = 'MENU'
            found = False
            if textEntry == '':
                self.footer_text_var.set("Name Empty!!")
                return
            for playlist in playlists:
                if isinstance(
                        playlist,
                        str) is False and textEntry == playlist['playlist']:
                    found = True
            if found:
                client.rm(textEntry)
                client.save(textEntry)
            else:
                client.save(textEntry)
            self.footer_text_var.set("Saved Playlist " + textEntry)
            textEntry = ''
            self.run_command("PLAYLISTS")
        elif action == "DELETE_PLAYLIST":
            keyMode = 'MENU'
            if textEntry == '1':
                selection = int(self.listbox.curselection()[0])
                client.rm(playlists[selection]['playlist'])
            textEntry = ''
            self.run_command("PLAYLISTS")
        elif action == "DELETE_SONG":
            keyMode = 'MENU'
            client.delete(int(self.listbox.curselection()[0]))
            textEntry = ''
            self.run_command("QUEUE")
        elif action == "CLEAR":
            self.footer_text_var.set("Clearing Queue")
            client.clear()
        elif action == "RANDOM":
            if status['random'] == '0':
                client.random('1')
            else:
                client.random('0')
            status = client.status()
            self.screen_data['1'][5] = "RANDOM " + status['random']
            self.update_random()
            self.show_screen()
        elif action == "REPEAT":
            if status['repeat'] == '0':
                client.repeat('1')
            else:
                client.repeat('0')
            status = client.status()
            self.screen_data['1'][6] = "REPEAT " + status['repeat']
            self.update_repeat()
            self.show_screen()
        elif action == "SINGLE":
            if status['single'] == '0':
                client.single('1')
            else:
                client.single('0')
            status = client.status()
            self.screen_data['1'][7] = "SINGLE " + status['single']
            self.update_single()
            self.show_screen()
        elif action == "CONSUME":
            if status['consume'] == '0':
                client.consume('1')
            else:
                client.consume('0')
            status = client.status()
            self.screen_data['1'][8] = "CONSUME " + status['consume']
            self.show_screen()
        self.update()
        return

    def load_icons(self):
        self.update_random()
        self.update_repeat()
        self.update_single()

    def update_random(self):
        global status, theme, icon_random
        fgcolor = ImageColor.getrgb(theme['PLAYER']['foreground'])
        bgcolor = ImageColor.getrgb(theme['PLAYER']['background'])
        fgcolor += (255, )
        bgcolor += (255, )
        icon_random = Image.open('./icons/ic_shuffle_white_36dp.png')
        if icon_random.mode != 'RGBA':
            icon_random = icon_random.convert('RGBA')
        data = list(icon_random.getdata())
        newData = list()
        for pixel in data:
            if pixel[3] != 0:
                if status['random'] == '1':
                    newData.append(fgcolor)
                else:
                    newData.append(bgcolor)
            else:
                newData.append(pixel)
        icon_random.putdata(newData)
        icon_random = ImageTk.PhotoImage(
            icon_random.resize((36, 36), Image.ANTIALIAS))

    def update_single(self):
        global status, theme, icon_single
        fgcolor = ImageColor.getrgb(theme['PLAYER']['foreground'])
        bgcolor = ImageColor.getrgb(theme['PLAYER']['background'])
        fgcolor += (255, )
        bgcolor += (255, )
        icon_single = Image.open('./icons/ic_repeat_one_white_36dp.png')
        if icon_single.mode != 'RGBA':
            icon_single = icon_single.convert('RGBA')
        data = list(icon_single.getdata())
        newData = list()
        for pixel in data:
            if pixel[3] != 0:
                if status['single'] == '1':
                    newData.append(fgcolor)
                else:
                    newData.append(bgcolor)
            else:
                newData.append(pixel)
        icon_single.putdata(newData)
        icon_single = ImageTk.PhotoImage(
            icon_single.resize((36, 36), Image.ANTIALIAS))

    def update_repeat(self):
        global status, theme, icon_repeat
        fgcolor = ImageColor.getrgb(theme['PLAYER']['foreground'])
        bgcolor = ImageColor.getrgb(theme['PLAYER']['background'])
        fgcolor += (255, )
        bgcolor += (255, )
        icon_repeat = Image.open('./icons/ic_repeat_white_36dp.png')
        if icon_repeat.mode != 'RGBA':
            icon_repeat = icon_repeat.convert('RGBA')
        data = list(icon_repeat.getdata())
        newData = list()
        for pixel in data:
            if pixel[3] != 0:
                if status['repeat'] == '1':
                    newData.append(fgcolor)
                else:
                    newData.append(bgcolor)
            else:
                newData.append(pixel)
        icon_repeat.putdata(newData)
        icon_repeat = ImageTk.PhotoImage(
            icon_repeat.resize((36, 36), Image.ANTIALIAS))

    def apply_theme(self):
        global theme_name, theme, config, bg
        my_file = Path('./theme/' + theme_name + '/theme.ini')
        if my_file.is_file():
            theme = configparser.ConfigParser()
            theme.read('./theme/' + theme_name + '/theme.ini')
            # player related settings
            bg = None
            self.playerScreen.configure(bg=theme['PLAYER']['background'])
            self.load_icons()
            # menu related settings
            self.headerFrame.configure(bg=theme['HEADER']['background'])
            self.currentSongLabel.configure(
                font=(theme['HEADER']['font'], 12, 'bold'),
                bg=theme['HEADER']['background'],
                foreground=theme['HEADER']['foreground'])
            self.volumeLabel.configure(
                font=(theme['HEADER']['font'], 10, 'bold'),
                bg=theme['HEADER']['background'],
                foreground=theme['HEADER']['foreground'])
            self.listbox.configure(
                font=(theme['MAIN']['font'], 11),
                bg=theme['MAIN']['background'],
                fg=theme['MAIN']['foreground'],
                selectbackground=theme['MAIN']['selected'],
                selectforeground=theme['MAIN']['foreground'])
            self.footer.configure(font=(theme['FOOTER']['font'], 10, 'bold'),
                                  bg=theme['FOOTER']['background'],
                                  foreground=theme['FOOTER']['foreground'])

            # write theme to config.ini
            config["THEME"]["theme"] = theme_name
            with open('config.ini', 'w') as configfile:
                config.write(configfile)
        else:
            self.footer_text_var.set("Theme Not Found")
            theme_name = config["THEME"]["theme"]