Exemple #1
0
    def create_content(self, **kw):
        self.rowconfigure(2, weight=1)
        self.columnconfigure(0, weight=1)
        self.minsize(50, 50)
        self.hide_completed = CONFIG.getboolean('Tasks', 'hide_completed')

        # --- elements
        label = Label(self, text=_('Tasks').upper(), style='title.Tasks.TLabel',
                      anchor='center')
        label.grid(row=0, columnspan=2, pady=4, sticky='ew')
        Separator(self, style='Tasks.TSeparator').grid(row=1, columnspan=2, sticky='we')
        self.display = Text(self, width=20, height=10, relief='flat',
                            cursor='arrow', wrap='word',
                            highlightthickness=0, state='disabled',
                            spacing1=5,
                            tabs=('35', 'right', '45', 'left'))
        self.display.grid(sticky='nsew', row=2, column=0, padx=2, pady=2)
        scroll = AutoScrollbar(self, orient='vertical',
                               style='Tasks.Vertical.TScrollbar',
                               command=self.display.yview)
        scroll.grid(row=2, column=1, sticky='ns', pady=(2, 16))
        self.display.configure(yscrollcommand=scroll.set)
        self.display_tasks()

        corner = Sizegrip(self, style="Tasks.TSizegrip")
        corner.place(relx=1, rely=1, anchor='se')

        # --- bindings
        self.bind('<3>', lambda e: self.menu.tk_popup(e.x_root, e.y_root))
        label.bind('<ButtonPress-1>', self._start_move)
        label.bind('<ButtonRelease-1>', self._stop_move)
        label.bind('<B1-Motion>', self._move)
Exemple #2
0
 def ting():
     """ joue le son marquant le changement de période """
     if not CONFIG.getboolean("Pomodoro", "mute", fallback=False):
         Popen([
             CONFIG.get("General", "soundplayer"),
             CONFIG.get("Pomodoro", "beep")
         ])
Exemple #3
0
    def __init__(self, name, master=None, **kw):
        """
        Create a  desktop widget that sticks on the desktop.
        """
        Toplevel.__init__(self, master)
        self.name = name
        if CONFIG.getboolean('General', 'splash_supported', fallback=True):
            self.attributes('-type', 'splash')
        else:
            self.attributes('-type', 'toolbar')

        self.style = Style(self)

        self._position = StringVar(self, CONFIG.get(self.name, 'position'))
        self._position.trace_add(
            'write',
            lambda *x: CONFIG.set(self.name, 'position', self._position.get()))

        self.ewmh = EWMH()
        self.title('scheduler.{}'.format(self.name.lower()))

        self.withdraw()

        # control main menu checkbutton
        self.variable = BooleanVar(self, False)

        # --- menu
        self.menu = Menu(self, relief='sunken', activeborderwidth=0)
        self._populate_menu()

        self.create_content(**kw)

        self.x = None
        self.y = None

        # --- geometry
        geometry = CONFIG.get(self.name, 'geometry')
        self.update_idletasks()
        if geometry:
            self.geometry(geometry)
        self.update_idletasks()

        if CONFIG.getboolean(self.name, 'visible', fallback=True):
            self.show()

        # --- bindings
        self.bind('<Configure>', self._on_configure)
Exemple #4
0
 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():
         self.withdraw()
         self.deiconify()
Exemple #5
0
 def show(self):
     ''' make widget sticky '''
     self.deiconify()
     self.update_idletasks()
     splash_supp = CONFIG.getboolean('General',
                                     'splash_supported',
                                     fallback=True)
     try:
         pos = self._position.get()
         for w in self.ewmh.getClientList():
             if w.get_wm_name() == self.title():
                 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')
                     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')
                 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')
                     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')
                 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.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')
         self.ewmh.display.flush()
         if not splash_supp:
             self.withdraw()
             self.deiconify()
         CONFIG.set(self.name, 'visible', 'True')
         self.variable.set(True)
         save_config()
     except TypeError:
         pass
