예제 #1
0
_bgcolor = '#d9d9d9'  # X11 color: 'gray85'
_fgcolor = '#000000'  # X11 color: 'black'
_compcolor = '#d9d9d9'  # X11 color: 'gray85'
_ana1color = '#d9d9d9'  # X11 color: 'gray85'
_ana2color = '#d9d9d9'  # X11 color: 'gray85'
styl = Style()
styl.theme_use('clam')
styl.configure('.', background=_bgcolor)
styl.configure('.', foreground=_fgcolor)
styl.configure('.', sliderthickness='20')
styl.configure('.', font="TkDefaultFont")
styl.map('.', background=[('selected', _compcolor), ('active', _ana2color)])

Frame1 = Frame(root)
Frame1.place(relx=0.02, rely=0.02, relheight=0.27, relwidth=0.46)
Frame1.configure(relief=GROOVE)
Frame1.configure(borderwidth="2")
Frame1.configure(relief=GROOVE)
Frame1.configure(width=285)

Checkbutton1 = Checkbutton(Frame1)
Checkbutton1.place(relx=0.07, rely=0.43, relheight=0.22, relwidth=0.34)
Checkbutton1.configure(text='''Profile photo''')
Checkbutton1.configure(variable=check1)

Checkbutton3 = Checkbutton(Frame1)
Checkbutton3.place(relx=0.07, rely=0.7, relheight=0.22, relwidth=0.35)
Checkbutton3.configure(text='''Header photo''')
Checkbutton3.configure(variable=check2)

Label1 = Label(Frame1)
예제 #2
0
class AppRow(MagicSession, Frame):
    """
    Row for each app in mixer.
    handles refreshing the gui if session is changed external.
    handles user input and changing session volume/mute.
    """
    def __init__(self, root_frame_instance):
        super().__init__(volume_callback=self.update_volume,
                         mute_callback=self.update_mute,
                         state_callback=self.update_state)

        self.root_frame_instance = root_frame_instance

        # ______________ DISPLAY NAME ______________
        self.app_name = self.magic_root_session.app_exec

        print(f":: new session: {self.app_name}")
        # ______________ CREATE FRAME ______________
        # super(MagicSession, self).__init__(root_frame_instance)
        Frame.__init__(self, root_frame_instance)

        # _______________ NAME LABEL _______________
        self.name_label = Label(self,
                                text=self.app_name,
                                font=("Consolas", 12, "italic"))

        # _____________ VOLUME SLIDER _____________
        self.volume_slider_state = DoubleVar()

        self.volume_slider = Scale(self,
                                   variable=self.volume_slider_state,
                                   command=self._slide_volume,
                                   from_=0,
                                   to=100,
                                   takefocus=False,
                                   orient=HORIZONTAL)

        # set initial:
        self.volume_slider_state.set(self.volume * 100)

        # ______________ MUTE BUTTON ______________

        self.mute_button_state = StringVar()

        self.mute_button = Button(self,
                                  style="",
                                  textvariable=self.mute_button_state,
                                  command=self._toogle_mute,
                                  takefocus=False)

        # set initial:
        self.update_mute(self.mute)

        # _____________ SESSION STATUS _____________
        self.status_line = Frame(self, style="", width=6)

        # set initial:
        self.update_state(self.state)

        # ________________ SEPARATE ________________
        self.separate = Separator(self, orient=HORIZONTAL)

        # ____________ ARRANGE ELEMENTS ____________
        # set column[1] to take the most space
        # and make all others as small as possible:
        self.columnconfigure(1, weight=1)

        # grid
        self.name_label.grid(row=0, column=0, columnspan=2, sticky="EW")
        self.mute_button.grid(row=1, column=0)
        self.volume_slider.grid(row=1, column=1, sticky="EW", pady=10, padx=20)
        self.separate.grid(row=2, column=0, columnspan=3, sticky="EW", pady=10)
        self.status_line.grid(row=0, rowspan=2, column=2, sticky="NS")

        # _____________ DISPLAY FRAME _____________
        self.pack(pady=0, padx=15, fill='x')

    def update_volume(self, new_volume):
        """
        when volume is changed externally
        (see callback -> AudioSessionEvents -> OnSimpleVolumeChanged )
        """
        # compare if the windows callback is because we set the slider:
        # if so drop update since we made the change
        # and all is already up to date - this will prevent lagg
        print(f"{self.app_name} volume: {new_volume}")
        self.volume_slider_state.set(new_volume * 100)

    def update_mute(self, new_mute):
        """ when mute state is changed by user or through other app """
        if new_mute:
            icon = "🔈"
            self.mute_button.configure(style="Muted.TButton")
        else:
            icon = "🔊"
            self.mute_button.configure(style="Unmuted.TButton")

        # .set is a method of tkinters variables
        # it will change the button text
        print(f"{self.app_name} mute: {icon}")
        self.mute_button_state.set(icon)

    def update_state(self, new_state):
        """
        when status changed
        (see callback -> AudioSessionEvents -> OnStateChanged)
        """
        print(f"{self.app_name} state: {new_state}")
        if new_state == AudioSessionState.Inactive:
            # AudioSessionStateInactive
            self.status_line.configure(style="Inactive.TFrame")

        elif new_state == AudioSessionState.Active:
            # AudioSessionStateActive
            self.status_line.configure(style="Active.TFrame")

        elif new_state == AudioSessionState.Expired:
            # AudioSessionStateExpired
            self.status_line.configure(style="TFrame")
            """when session expires"""
            print(f":: closed session: {self.app_name}")
            self.destroy()

    def _slide_volume(self, value):
        """ when slider moved by user """
        new_volume = float(value) / 100
        # check if new user value really is new: (ttk bug)
        if self.volume != new_volume:
            # since self.volume is true data through windows
            # it will generally differ, but 1.0 == 1
            print(f"with pycaw: {self.app_name} volume: {new_volume}")
            self.volume = new_volume

    def _toogle_mute(self):
        """ when mute button pressed """
        new_mute = self.toggle_mute()

        self.update_mute(new_mute)