Exemple #6
0
    def _init_tasks(self):
        self.frames[_('Tasks')].columnconfigure(0, weight=1)
        self.tasks_hide_comp = tk.BooleanVar(
            self, CONFIG.getboolean('Tasks', 'hide_completed'))
        # --- Fonts
        frame_font = ttk.Frame(self.frames[_('Tasks')])
        frame_font.columnconfigure(2, weight=1)
        ttk.Label(frame_font, text=_('Font'),
                  style='title.TLabel').grid(row=0,
                                             column=0,
                                             sticky='w',
                                             padx=4,
                                             pady=4)
        # --- --- title
        ttk.Label(frame_font, style='subtitle.TLabel',
                  text=_('Title')).grid(row=1,
                                        column=0,
                                        sticky='nw',
                                        padx=4,
                                        pady=8)
        self.tasks_font_title = FontFrame(frame_font,
                                          CONFIG.get('Tasks', 'font_title'),
                                          True)
        self.tasks_font_title.grid(row=1, column=1, padx=4, pady=4)
        ttk.Separator(frame_font, orient='horizontal').grid(row=2,
                                                            columnspan=3,
                                                            padx=10,
                                                            pady=4,
                                                            sticky='ew')
        # --- --- text
        ttk.Label(frame_font, style='subtitle.TLabel',
                  text=_('Text')).grid(row=5,
                                       column=0,
                                       sticky='nw',
                                       padx=4,
                                       pady=8)
        self.tasks_font = FontFrame(frame_font, CONFIG.get('Tasks', 'font'))
        self.tasks_font.grid(row=5, column=1, padx=4, pady=4)

        # --- opacity
        self.tasks_opacity = OpacityFrame(
            self.frames[_('Tasks')],
            CONFIG.getfloat("Tasks", "alpha", fallback=0.85))

        # --- colors
        frame_color = ttk.Frame(self.frames[_('Tasks')])
        ttk.Label(frame_color, text=_('Colors'),
                  style='title.TLabel').grid(row=0,
                                             column=0,
                                             sticky='w',
                                             padx=8,
                                             pady=4)
        self.tasks_bg = ColorFrame(frame_color,
                                   CONFIG.get('Tasks', 'background'),
                                   _('Background'))
        self.tasks_bg.grid(row=0, column=1, sticky='e', padx=8, pady=4)
        self.tasks_fg = ColorFrame(frame_color,
                                   CONFIG.get('Tasks', 'foreground'),
                                   _('Foreground'))
        self.tasks_fg.grid(row=0, column=2, sticky='e', padx=8, pady=4)

        # --- placement
        frame_font.grid(sticky='ew')
        ttk.Separator(self.frames[_('Tasks')],
                      orient='horizontal').grid(sticky='ew', pady=8)
        self.tasks_opacity.grid(sticky='w', padx=4)
        ttk.Separator(self.frames[_('Tasks')],
                      orient='horizontal').grid(sticky='ew', pady=8)
        frame_color.grid(sticky='w')
        ttk.Separator(self.frames[_('Tasks')],
                      orient='horizontal').grid(sticky='ew', pady=8)
        ttk.Checkbutton(self.frames[_('Tasks')],
                        text=_('Hide completed tasks'),
                        variable=self.tasks_hide_comp).grid(sticky='w',
                                                            padx=4,
                                                            pady=4)
Exemple #7
0
    def _init_reminders(self):
        # --- window

        def toggle_window():
            b = 'selected' in self.reminders_window.state()
            state = [b * '!' + 'disabled']
            label.state(state)
            self.reminders_timeout.state(state)
            self.reminders_blink.state(state)
            self.reminders_sound.state(state)

        frame_window = ttk.Frame(self.frames[_('Reminders')])
        frame_window.columnconfigure(0, weight=1)
        self.reminders_window = ttk.Checkbutton(frame_window,
                                                text=_('Banner'),
                                                style='title.TCheckbutton',
                                                command=toggle_window)
        self.reminders_window.grid(sticky='w',
                                   row=0,
                                   columnspan=2,
                                   column=0,
                                   pady=4)
        self.reminders_window.state(
            ('!alternate', '!' *
             (not CONFIG.getboolean('Reminders', 'window')) + 'selected'))
        # --- --- timeout
        frame_timeout = ttk.Frame(frame_window)
        frame_timeout.grid(sticky='w', padx=(16, 4), pady=4)
        label = ttk.Label(frame_timeout, text=_('Timeout (min)'))
        label.pack(side='left')
        self.reminders_timeout = ttk.Entry(frame_timeout,
                                           width=5,
                                           justify='center',
                                           validate='key',
                                           validatecommand=(self._only_nb,
                                                            '%P'))
        self.reminders_timeout.insert(0, CONFIG.get('Reminders', 'timeout'))
        self.reminders_timeout.pack(side='left', padx=4)
        # --- --- colors
        frame_color = ttk.Frame(frame_window)
        frame_color.grid(sticky='w', padx=(16, 4), pady=4)
        self.reminders_window_bg = ColorFrame(
            frame_color, CONFIG.get('Reminders', 'window_bg'), _('Background'))
        self.reminders_window_bg.pack(side='left', padx=(0, 4))
        self.reminders_window_fg = ColorFrame(
            frame_color, CONFIG.get('Reminders', 'window_fg'), _('Foreground'))
        self.reminders_window_fg.pack(side='left', padx=(4, 0))
        # --- --- opacity
        self.reminders_opacity = OpacityFrame(frame_window,
                                              CONFIG.getfloat('Reminders',
                                                              'window_alpha',
                                                              fallback=0.75),
                                              style='TLabel')
        self.reminders_opacity.grid(sticky='w', padx=(16, 4), pady=4)

        ttk.Separator(frame_window, orient='horizontal').grid(sticky='ew',
                                                              padx=(16, 10),
                                                              pady=10)

        # --- --- blink
        frame_blink = ttk.Frame(frame_window)
        frame_blink.grid(sticky='w', padx=(16, 4), pady=4)

        def toggle_blink():
            b = 'selected' in self.reminders_blink.state()
            state = [b * '!' + 'disabled']
            self.reminders_window_bg_alt.state(state)
            self.reminders_window_fg_alt.state(state)

        self.reminders_blink = ttk.Checkbutton(frame_blink,
                                               text=_('Blink'),
                                               command=toggle_blink)
        self.reminders_blink.pack(anchor='nw')
        self.reminders_blink.state(
            ('!alternate',
             '!' * (not CONFIG.getboolean('Reminders', 'blink')) + 'selected'))
        self.reminders_window_bg_alt = ColorFrame(
            frame_blink, CONFIG.get('Reminders', 'window_bg_alternate'),
            _('Alternate Background'))
        self.reminders_window_bg_alt.pack(side='left', padx=(16, 4))
        self.reminders_window_fg_alt = ColorFrame(
            frame_blink, CONFIG.get('Reminders', 'window_fg_alternate'),
            _('Alternate Foreground'))
        self.reminders_window_fg_alt.pack(side='left', padx=10)
        toggle_blink()

        ttk.Separator(frame_window, orient='horizontal').grid(sticky='ew',
                                                              padx=(16, 10),
                                                              pady=10)
        # --- --- alarm

        self.reminders_sound = SoundFrame(frame_window,
                                          CONFIG.get('Reminders', 'alarm'),
                                          CONFIG.get('Reminders', 'mute'),
                                          _('Alarm'))
        self.reminders_sound.grid(sticky='ew', padx=(16, 10), pady=4)

        # --- notif
        frame_notif = ttk.Frame(self.frames[_('Reminders')])
        self.reminders_notif = ttk.Checkbutton(frame_notif,
                                               text=_('Notification'),
                                               style='title.TCheckbutton')
        self.reminders_notif.grid(sticky='w', pady=4)
        self.reminders_notif.state(
            ('!alternate',
             '!' * (not CONFIG.getboolean('Reminders', 'notification')) +
             'selected'))

        # --- placement
        frame_window.pack(anchor='nw', fill='x')
        ttk.Separator(self.frames[_('Reminders')],
                      orient='horizontal').pack(fill='x', pady=10)
        frame_notif.pack(anchor='nw')