예제 #3
0
class BaseWidget(Toplevel):
    def __init__(self, master, name, config, save_config):
        """Create base desktop widget."""
        Toplevel.__init__(self, master, class_=APP_NAME)

        self.rowconfigure(2, weight=1)
        self.columnconfigure(0, weight=1)
        self.minsize(50, 50)
        self.protocol('WM_DELETE_WINDOW', self.withdraw)

        self.ewmh = EWMH()

        self.name = name
        self.config = config  # configparser
        self.save_config = save_config  # save config method

        # get splash window type compatibility
        if CONFIG.getboolean('General', 'splash_supported', fallback=True):
            self.attributes('-type', 'splash')
        else:
            self.attributes('-type', 'toolbar')

        # control main menu checkbutton
        self.variable = BooleanVar(self, False)
        # save widget's position
        self._position = StringVar(
            self, self.config.get(name, 'position', fallback='normal'))
        add_trace(self._position, 'write', self._position_trace)

        self.title('feedagregator.widget.{}'.format(name.replace(' ', '_')))
        self.withdraw()

        # window dragging
        self.x = None
        self.y = None

        # --- menu
        self._create_menu()

        # --- elements
        # --- --- title bar
        frame = Frame(self, style='widget.TFrame')
        Button(frame, style='widget.close.TButton',
               command=self.withdraw).pack(side='left')
        self.label = Label(frame,
                           text=name,
                           style='widget.title.TLabel',
                           anchor='center')
        self.label.pack(side='left', fill='x', expand=True)
        frame.grid(row=0, columnspan=2, padx=4, pady=4, sticky='ew')

        sep = Separator(self, style='widget.Horizontal.TSeparator')
        sep.grid(row=1, columnspan=2, sticky='ew')
        # --- --- widget body
        self.canvas = Canvas(self, highlightthickness=0)
        self.canvas.grid(row=2,
                         column=0,
                         sticky='ewsn',
                         padx=(2, 8),
                         pady=(2, 4))
        scroll = AutoScrollbar(self,
                               orient='vertical',
                               style='widget.Vertical.TScrollbar',
                               command=self.canvas.yview)
        scroll.grid(row=2, column=1, sticky='ns', pady=(2, 14))
        self.canvas.configure(yscrollcommand=scroll.set)
        self.display = Frame(self.canvas, style='widget.TFrame')
        self.canvas.create_window(0,
                                  0,
                                  anchor='nw',
                                  window=self.display,
                                  tags=('display', ))

        self.display.columnconfigure(0, weight=1)

        # --- style
        self.style = Style(self)
        self._font_size = 10
        self.update_style()

        # --- resizing and geometry
        corner = Sizegrip(self, style="widget.TSizegrip")
        corner.place(relx=1, rely=1, anchor='se', bordermode='outside')

        geometry = self.config.get(self.name, 'geometry')
        if geometry:
            self.geometry(geometry)
        self.update_idletasks()
        if self.config.getboolean(self.name, 'visible', fallback=True):
            self.deiconify()

        # --- bindings
        self.bind('<3>', lambda e: self.menu.tk_popup(e.x_root, e.y_root))
        for widget in [self.label, self.canvas, sep]:
            widget.bind('<ButtonPress-1>', self._start_move)
            widget.bind('<ButtonRelease-1>', self._stop_move)
            widget.bind('<B1-Motion>', self._move)
        self.label.bind('<Map>', self._change_position)
        self.bind('<Configure>', self._on_configure)
        self.bind('<4>', lambda e: self._scroll(-1))
        self.bind('<5>', lambda e: self._scroll(1))

        self.update_idletasks()
        self.canvas.configure(scrollregion=self.canvas.bbox('all'))

        self.populate_widget()

        if not CONFIG.getboolean('General', 'splash_supported',
                                 fallback=True) and self.config.getboolean(
                                     self.name, 'visible', fallback=True):
            Toplevel.withdraw(self)
            Toplevel.deiconify(self)

    def _create_menu(self):
        self.menu = Menu(self, tearoff=False)
        self.menu_sort = Menu(self.menu, tearoff=False)

        menu_pos = Menu(self.menu, tearoff=False)
        menu_pos.add_radiobutton(label=_('Normal'),
                                 value='normal',
                                 variable=self._position,
                                 command=self._change_position)
        menu_pos.add_radiobutton(label=_('Above'),
                                 value='above',
                                 variable=self._position,
                                 command=self._change_position)
        menu_pos.add_radiobutton(label=_('Below'),
                                 value='below',
                                 variable=self._position,
                                 command=self._change_position)
        self.menu.add_cascade(label=_('Sort'), menu=self.menu_sort)
        self.menu.add_cascade(label=_('Position'), menu=menu_pos)
        self.menu.add_command(label=_('Hide'), command=self.withdraw)
        self.menu.add_command(label=_('Open all'), command=self.open_all)
        self.menu.add_command(label=_('Close all'), command=self.close_all)

    def populate_widget(self):
        pass  # to be overriden by subclass

    def open_all(self):
        pass  # to be overriden by subclass

    def close_all(self):
        pass  # to be overriden by subclass

    def entry_add(self, title, date, summary, url):
        """Display entry and return the toggleframe and htmlframe."""
        def unwrap(event):
            l.update_idletasks()
            try:
                h = l.html.bbox()[-1]
            except TclError:
                pass
            else:
                l.configure(height=h + 2)

        def resize(event):
            if l.winfo_viewable():
                try:
                    h = l.html.bbox()[-1]
                except TclError:
                    pass
                else:
                    l.configure(height=h + 2)

        # convert date to locale time
        formatted_date = format_datetime(datetime.strptime(
            date, '%Y-%m-%d %H:%M').astimezone(tz=None),
                                         'short',
                                         locale=getlocale()[0])

        tf = ToggledFrame(self.display,
                          text="{} - {}".format(title, formatted_date),
                          style='widget.TFrame')
        l = HtmlFrame(tf.interior, height=50, style='widget.interior.TFrame')
        l.set_content(summary)
        l.set_style(self._stylesheet)
        l.set_font_size(self._font_size)
        tf.interior.configure(style='widget.interior.TFrame')
        tf.interior.rowconfigure(0, weight=1)
        tf.interior.columnconfigure(0, weight=1)
        l.grid(padx=4, sticky='eswn')
        Button(tf.interior,
               text='Open',
               style='widget.TButton',
               command=lambda: webopen(url)).grid(pady=4, padx=6, sticky='e')
        tf.grid(sticky='we', row=len(self.entries), pady=2, padx=(8, 4))
        tf.bind("<<ToggledFrameOpen>>", unwrap)
        l.bind("<Configure>", resize)
        return tf, l

    def update_position(self):
        if self._position.get() == 'normal':
            if CONFIG.getboolean('General', 'splash_supported', fallback=True):
                self.attributes('-type', 'splash')
            else:
                self.attributes('-type', 'toolbar')
        if self.variable.get():
            Toplevel.withdraw(self)
            Toplevel.deiconify(self)

    def update_style(self):
        self.attributes('-alpha', CONFIG.getint('Widget', 'alpha') / 100)
        text_font = Font(self, font=CONFIG.get('Widget', 'font')).actual()
        bg = CONFIG.get('Widget', 'background')
        feed_bg = CONFIG.get('Widget', 'feed_background', fallback='gray20')
        feed_fg = CONFIG.get('Widget', 'feed_foreground', fallback='white')

        self._stylesheet = """
body {
  background-color: %(bg)s;
  color: %(fg)s;
  font-family: %(family)s;
  font-weight: %(weight)s;
  font-style: %(slant)s;
}

ul {
padding-left: 5px;
}

ol {
padding-left: 5px;
}

#title {
  font-weight: bold;
  font-size: large;
}

a {
  color: %(link)s;
  font-style: italic;
}

code {font-family: monospace;}

a:hover {
  font-style: italic;
  border-bottom: 1px solid %(link)s;
}
""" % (dict(bg=feed_bg,
            fg=feed_fg,
            link=CONFIG.get('Widget', 'link_color', fallback='#89B9F6'),
            **text_font))

        self.configure(bg=bg)
        self.canvas.configure(background=bg)
        self._font_size = text_font['size']

    def withdraw(self):
        Toplevel.withdraw(self)
        self.variable.set(False)

    def deiconify(self):
        Toplevel.deiconify(self)
        self.variable.set(True)

    def _scroll(self, delta):
        top, bottom = self.canvas.yview()
        top += delta * 0.05
        top = min(max(top, 0), 1)
        self.canvas.yview_moveto(top)

    def _position_trace(self, *args):
        self.config.set(self.name, 'position', self._position.get())
        self.save_config()

    def _change_position(self, event=None):
        '''Make widget sticky and set its position with respects to the other windows.'''
        pos = self._position.get()
        splash_supp = CONFIG.getboolean('General',
                                        'splash_supported',
                                        fallback=True)
        try:
            for w in self.ewmh.getClientList():
                if w.get_wm_name() == self.title():
                    self.ewmh.setWmState(w, 1, '_NET_WM_STATE_STICKY')
                    self.ewmh.setWmState(w, 1, '_NET_WM_STATE_SKIP_TASKBAR')
                    self.ewmh.setWmState(w, 1, '_NET_WM_STATE_SKIP_PAGER')
                    if pos == 'above':
                        self.attributes('-type', 'dock')
                        self.ewmh.setWmState(w, 1, '_NET_WM_STATE_ABOVE')
                        self.ewmh.setWmState(w, 0, '_NET_WM_STATE_BELOW')
                    elif pos == 'below':
                        self.attributes('-type', 'desktop')
                        self.ewmh.setWmState(w, 0, '_NET_WM_STATE_ABOVE')
                        self.ewmh.setWmState(w, 1, '_NET_WM_STATE_BELOW')
                    else:
                        if splash_supp:
                            self.attributes('-type', 'splash')
                        else:
                            self.attributes('-type', 'toolbar')
                        self.ewmh.setWmState(w, 0, '_NET_WM_STATE_BELOW')
                        self.ewmh.setWmState(w, 0, '_NET_WM_STATE_ABOVE')
            self.ewmh.display.flush()
            if event is None and not splash_supp:
                Toplevel.withdraw(self)
                Toplevel.deiconify(self)
        except ewmh.display.error.BadWindow:
            pass

    def _on_configure(self, event):
        if event.widget is self:
            geometry = self.geometry()
            if geometry != '1x1+0+0':
                self.config.set(self.name, 'geometry', geometry)
                self.save_config()
        elif event.widget in [self.canvas, self.display]:
            self.canvas.configure(scrollregion=self.canvas.bbox('all'))
            self.canvas.itemconfigure('display',
                                      width=self.canvas.winfo_width() - 4)

    def _start_move(self, event):
        self.x = event.x
        self.y = event.y
        self.configure(cursor='fleur')
        self.display.configure(cursor='fleur')

    def _stop_move(self, event):
        self.x = None
        self.y = None
        self.configure(cursor='arrow')
        self.display.configure(cursor='arrow')

    def _move(self, event):
        if self.x is not None and self.y is not None:
            deltax = event.x - self.x
            deltay = event.y - self.y
            x = self.winfo_x() + deltax
            y = self.winfo_y() + deltay
            self.geometry("+%s+%s" % (x, y))