Exemple #8
0
    def _init_general(self):
        self.frames[_('General')].columnconfigure(0, weight=1)
        # --- variables
        self.gui = tk.StringVar(self,
                                CONFIG.get("General", "trayicon").capitalize())
        self.lang = tk.StringVar(self,
                                 LANGUAGES[CONFIG.get("General", "language")])

        # --- Langue
        lang_frame = ttk.Frame(self.frames[_('General')])

        ttk.Label(lang_frame, text=_("Language")).pack(side="left")
        languages = list(REV_LANGUAGES)
        self.cb_lang = ttk.Combobox(lang_frame,
                                    textvariable=self.lang,
                                    state='readonly',
                                    style='menu.TCombobox',
                                    exportselection=False,
                                    width=len(max(languages, key=len)) + 1,
                                    values=languages)
        self.cb_lang.pack(side="left", padx=4)
        self.cb_lang.bind('<<ComboboxSelected>>', self.change_langue)
        # --- gui toolkit
        frame_gui = ttk.Frame(self.frames[_('General')])
        ttk.Label(
            frame_gui,
            text=_("GUI Toolkit for the system tray icon")).pack(side="left")
        self.cb_gui = ttk.Combobox(
            frame_gui,
            textvariable=self.gui,
            state='readonly',
            style='menu.TCombobox',
            exportselection=False,
            width=4,
            values=[t.capitalize() for (t, b) in TOOLKITS.items() if b])
        self.cb_gui.pack(side="left", padx=4)
        self.cb_gui.bind('<<ComboboxSelected>>', self.change_gui)
        # --- Update checks
        # self.confirm_update = ttk.Checkbutton(self.frames[_('General')],
        # text=_("Check for updates on start-up"))
        # if CONFIG.getboolean('General', 'check_update', fallback=True):
        # self.confirm_update.state(('selected', '!alternate'))
        # else:
        # self.confirm_update.state(('!selected', '!alternate'))

        # --- eyes
        frame_eyes = ttk.Frame(self.frames[_('General')])
        ttk.Label(frame_eyes, text=_("Eyes' rest"),
                  style='title.TLabel').grid(sticky='w', padx=4, pady=4)
        ttk.Label(frame_eyes,
                  text=_("Interval between two eyes' rest (min)")).grid(
                      row=1, column=0, sticky='w', padx=4, pady=4)
        self.eyes_interval = ttk.Entry(frame_eyes,
                                       width=4,
                                       justify='center',
                                       validate='key',
                                       validatecommand=(self._only_nb, '%P'))
        self.eyes_interval.insert(
            0, CONFIG.get("General", "eyes_interval", fallback='20'))
        self.eyes_interval.grid(row=1, column=1, sticky='w', padx=4, pady=4)

        # --- Splash supported
        self.splash_support = ttk.Checkbutton(
            self.frames[_('General')],
            text=_("Check this box if the widgets disappear when you click"))
        if not CONFIG.getboolean('General', 'splash_supported', fallback=True):
            self.splash_support.state(('selected', '!alternate'))
        else:
            self.splash_support.state(('!selected', '!alternate'))

        # --- Maintenance
        frame_maintenance = ttk.Frame(self.frames[_('General')])
        ttk.Label(frame_maintenance,
                  text=_("Maintenance"),
                  style='title.TLabel').grid(sticky='w', padx=4, pady=4)
        ttk.Label(frame_maintenance,
                  text=_("Delete all outdated events")).grid(row=1,
                                                             column=0,
                                                             sticky='w',
                                                             padx=4,
                                                             pady=4)
        ttk.Button(frame_maintenance,
                   image=self._im_cleanup,
                   padding=1,
                   command=self.cleanup).grid(row=1,
                                              column=1,
                                              sticky='w',
                                              padx=4,
                                              pady=4)
        ttk.Label(
            frame_maintenance,
            text=
            _("Refresh scheduled reminders\n(needed after APScheduler's updates)"
              )).grid(row=2, column=0, sticky='w', padx=4, pady=4)
        ttk.Button(frame_maintenance,
                   image=self._im_refresh,
                   padding=1,
                   command=self.refresh).grid(row=2,
                                              column=1,
                                              sticky='w',
                                              padx=4,
                                              pady=4)

        # --- placement
        ttk.Label(self.frames[_('General')],
                  text=_("Interface"),
                  style='title.TLabel').grid(sticky='w', pady=4)
        lang_frame.grid(pady=4, sticky="ew")
        frame_gui.grid(pady=4, sticky="ew")
        # self.confirm_update.grid(pady=4, sticky='w')
        self.splash_support.grid(pady=4, sticky='w')
        ttk.Separator(self.frames[_('General')],
                      orient='horizontal').grid(sticky='ew', pady=10)
        frame_eyes.grid(pady=4, sticky="ew")
        ttk.Separator(self.frames[_('General')],
                      orient='horizontal').grid(sticky='ew', pady=10)
        frame_maintenance.grid(pady=4, sticky="ew")
Exemple #9
0
    def __init__(self, parent, **options):
        """ créer le Toplevel permettant de modifier les paramètres """
        Frame.__init__(self, parent, **options)

        self.onglets = Notebook(self)
        self.onglets.pack(fill='both', expand=True)
        self.im_color = PhotoImage(master=self, file=IM_COLOR)
        self.im_plus = PhotoImage(master=self, file=IM_ADD)
        self.im_moins = PhotoImage(master=self, file=IM_DEL)

        self.okfct = self.register(only_nb)

        self.style = Style(self)

        self.nb_task = len(CONFIG.options("PomodoroTasks"))

        # --- Général (temps, police et langue)
        self.general = Frame(self.onglets, padding=10)
        self.general.columnconfigure(1, weight=1)
        self.onglets.add(self.general, text=_("General"))

        # --- --- Temps
        Label(self.general, text=_("Times (min)"),
              style='title.TLabel').grid(row=0,
                                         pady=4,
                                         padx=(2, 10),
                                         sticky="w")
        self.time_frame = Frame(self.general)
        self.time_frame.grid(row=0, column=1, sticky="w", padx=4)
        Label(self.time_frame, text=_("Work")).grid(row=0, padx=4, column=0)
        self.travail = Entry(self.time_frame,
                             width=4,
                             justify='center',
                             validatecommand=(self.okfct, '%P'),
                             validate='key')
        self.travail.insert(0, CONFIG.get("Pomodoro", "work_time"))
        self.travail.grid(row=0, column=1, padx=(0, 10))
        Label(self.time_frame, text=_("Break")).grid(row=0, column=2, padx=4)
        self.pause = Entry(self.time_frame,
                           width=4,
                           justify='center',
                           validatecommand=(self.okfct, '%P'),
                           validate='key')
        self.pause.insert(0, CONFIG.get("Pomodoro", "break_time"))
        self.pause.grid(row=0, column=3, padx=(0, 10))
        Label(self.time_frame, text=_("Rest")).grid(row=0, column=4, padx=4)
        self.rest = Entry(self.time_frame,
                          width=4,
                          justify='center',
                          validatecommand=(self.okfct, '%P'),
                          validate='key')
        self.rest.insert(0, CONFIG.get("Pomodoro", "rest_time"))
        self.rest.grid(row=0, column=5)

        Separator(self.general, orient='horizontal').grid(row=1,
                                                          columnspan=2,
                                                          sticky="ew",
                                                          pady=10)

        # --- --- Police
        Label(self.general, text=_("Font"),
              style='title.TLabel').grid(row=2, sticky='nw', padx=(2, 10))
        self.font = FontFrame(self.general,
                              font=CONFIG.get('Pomodoro', 'font'),
                              sample_text="02:17")
        self.font.grid(row=2, column=1, padx=4, sticky='w')

        Separator(self.general, orient='horizontal').grid(row=3,
                                                          columnspan=2,
                                                          sticky="ew",
                                                          pady=10)

        # --- --- Opacity
        self.opacity = OpacityFrame(self.general)
        self.opacity.grid(row=5, columnspan=2, sticky='w', padx=(2, 4), pady=4)

        Separator(self.general, orient='horizontal').grid(row=6,
                                                          columnspan=2,
                                                          sticky="ew",
                                                          pady=10)

        # --- --- Son
        self.sound = SoundFrame(self.general,
                                CONFIG.get("Pomodoro", "beep"),
                                mute=CONFIG.getboolean("Pomodoro", "mute"),
                                label=_("Sound"),
                                style='title.TLabel')
        self.sound.grid(row=7, columnspan=2, sticky='ew', pady=4)

        # --- Couleurs
        self.couleurs = Frame(self.onglets, padding=10)
        self.couleurs.columnconfigure(3, weight=1)
        self.onglets.add(self.couleurs, text=_("Colors"))

        self.bg = ColorFrame(self.couleurs, CONFIG.get("Pomodoro",
                                                       "background"),
                             _("Background"))
        self.work_bg = ColorFrame(self.couleurs,
                                  CONFIG.get("Pomodoro", "work_bg"),
                                  _("Background"))
        self.break_bg = ColorFrame(self.couleurs,
                                   CONFIG.get("Pomodoro", "break_bg"),
                                   _("Background"))
        self.rest_bg = ColorFrame(self.couleurs,
                                  CONFIG.get("Pomodoro", "rest_bg"),
                                  _("Background"))
        self.fg = ColorFrame(self.couleurs, CONFIG.get("Pomodoro",
                                                       "foreground"),
                             _("Foreground"))
        self.work_fg = ColorFrame(self.couleurs,
                                  CONFIG.get("Pomodoro", "work_fg"),
                                  _("Foreground"))
        self.break_fg = ColorFrame(self.couleurs,
                                   CONFIG.get("Pomodoro", "break_fg"),
                                   _("Foreground"))
        self.rest_fg = ColorFrame(self.couleurs,
                                  CONFIG.get("Pomodoro", "rest_fg"),
                                  _("Foreground"))

        Label(self.couleurs, text=_("General"),
              style='title.TLabel').grid(row=0,
                                         column=0,
                                         pady=4,
                                         padx=(2, 10),
                                         sticky="w")
        self.bg.grid(row=0, column=1, sticky='e', padx=8, pady=4)
        self.fg.grid(row=0, column=2, sticky='e', padx=8, pady=4)
        Separator(self.couleurs, orient='horizontal').grid(row=1,
                                                           sticky="ew",
                                                           pady=10,
                                                           columnspan=4)
        Label(self.couleurs, text=_("Work"),
              style='title.TLabel').grid(row=2,
                                         column=0,
                                         pady=4,
                                         padx=(2, 10),
                                         sticky="w")
        self.work_bg.grid(row=2, column=1, sticky='e', padx=8, pady=4)
        self.work_fg.grid(row=2, column=2, sticky='e', padx=8, pady=4)
        Separator(self.couleurs, orient='horizontal').grid(row=3,
                                                           sticky="ew",
                                                           pady=10,
                                                           columnspan=4)
        Label(self.couleurs, text=_("Break"),
              style='title.TLabel').grid(row=4,
                                         column=0,
                                         pady=4,
                                         padx=(2, 10),
                                         sticky="w")
        self.break_bg.grid(row=4, column=1, sticky='e', padx=8, pady=4)
        self.break_fg.grid(row=4, column=2, sticky='e', padx=8, pady=4)
        Separator(self.couleurs, orient='horizontal').grid(row=5,
                                                           sticky="ew",
                                                           pady=10,
                                                           columnspan=4)
        Label(self.couleurs, text=_("Rest"),
              style='title.TLabel').grid(row=6,
                                         column=0,
                                         pady=4,
                                         padx=(2, 10),
                                         sticky="w")
        self.rest_bg.grid(row=6, column=1, sticky='e', padx=8, pady=4)
        self.rest_fg.grid(row=6, column=2, sticky='e', padx=8, pady=4)

        # --- Tasks
        self.stats = Frame(self.onglets, padding=10)
        self.stats.columnconfigure(0, weight=1)
        self.stats.rowconfigure(2, weight=1)
        self.onglets.add(self.stats, text=_("Tasks"))
        # graph legend
        legend_frame = Frame(self.stats)
        Label(legend_frame,
              style='title.TLabel',
              text=_('Maximum number of rows in the legend')).pack(side='left')
        self.legend_row_nb = Entry(legend_frame,
                                   width=4,
                                   justify='center',
                                   validatecommand=(self.okfct, '%P'),
                                   validate='key')
        self.legend_row_nb.insert(
            0, CONFIG.get('Pomodoro', 'legend_max_height', fallback='6'))
        self.legend_row_nb.pack(side='left', padx=4)

        # task colors
        can = Canvas(self.stats,
                     bg=self.style.lookup('TFrame', 'background'),
                     highlightthickness=0,
                     width=1,
                     relief='flat')
        scroll = AutoScrollbar(self.stats,
                               orient='vertical',
                               command=can.yview)
        can.configure(yscrollcommand=scroll.set)
        self.task_frame = Frame(can)
        can.create_window(0, 0, anchor='nw', window=self.task_frame)

        tasks = CONFIG.options("PomodoroTasks")
        tasks.sort()
        cmap = [CONFIG.get("PomodoroTasks", task) for task in tasks]
        self.tasks = {}
        self._tasks_btns = {}
        for i, (coul, task) in enumerate(zip(cmap, tasks)):
            self.tasks[task] = ColorFrame(self.task_frame, coul,
                                          task.capitalize())
            self.tasks[task].grid(row=i, column=0, sticky='e', padx=4, pady=4)
            b = Button(self.task_frame,
                       image=self.im_moins,
                       padding=2,
                       command=lambda t=task: self.del_task(t))
            b.grid(row=i, column=1, sticky='w', padx=4, pady=4)
            self._tasks_btns[task] = b
        if len(tasks) == 1:
            self._tasks_btns[tasks[0]].state(['disabled'])

        legend_frame.grid(row=0, columnspan=2, sticky='w', pady=4)
        Label(self.stats,
              text=_('Colors in the statistic graph'),
              style='title.TLabel').grid(row=1, column=0, sticky='w', pady=4)
        can.grid(row=2, column=0, sticky='ewns')
        scroll.grid(row=2, column=1, sticky='ns')
        Button(self.stats, image=self.im_plus,
               command=self.add_task).grid(row=3, column=0, sticky='w')

        self.update_idletasks()
        can.configure(width=self.task_frame.winfo_reqwidth())
        can.configure(scrollregion=can.bbox('all'))
        can.bind('<4>', lambda e: self._scroll(e, -1))
        can.bind('<5>', lambda e: self._scroll(e, 1))
        self.task_frame.bind(
            '<Configure>',
            lambda e: can.configure(scrollregion=can.bbox('all')))