Exemplo n.º 1
0
    def GetFont(self, root, configType, section):
        """Retrieve a font from configuration (font, font-size, font-bold)
        Intercept the special value 'TkFixedFont' and substitute
        the actual font, factoring in some tweaks if needed for
        appearance sakes.

        The 'root' parameter can normally be any valid Tkinter widget.

        Return a tuple (family, size, weight) suitable for passing
        to tkinter.Font
        """
        family = self.GetOption(configType, section, 'font', default='courier')
        size = self.GetOption(configType, section, 'font-size', type='int',
                              default='10')
        bold = self.GetOption(configType, section, 'font-bold', default=0,
                              type='bool')
        if (family == 'TkFixedFont'):
            f = Font(name='TkFixedFont', exists=True, root=root)
            actualFont = Font.actual(f)
            family = actualFont['family']
            size = actualFont['size']
            if size <= 0:
                size = 10  # if font in pixels, ignore actual size
            bold = actualFont['weight'] == 'bold'
        return (family, size, 'bold' if bold else 'normal')
Exemplo n.º 2
0
    def GetFont(self, root, configType, section):
        """Retrieve a font from configuration (font, font-size, font-bold)
        Intercept the special value 'TkFixedFont' and substitute
        the actual font, factoring in some tweaks if needed for
        appearance sakes.

        The 'root' parameter can normally be any valid Tkinter widget.

        Return a tuple (family, size, weight) suitable for passing
        to tkinter.Font
        """
        family = self.GetOption(configType, section, 'font', default='courier')
        size = self.GetOption(configType,
                              section,
                              'font-size',
                              type='int',
                              default='10')
        bold = self.GetOption(configType,
                              section,
                              'font-bold',
                              default=0,
                              type='bool')
        if (family == 'TkFixedFont'):
            f = Font(name='TkFixedFont', exists=True, root=root)
            actualFont = Font.actual(f)
            family = actualFont['family']
            size = actualFont['size']
            if size <= 0:
                size = 10  # if font in pixels, ignore actual size
            bold = actualFont['weight'] == 'bold'
        return (family, size, 'bold' if bold else 'normal')
Exemplo n.º 3
0
    def GetFont(self, root, configType, section):
        """Retrieve a font from configuration (font, font-size, font-bold)
        Intercept the special value 'TkFixedFont' and substitute
        the actual font, factoring in some tweaks if needed for
        appearance sakes.

        The 'root' parameter can normally be any valid Tkinter widget.

        Return a tuple (family, size, weight) suitable for passing
        to tkinter.Font
        """
        family = self.GetOption(configType, section, "font", default="courier")
        size = self.GetOption(configType, section, "font-size", type="int", default="10")
        bold = self.GetOption(configType, section, "font-bold", default=0, type="bool")
        if family == "TkFixedFont":
            if TkVersion < 8.5:
                family = "Courier"
            else:
                f = Font(name="TkFixedFont", exists=True, root=root)
                actualFont = Font.actual(f)
                family = actualFont["family"]
                size = actualFont["size"]
                if size < 0:
                    size = 10  # if font in pixels, ignore actual size
                bold = actualFont["weight"] == "bold"
        return (family, size, "bold" if bold else "normal")
Exemplo n.º 4
0
 def configure(self, **kwargs):
     if 'text' in kwargs:
         self.label.configure(text=kwargs.pop('text'))
     if 'image' in kwargs:
         self.label.configure(image=kwargs.pop('image'))
     if 'background' in kwargs:
         self.style.configure('tooltip.TLabel',
                              background=kwargs['background'])
     if 'foreground' in kwargs:
         fg = kwargs.pop('foreground')
         self.style.configure('tooltip.TLabel', foreground=fg)
     if 'alpha' in kwargs:
         self.attributes('-alpha', kwargs.pop('alpha'))
     if 'font' in kwargs:
         font = Font(self, kwargs.pop('font'))
         self.font.configure(**font.actual())
     Toplevel.configure(self, **kwargs)
Exemplo n.º 5
0
    def test_get_font(self):
        from test.support import requires
        from tkinter import Tk
        from tkinter.font import Font
        conf = self.mock_config()

        requires('gui')
        root = Tk()
        root.withdraw()

        f = Font.actual(Font(name='TkFixedFont', exists=True, root=root))
        self.assertEqual(
            conf.GetFont(root, 'main', 'EditorWindow'),
            (f['family'], 10 if f['size'] <= 0 else f['size'], f['weight']))

        # Cleanup root
        root.destroy()
        del root
Exemplo n.º 6
0
class Calendar(ttk.Frame):
    """Calendar widget."""
    date = calendar.datetime.date
    timedelta = calendar.datetime.timedelta
    strptime = calendar.datetime.datetime.strptime
    strftime = calendar.datetime.datetime.strftime

    def __init__(self, master=None, **kw):
        """
        Construct a Calendar with parent master.

        STANDARD OPTIONS

            cursor, font, borderwidth, state

        WIDGET-SPECIFIC OPTIONS

            year, month: initially displayed month, default is current month
            day: initially selected day, if month or year is given but not
                day, no initial selection, otherwise, default is today
            locale: locale to use, e.g. 'fr_FR'
            selectmode: "none" or "day" (default) define whether the user
                        can change the selected day with a mouse click
            showweeknumbers: boolean (default is True) to show/hide week numbers
            textvariable: StringVar that will contain the currently selected date as str
            background: background color of calendar border and month/year name
            foreground: foreground color of month/year name
            bordercolor: day border color
            selectbackground: background color of selected day
            selectforeground: foreground color of selected day
            disabledselectbackground: background color of selected day in disabled state
            disabledselectforeground: foreground color of selected day in disabled state
            normalbackground: background color of normal week days
            normalforeground: foreground color of normal week days
            othermonthforeground: foreground color of normal week days
                                  belonging to the previous/next month
            othermonthbackground: background color of normal week days
                                  belonging to the previous/next month
            othermonthweforeground: foreground color of week-end days
                                    belonging to the previous/next month
            othermonthwebackground: background color of week-end days
                                    belonging to the previous/next month
            weekendbackground: background color of week-end days
            weekendforeground: foreground color of week-end days
            headersbackground: background color of day names and week numbers
            headersforeground: foreground color of day names and week numbers
            disableddaybackground: background color of days in disabled state
            disableddayforeground: foreground color of days in disabled state

        VIRTUAL EVENTS

            A <<CalendarSelected>> event is generated each time the user
            selects a day with the mouse.
        """

        curs = kw.pop("cursor", "")
        font = kw.pop("font", "Liberation\ Sans 9")
        classname = kw.pop('class_', "Calendar")
        name = kw.pop('name', None)
        ttk.Frame.__init__(self, master, class_=classname, cursor=curs, name=name)
        self._style_prefixe = str(self)
        ttk.Frame.configure(self, style='main.%s.TFrame' % self._style_prefixe)

        self._textvariable = kw.pop("textvariable", None)

        self._font = Font(self, font)
        prop = self._font.actual()
        prop["size"] += 1
        self._header_font = Font(self, **prop)

        # state
        state = kw.get('state', 'normal')

        try:
            bd = int(kw.pop('borderwidth', 2))
        except ValueError:
            raise ValueError('expected integer for the borderwidth option.')

        self._cal = calendar.TextCalendar(calendar.MONDAY)

        # --- locale
        locale = kw.pop("locale", getdefaultlocale()[0])
        self._day_names = get_day_names('abbreviated', locale=locale)
        self._month_names = get_month_names('wide', locale=locale)

        # --- date
        today = self.date.today()

        if (("month" in kw) or ("year" in kw)) and ("day" not in kw):
            month = kw.pop("month", today.month)
            year = kw.pop('year', today.year)
            self._sel_date = None  # selected day
        else:
            day = kw.pop('day', today.day)
            month = kw.pop("month", today.month)
            year = kw.pop('year', today.year)
            try:
                self._sel_date = self.date(year, month, day)  # selected day
                if self._textvariable is not None:
                    self._textvariable.set(format_date(self._sel_date, 'short', locale))
            except ValueError:
                self._sel_date = None

        self._date = self.date(year, month, 1)  # (year, month) displayed by the calendar

        # --- selectmode
        selectmode = kw.pop("selectmode", "day")
        if selectmode not in ("none", "day"):
            raise ValueError("'selectmode' option should be 'none' or 'day'.")
        # --- show week numbers
        showweeknumbers = kw.pop('showweeknumbers', True)

        # --- style
        self.style = ttk.Style(self)
        active_bg = self.style.lookup('TEntry', 'selectbackground', ('focus',))
        dis_active_bg = self.style.lookup('TEntry', 'selectbackground', ('disabled',))
        dis_bg = self.style.lookup('TLabel', 'background', ('disabled',))
        dis_fg = self.style.lookup('TLabel', 'foreground', ('disabled',))

        # --- properties
        options = ['cursor',
                   'font',
                   'borderwidth',
                   'state',
                   'selectmode',
                   'textvariable',
                   'locale',
                   'showweeknumbers',
                   'selectbackground',
                   'selectforeground',
                   'disabledselectbackground',
                   'disabledselectforeground',
                   'normalbackground',
                   'normalforeground',
                   'background',
                   'foreground',
                   'bordercolor',
                   'othermonthforeground',
                   'othermonthbackground',
                   'othermonthweforeground',
                   'othermonthwebackground',
                   'weekendbackground',
                   'weekendforeground',
                   'headersbackground',
                   'headersforeground',
                   'disableddaybackground',
                   'disableddayforeground']

        keys = list(kw.keys())
        for option in keys:
            if option not in options:
                del(kw[option])

        self._properties = {"cursor": curs,
                            "font": font,
                            "borderwidth": bd,
                            "state": state,
                            "locale": locale,
                            "selectmode": selectmode,
                            'textvariable': self._textvariable,
                            'showweeknumbers': showweeknumbers,
                            'selectbackground': active_bg,
                            'selectforeground': 'white',
                            'disabledselectbackground': dis_active_bg,
                            'disabledselectforeground': 'white',
                            'normalbackground': 'white',
                            'normalforeground': 'black',
                            'background': 'gray30',
                            'foreground': 'white',
                            'bordercolor': 'gray70',
                            'othermonthforeground': 'gray45',
                            'othermonthbackground': 'gray93',
                            'othermonthweforeground': 'gray45',
                            'othermonthwebackground': 'gray75',
                            'weekendbackground': 'gray80',
                            'weekendforeground': 'gray30',
                            'headersbackground': 'gray70',
                            'headersforeground': 'black',
                            'disableddaybackground': dis_bg,
                            'disableddayforeground': dis_fg}
        self._properties.update(kw)

        # --- init calendar
        # --- *-- header: month - year
        header = ttk.Frame(self, style='main.%s.TFrame' % self._style_prefixe)

        f_month = ttk.Frame(header,
                            style='main.%s.TFrame' % self._style_prefixe)
        self._l_month = ttk.Button(f_month,
                                   style='L.%s.TButton' % self._style_prefixe,
                                   command=self._prev_month)
        self._header_month = ttk.Label(f_month, width=10, anchor='center',
                                       style='main.%s.TLabel' % self._style_prefixe, font=self._header_font)
        self._r_month = ttk.Button(f_month,
                                   style='R.%s.TButton' % self._style_prefixe,
                                   command=self._next_month)
        self._l_month.pack(side='left', fill="y")
        self._header_month.pack(side='left', padx=4)
        self._r_month.pack(side='left', fill="y")

        f_year = ttk.Frame(header, style='main.%s.TFrame' % self._style_prefixe)
        self._l_year = ttk.Button(f_year, style='L.%s.TButton' % self._style_prefixe,
                                  command=self._prev_year)
        self._header_year = ttk.Label(f_year, width=4, anchor='center',
                                      style='main.%s.TLabel' % self._style_prefixe, font=self._header_font)
        self._r_year = ttk.Button(f_year, style='R.%s.TButton' % self._style_prefixe,
                                  command=self._next_year)
        self._l_year.pack(side='left', fill="y")
        self._header_year.pack(side='left', padx=4)
        self._r_year.pack(side='left', fill="y")

        f_month.pack(side='left', fill='x')
        f_year.pack(side='right')

        # --- *-- calendar
        self._cal_frame = ttk.Frame(self,
                                    style='cal.%s.TFrame' % self._style_prefixe)

        ttk.Label(self._cal_frame,
                  style='headers.%s.TLabel' % self._style_prefixe).grid(row=0,
                                                                        column=0,
                                                                        sticky="eswn")

        for i in range(7):
            d = self._day_names[i]
            self._cal_frame.columnconfigure(i + 1, weight=1)
            ttk.Label(self._cal_frame,
                      font=self._font,
                      style='headers.%s.TLabel' % self._style_prefixe,
                      anchor="center",
                      text=d, width=4).grid(row=0, column=i + 1,
                                            sticky="ew", pady=(0, 1))
        self._week_nbs = []
        self._calendar = []
        for i in range(1, 7):
            self._cal_frame.rowconfigure(i, weight=1)
            wlabel = ttk.Label(self._cal_frame, style='headers.%s.TLabel' % self._style_prefixe,
                               font=self._font, padding=2,
                               anchor="e", width=2)
            self._week_nbs.append(wlabel)
            wlabel.grid(row=i, column=0, sticky="esnw", padx=(0, 1))
            if not showweeknumbers:
                wlabel.grid_remove()
            self._calendar.append([])
            for j in range(1, 8):
                label = ttk.Label(self._cal_frame, style='normal.%s.TLabel' % self._style_prefixe,
                                  font=self._font, anchor="center")
                self._calendar[-1].append(label)
                label.grid(row=i, column=j, padx=(0, 1), pady=(0, 1), sticky="nsew")
                if selectmode is "day":
                    label.bind("<1>", self._on_click)

        # --- *-- pack main elements
        header.pack(fill="x", padx=2, pady=2)
        self._cal_frame.pack(fill="both", expand=True, padx=bd, pady=bd)

        self.config(state=state)

        # --- bindings
        self.bind('<<ThemeChanged>>', self._setup_style)

        self._setup_style()
        self._display_calendar()

        if self._textvariable is not None:
            try:
                self._textvariable_trace_id = self._textvariable.trace_add('write', self._textvariable_trace)
            except AttributeError:
                self._textvariable_trace_id = self._textvariable.trace('w', self._textvariable_trace)

    def __getitem__(self, key):
        """Return the resource value for a KEY given as string."""
        try:
            return self._properties[key]
        except KeyError:
            raise AttributeError("Calendar object has no attribute %s." % key)

    def __setitem__(self, key, value):
        if key not in self._properties:
            raise AttributeError("Calendar object has no attribute %s." % key)
        elif key is "locale":
            raise AttributeError("This attribute cannot be modified.")
        else:
            if key is "selectmode":
                if value is "none":
                    for week in self._calendar:
                        for day in week:
                            day.unbind("<1>")
                elif value is "day":
                    for week in self._calendar:
                        for day in week:
                            day.bind("<1>", self._on_click)
                else:
                    raise ValueError("'selectmode' option should be 'none' or 'day'.")
            elif key is 'textvariable':
                if self._sel_date is not None:
                    if value is not None:
                        value.set(self.format_date(self._sel_date))
                    try:
                        if self._textvariable is not None:
                            self._textvariable.trace_remove('write', self._textvariable_trace_id)
                        if value is not None:
                            self._textvariable_trace_id = value.trace_add('write', self._textvariable_trace)
                    except AttributeError:
                        if self._textvariable is not None:
                            self._textvariable.trace_vdelete('w', self._textvariable_trace_id)
                        if value is not None:
                            value.trace('w', self._textvariable_trace)
                self._textvariable = value
            elif key is 'showweeknumbers':
                if value:
                    for wlabel in self._week_nbs:
                        wlabel.grid()
                else:
                    for wlabel in self._week_nbs:
                        wlabel.grid_remove()
            elif key is 'borderwidth':
                try:
                    bd = int(value)
                    self._cal_frame.pack_configure(padx=bd, pady=bd)
                except ValueError:
                    raise ValueError('expected integer for the borderwidth option.')
            elif key is 'state':
                if value not in ['normal', 'disabled']:
                    raise ValueError("bad state '%s': must be disabled or normal" % value)
                else:
                    state = '!' * (value == 'normal') + 'disabled'
                    self._l_year.state((state,))
                    self._r_year.state((state,))
                    self._l_month.state((state,))
                    self._r_month.state((state,))
                    for child in self._cal_frame.children.values():
                        child.state((state,))
            elif key is "font":
                font = Font(self, value)
                prop = font.actual()
                self._font.configure(**prop)
                prop["size"] += 1
                self._header_font.configure(**prop)
                size = max(prop["size"], 10)
                self.style.configure('R.%s.TButton' % self._style_prefixe, arrowsize=size)
                self.style.configure('L.%s.TButton' % self._style_prefixe, arrowsize=size)
            elif key is "normalbackground":
                self.style.configure('cal.%s.TFrame' % self._style_prefixe, background=value)
                self.style.configure('normal.%s.TLabel' % self._style_prefixe, background=value)
                self.style.configure('normal_om.%s.TLabel' % self._style_prefixe, background=value)
            elif key is "normalforeground":
                self.style.configure('normal.%s.TLabel' % self._style_prefixe, foreground=value)
            elif key is "bordercolor":
                self.style.configure('cal.%s.TFrame' % self._style_prefixe, background=value)
            elif key is "othermonthforeground":
                self.style.configure('normal_om.%s.TLabel' % self._style_prefixe, foreground=value)
            elif key is "othermonthbackground":
                self.style.configure('normal_om.%s.TLabel' % self._style_prefixe, background=value)
            elif key is "othermonthweforeground":
                self.style.configure('we_om.%s.TLabel' % self._style_prefixe, foreground=value)
            elif key is "othermonthwebackground":
                self.style.configure('we_om.%s.TLabel' % self._style_prefixe, background=value)
            elif key is "selectbackground":
                self.style.configure('sel.%s.TLabel' % self._style_prefixe, background=value)
            elif key is "selectforeground":
                self.style.configure('sel.%s.TLabel' % self._style_prefixe, foreground=value)
            elif key is "disabledselectbackground":
                self.style.map('sel.%s.TLabel' % self._style_prefixe, background=[('disabled', value)])
            elif key is "disabledselectforeground":
                self.style.map('sel.%s.TLabel' % self._style_prefixe, foreground=[('disabled', value)])
            elif key is "disableddaybackground":
                self.style.map('%s.TLabel' % self._style_prefixe, background=[('disabled', value)])
            elif key is "disableddayforeground":
                self.style.map('%s.TLabel' % self._style_prefixe, foreground=[('disabled', value)])
            elif key is "weekendbackground":
                self.style.configure('we.%s.TLabel' % self._style_prefixe, background=value)
                self.style.configure('we_om.%s.TLabel' % self._style_prefixe, background=value)
            elif key is "weekendforeground":
                self.style.configure('we.%s.TLabel' % self._style_prefixe, foreground=value)
            elif key is "headersbackground":
                self.style.configure('headers.%s.TLabel' % self._style_prefixe, background=value)
            elif key is "headersforeground":
                self.style.configure('headers.%s.TLabel' % self._style_prefixe, foreground=value)
            elif key is "background":
                self.style.configure('main.%s.TFrame' % self._style_prefixe, background=value)
                self.style.configure('main.%s.TLabel' % self._style_prefixe, background=value)
                self.style.configure('R.%s.TButton' % self._style_prefixe, background=value,
                                     bordercolor=value,
                                     lightcolor=value, darkcolor=value)
                self.style.configure('L.%s.TButton' % self._style_prefixe, background=value,
                                     bordercolor=value,
                                     lightcolor=value, darkcolor=value)
            elif key is "foreground":
                self.style.configure('R.%s.TButton' % self._style_prefixe, arrowcolor=value)
                self.style.configure('L.%s.TButton' % self._style_prefixe, arrowcolor=value)
                self.style.configure('main.%s.TLabel' % self._style_prefixe, foreground=value)
            elif key is "cursor":
                ttk.Frame.configure(self, cursor=value)
            self._properties[key] = value

    def _textvariable_trace(self, *args):
        if self._properties.get("selectmode") is "day":
            date = self._textvariable.get()
            if not date:
                self._remove_selection()
                self._sel_date = None
            else:
                try:
                    self._sel_date = self.parse_date(date)
                except Exception:
                    if self._sel_date is None:
                        self._textvariable.set('')
                    else:
                        self._textvariable.set(self.format_date(self._sel_date))
                    raise ValueError("%r is not a valid date." % date)
                else:
                    self._date = self._sel_date.replace(day=1)
                    self._display_calendar()
                    self._display_selection()

    def _setup_style(self, event=None):
        """Configure style."""
        self.style.layout('L.%s.TButton' % self._style_prefixe,
                          [('Button.focus',
                            {'children': [('Button.leftarrow', None)]})])
        self.style.layout('R.%s.TButton' % self._style_prefixe,
                          [('Button.focus',
                            {'children': [('Button.rightarrow', None)]})])
        active_bg = self.style.lookup('TEntry', 'selectbackground', ('focus',))

        sel_bg = self._properties.get('selectbackground')
        sel_fg = self._properties.get('selectforeground')
        dis_sel_bg = self._properties.get('disabledselectbackground')
        dis_sel_fg = self._properties.get('disabledselectforeground')
        dis_bg = self._properties.get('disableddaybackground')
        dis_fg = self._properties.get('disableddayforeground')
        cal_bg = self._properties.get('normalbackground')
        cal_fg = self._properties.get('normalforeground')
        hd_bg = self._properties.get("headersbackground")
        hd_fg = self._properties.get("headersforeground")
        bg = self._properties.get('background')
        fg = self._properties.get('foreground')
        bc = self._properties.get('bordercolor')
        om_fg = self._properties.get('othermonthforeground')
        om_bg = self._properties.get('othermonthbackground')
        omwe_fg = self._properties.get('othermonthweforeground')
        omwe_bg = self._properties.get('othermonthwebackground')
        we_bg = self._properties.get('weekendbackground')
        we_fg = self._properties.get('weekendforeground')

        self.style.configure('main.%s.TFrame' % self._style_prefixe, background=bg)
        self.style.configure('cal.%s.TFrame' % self._style_prefixe, background=bc)
        self.style.configure('main.%s.TLabel' % self._style_prefixe, background=bg, foreground=fg)
        self.style.configure('headers.%s.TLabel' % self._style_prefixe, background=hd_bg,
                             foreground=hd_fg)
        self.style.configure('normal.%s.TLabel' % self._style_prefixe, background=cal_bg,
                             foreground=cal_fg)
        self.style.configure('normal_om.%s.TLabel' % self._style_prefixe, background=om_bg,
                             foreground=om_fg)
        self.style.configure('we_om.%s.TLabel' % self._style_prefixe, background=omwe_bg,
                             foreground=omwe_fg)
        self.style.configure('sel.%s.TLabel' % self._style_prefixe, background=sel_bg,
                             foreground=sel_fg)
        self.style.configure('we.%s.TLabel' % self._style_prefixe, background=we_bg,
                             foreground=we_fg)
        size = max(self._header_font.actual()["size"], 10)
        self.style.configure('R.%s.TButton' % self._style_prefixe, background=bg,
                             arrowcolor=fg, arrowsize=size, bordercolor=bg,
                             relief="flat", lightcolor=bg, darkcolor=bg)
        self.style.configure('L.%s.TButton' % self._style_prefixe, background=bg,
                             arrowsize=size, arrowcolor=fg, bordercolor=bg,
                             relief="flat", lightcolor=bg, darkcolor=bg)

        self.style.map('R.%s.TButton' % self._style_prefixe, background=[('active', active_bg)],
                       bordercolor=[('active', active_bg)],
                       relief=[('active', 'flat')],
                       darkcolor=[('active', active_bg)],
                       lightcolor=[('active', active_bg)])
        self.style.map('L.%s.TButton' % self._style_prefixe, background=[('active', active_bg)],
                       bordercolor=[('active', active_bg)],
                       relief=[('active', 'flat')],
                       darkcolor=[('active', active_bg)],
                       lightcolor=[('active', active_bg)])
        self.style.map('sel.%s.TLabel' % self._style_prefixe,
                       background=[('disabled', dis_sel_bg)],
                       foreground=[('disabled', dis_sel_fg)])
        self.style.map(self._style_prefixe + '.TLabel',
                       background=[('disabled', dis_bg)],
                       foreground=[('disabled', dis_fg)])

    def _display_calendar(self):
        """Display the days of the current month (the one in self._date)."""
        year, month = self._date.year, self._date.month

        # update header text (Month, Year)
        header = self._month_names[month]
        self._header_month.configure(text=header.title())
        self._header_year.configure(text=str(year))

        # update calendar shown dates
        cal = self._cal.monthdatescalendar(year, month)

        next_m = month + 1
        y = year
        if next_m == 13:
            next_m = 1
            y += 1
        if len(cal) < 6:
            if cal[-1][-1].month == month:
                i = 0
            else:
                i = 1
            cal.append(self._cal.monthdatescalendar(y, next_m)[i])
            if len(cal) < 6:
                cal.append(self._cal.monthdatescalendar(y, next_m)[i + 1])

        week_days = {i: 'normal' for i in range(7)}
        week_days[5] = 'we'
        week_days[6] = 'we'
        prev_m = (month - 2) % 12 + 1
        months = {month: '.%s.TLabel' % self._style_prefixe,
                  next_m: '_om.%s.TLabel' % self._style_prefixe,
                  prev_m: '_om.%s.TLabel' % self._style_prefixe}

        week_nb = self._date.isocalendar()[1]
        modulo = max(week_nb, 52)
        for i_week in range(6):
            self._week_nbs[i_week].configure(text=str((week_nb + i_week - 1) % modulo + 1))
            for i_day in range(7):
                style = week_days[i_day] + months[cal[i_week][i_day].month]
                txt = str(cal[i_week][i_day].day)
                self._calendar[i_week][i_day].configure(text=txt,
                                                        style=style)
        self._display_selection()

    def _display_selection(self):
        """Highlight selected day."""
        if self._sel_date is not None:
            year = self._sel_date.year
            if year == self._date.year:
                _, w, d = self._sel_date.isocalendar()
                wn = self._date.isocalendar()[1]
                w -= wn
                w %= max(52, wn)
                if 0 <= w and w < 6:
                    self._calendar[w][d - 1].configure(style='sel.%s.TLabel' % self._style_prefixe)

    def _remove_selection(self):
        """Remove highlight of selected day."""
        if self._sel_date is not None:
            year, month = self._sel_date.year, self._sel_date.month
            if year == self._date.year:
                _, w, d = self._sel_date.isocalendar()
                wn = self._date.isocalendar()[1]
                w -= wn
                w %= max(52, wn)
                if w >= 0 and w < 6:
                    if month == self._date.month:
                        if d < 6:
                            self._calendar[w][d - 1].configure(style='normal.%s.TLabel' % self._style_prefixe)
                        else:
                            self._calendar[w][d - 1].configure(style='we.%s.TLabel' % self._style_prefixe)
                    else:
                        if d < 6:
                            self._calendar[w][d - 1].configure(style='normal_om.%s.TLabel' % self._style_prefixe)
                        else:
                            self._calendar[w][d - 1].configure(style='we_om.%s.TLabel' % self._style_prefixe)

    # --- callbacks
    def _next_month(self):
        """Display the next month."""
        year, month = self._date.year, self._date.month
        self._date = self._date + \
            self.timedelta(days=calendar.monthrange(year, month)[1])
#        if month == 12:
#            # don't increment year
#            self._date = self._date.replace(year=year)
        self._display_calendar()

    def _prev_month(self):
        """Display the previous month."""
        self._date = self._date - self.timedelta(days=1)
        self._date = self._date.replace(day=1)
        self._display_calendar()

    def _next_year(self):
        """Display the next year."""
        year = self._date.year
        self._date = self._date.replace(year=year + 1)
        self._display_calendar()

    def _prev_year(self):
        """Display the previous year."""
        year = self._date.year
        self._date = self._date.replace(year=year - 1)
        self._display_calendar()

    # --- bindings
    def _on_click(self, event):
        """Select the day on which the user clicked."""
        if self._properties['state'] is 'normal':
            label = event.widget
            day = label.cget("text")
            style = label.cget("style")
            if style in ['normal_om.%s.TLabel' % self._style_prefixe, 'we_om.%s.TLabel' % self._style_prefixe]:
                if label in self._calendar[0]:
                    self._prev_month()
                else:
                    self._next_month()
            if day:
                day = int(day)
                year, month = self._date.year, self._date.month
                self._remove_selection()
                self._sel_date = self.date(year, month, day)
                self._display_selection()
                if self._textvariable is not None:
                    self._textvariable.set(self.format_date(self._sel_date))
                self.event_generate("<<CalendarSelected>>")

    def format_date(self, date=None):
        """Convert date (datetime.date) to a string in the locale (short format)."""
        return format_date(date, 'short', self._properties['locale'])

    def parse_date(self, date):
        """Parse string date in the locale format and return the corresponding datetime.date."""
        return parse_date(date, self._properties['locale'])

    # --- selection handling
    def selection_get(self):
        """
        Return currently selected date (datetime.date instance).
        Always return None if selectmode is "none".
        """

        if self._properties.get("selectmode") is "day":
            return self._sel_date
        else:
            return None

    def selection_set(self, date):
        """
        Set the selection to date.

        date can be either a datetime.date
        instance or a string corresponding to the date format "%x"
        in the Calendar locale.

        Do nothing if selectmode is "none".
        """
        if self._properties.get("selectmode") is "day" and self._properties['state'] is 'normal':
            if date is None:
                self._remove_selection()
                self._sel_date = None
                if self._textvariable is not None:
                    self._textvariable.set('')
            else:
                if isinstance(date, self.date):
                    self._sel_date = date
                else:
                    try:
                        self._sel_date = self.parse_date(date)
                    except Exception:
                        raise ValueError("%r is not a valid date." % date)
                if self._textvariable is not None:
                    self._textvariable.set(self.format_date(self._sel_date))
                self._date = self._sel_date.replace(day=1)
                self._display_calendar()
                self._display_selection()

    def get_date(self):
        """Return selected date as string."""
        if self._sel_date is not None:
            return self.format_date(self._sel_date)
        else:
            return ""

    # --- other methods
    def keys(self):
        """Return a list of all resource names of this widget."""
        return list(self._properties.keys())

    def cget(self, key):
        """Return the resource value for a KEY given as string."""
        return self[key]

    def configure(self, **kw):
        """
        Configure resources of a widget.

        The values for resources are specified as keyword
        arguments. To get an overview about
        the allowed keyword arguments call the method keys.
        """
        for item, value in kw.items():
            self[item] = value

    def config(self, **kw):
        """
        Configure resources of a widget.

        The values for resources are specified as keyword
        arguments. To get an overview about
        the allowed keyword arguments call the method keys.
        """
        for item, value in kw.items():
            self[item] = value
Exemplo n.º 7
0
 def __setitem__(self, key, value):
     if key not in self._properties:
         raise AttributeError("Calendar object has no attribute %s." % key)
     elif key is "locale":
         raise AttributeError("This attribute cannot be modified.")
     else:
         if key is "selectmode":
             if value is "none":
                 for week in self._calendar:
                     for day in week:
                         day.unbind("<1>")
             elif value is "day":
                 for week in self._calendar:
                     for day in week:
                         day.bind("<1>", self._on_click)
             else:
                 raise ValueError("'selectmode' option should be 'none' or 'day'.")
         elif key is 'textvariable':
             if self._sel_date is not None:
                 if value is not None:
                     value.set(self.format_date(self._sel_date))
                 try:
                     if self._textvariable is not None:
                         self._textvariable.trace_remove('write', self._textvariable_trace_id)
                     if value is not None:
                         self._textvariable_trace_id = value.trace_add('write', self._textvariable_trace)
                 except AttributeError:
                     if self._textvariable is not None:
                         self._textvariable.trace_vdelete('w', self._textvariable_trace_id)
                     if value is not None:
                         value.trace('w', self._textvariable_trace)
             self._textvariable = value
         elif key is 'showweeknumbers':
             if value:
                 for wlabel in self._week_nbs:
                     wlabel.grid()
             else:
                 for wlabel in self._week_nbs:
                     wlabel.grid_remove()
         elif key is 'borderwidth':
             try:
                 bd = int(value)
                 self._cal_frame.pack_configure(padx=bd, pady=bd)
             except ValueError:
                 raise ValueError('expected integer for the borderwidth option.')
         elif key is 'state':
             if value not in ['normal', 'disabled']:
                 raise ValueError("bad state '%s': must be disabled or normal" % value)
             else:
                 state = '!' * (value == 'normal') + 'disabled'
                 self._l_year.state((state,))
                 self._r_year.state((state,))
                 self._l_month.state((state,))
                 self._r_month.state((state,))
                 for child in self._cal_frame.children.values():
                     child.state((state,))
         elif key is "font":
             font = Font(self, value)
             prop = font.actual()
             self._font.configure(**prop)
             prop["size"] += 1
             self._header_font.configure(**prop)
             size = max(prop["size"], 10)
             self.style.configure('R.%s.TButton' % self._style_prefixe, arrowsize=size)
             self.style.configure('L.%s.TButton' % self._style_prefixe, arrowsize=size)
         elif key is "normalbackground":
             self.style.configure('cal.%s.TFrame' % self._style_prefixe, background=value)
             self.style.configure('normal.%s.TLabel' % self._style_prefixe, background=value)
             self.style.configure('normal_om.%s.TLabel' % self._style_prefixe, background=value)
         elif key is "normalforeground":
             self.style.configure('normal.%s.TLabel' % self._style_prefixe, foreground=value)
         elif key is "bordercolor":
             self.style.configure('cal.%s.TFrame' % self._style_prefixe, background=value)
         elif key is "othermonthforeground":
             self.style.configure('normal_om.%s.TLabel' % self._style_prefixe, foreground=value)
         elif key is "othermonthbackground":
             self.style.configure('normal_om.%s.TLabel' % self._style_prefixe, background=value)
         elif key is "othermonthweforeground":
             self.style.configure('we_om.%s.TLabel' % self._style_prefixe, foreground=value)
         elif key is "othermonthwebackground":
             self.style.configure('we_om.%s.TLabel' % self._style_prefixe, background=value)
         elif key is "selectbackground":
             self.style.configure('sel.%s.TLabel' % self._style_prefixe, background=value)
         elif key is "selectforeground":
             self.style.configure('sel.%s.TLabel' % self._style_prefixe, foreground=value)
         elif key is "disabledselectbackground":
             self.style.map('sel.%s.TLabel' % self._style_prefixe, background=[('disabled', value)])
         elif key is "disabledselectforeground":
             self.style.map('sel.%s.TLabel' % self._style_prefixe, foreground=[('disabled', value)])
         elif key is "disableddaybackground":
             self.style.map('%s.TLabel' % self._style_prefixe, background=[('disabled', value)])
         elif key is "disableddayforeground":
             self.style.map('%s.TLabel' % self._style_prefixe, foreground=[('disabled', value)])
         elif key is "weekendbackground":
             self.style.configure('we.%s.TLabel' % self._style_prefixe, background=value)
             self.style.configure('we_om.%s.TLabel' % self._style_prefixe, background=value)
         elif key is "weekendforeground":
             self.style.configure('we.%s.TLabel' % self._style_prefixe, foreground=value)
         elif key is "headersbackground":
             self.style.configure('headers.%s.TLabel' % self._style_prefixe, background=value)
         elif key is "headersforeground":
             self.style.configure('headers.%s.TLabel' % self._style_prefixe, foreground=value)
         elif key is "background":
             self.style.configure('main.%s.TFrame' % self._style_prefixe, background=value)
             self.style.configure('main.%s.TLabel' % self._style_prefixe, background=value)
             self.style.configure('R.%s.TButton' % self._style_prefixe, background=value,
                                  bordercolor=value,
                                  lightcolor=value, darkcolor=value)
             self.style.configure('L.%s.TButton' % self._style_prefixe, background=value,
                                  bordercolor=value,
                                  lightcolor=value, darkcolor=value)
         elif key is "foreground":
             self.style.configure('R.%s.TButton' % self._style_prefixe, arrowcolor=value)
             self.style.configure('L.%s.TButton' % self._style_prefixe, arrowcolor=value)
             self.style.configure('main.%s.TLabel' % self._style_prefixe, foreground=value)
         elif key is "cursor":
             ttk.Frame.configure(self, cursor=value)
         self._properties[key] = value
Exemplo n.º 8
0
 def __setitem__(self, key, value):
     if key not in self._properties:
         raise AttributeError("Calendar object has no attribute %s." % key)
     elif key is "locale":
         raise AttributeError("This attribute cannot be modified.")
     else:
         if key is "selectmode":
             if value is "none":
                 for week in self._calendar:
                     for day in week:
                         day.unbind("<1>")
             elif value is "day":
                 for week in self._calendar:
                     for day in week:
                         day.bind("<1>", self._on_click)
             else:
                 raise ValueError(
                     "'selectmode' option should be 'none' or 'day'.")
         elif key is 'borderwidth':
             try:
                 bd = int(value)
                 self._cal_frame.pack_configure(padx=bd, pady=bd)
             except ValueError:
                 raise ValueError(
                     'expected integer for the borderwidth option.')
         elif key is "font":
             font = Font(self, value)
             prop = font.actual()
             self._font.configure(**prop)
             prop["size"] += 1
             self._header_font.configure(**prop)
             size = max(prop["size"], 10)
             self.style.configure(self._style_prefixe + '.R.TButton',
                                  arrowsize=size)
             self.style.configure(self._style_prefixe + '.L.TButton',
                                  arrowsize=size)
         elif key is "normalbackground":
             self.style.configure(self._style_prefixe + '.cal.TFrame',
                                  background=value)
             self.style.configure(self._style_prefixe + '.normal.TLabel',
                                  background=value)
             self.style.configure(self._style_prefixe + '.normal_om.TLabel',
                                  background=value)
         elif key is "normalforeground":
             self.style.configure(self._style_prefixe + '.normal.TLabel',
                                  foreground=value)
         elif key is "bordercolor":
             self.style.configure(self._style_prefixe + '.cal.TFrame',
                                  background=value)
         elif key is "othermonthforeground":
             self.style.configure(self._style_prefixe + '.normal_om.TLabel',
                                  foreground=value)
         elif key is "othermonthbackground":
             self.style.configure(self._style_prefixe + '.normal_om.TLabel',
                                  background=value)
         elif key is "othermonthweforeground":
             self.style.configure(self._style_prefixe + '.we_om.TLabel',
                                  foreground=value)
         elif key is "othermonthwebackground":
             self.style.configure(self._style_prefixe + '.we_om.TLabel',
                                  background=value)
         elif key is "selectbackground":
             self.style.configure(self._style_prefixe + '.sel.TLabel',
                                  background=value)
         elif key is "selectforeground":
             self.style.configure(self._style_prefixe + '.sel.TLabel',
                                  foreground=value)
         elif key is "weekendbackground":
             self.style.configure(self._style_prefixe + '.we.TLabel',
                                  background=value)
             self.style.configure(self._style_prefixe + '.we_om.TLabel',
                                  background=value)
         elif key is "weekendforeground":
             self.style.configure(self._style_prefixe + '.we.TLabel',
                                  foreground=value)
         elif key is "headersbackground":
             self.style.configure(self._style_prefixe + '.headers.TLabel',
                                  background=value)
         elif key is "headersforeground":
             self.style.configure(self._style_prefixe + '.headers.TLabel',
                                  foreground=value)
         elif key is "background":
             self.style.configure(self._style_prefixe + '.main.TFrame',
                                  background=value)
             self.style.configure(self._style_prefixe + '.main.TLabel',
                                  background=value)
             self.style.configure(self._style_prefixe + '.R.TButton',
                                  background=value,
                                  bordercolor=value,
                                  lightcolor=value,
                                  darkcolor=value)
             self.style.configure(self._style_prefixe + '.L.TButton',
                                  background=value,
                                  bordercolor=value,
                                  lightcolor=value,
                                  darkcolor=value)
         elif key is "foreground":
             self.style.configure(self._style_prefixe + '.R.TButton',
                                  arrowcolor=value)
             self.style.configure(self._style_prefixe + '.L.TButton',
                                  arrowcolor=value)
             self.style.configure(self._style_prefixe + '.main.TLabel',
                                  foreground=value)
         elif key is "cursor":
             ttk.Frame.configure(self, cursor=value)
         self._properties[key] = value
Exemplo n.º 9
0
class FontChooser(Toplevel):
    """Font chooser dialog."""

    def __init__(self, master, font_dict={}, text="Abcd", title="Font Chooser",
                 **kwargs):
        """
        Create a new FontChooser instance.
        Arguments:
            master : Tk or Toplevel instance
                master window
            font_dict : dict
                dictionnary, like the one returned by the ``actual`` method of a ``Font`` object:
                ::
                    {'family': str,
                     'size': int,
                     'weight': 'bold'/'normal',
                     'slant': 'italic'/'roman',
                     'underline': bool,
                     'overstrike': bool}
            text : str
                text to be displayed in the preview label
            title : str
                window title
            kwargs : dict
                additional keyword arguments to be passed to ``Toplevel.__init__``
        """
        Toplevel.__init__(self, master, **kwargs)
        self.title(title)
        self.resizable(False, False)
        self.protocol("WM_DELETE_WINDOW", self.quit)
        self._validate_family = self.register(self.validate_font_family)
        self._validate_size = self.register(self.validate_font_size)

        # --- variable storing the chosen font
        self.res = ""

        style = Style(self)
        style.configure("prev.TLabel", background="white")
        bg = style.lookup("TLabel", "background")
        self.configure(bg=bg)

        # --- family list
        self.fonts = list(set(families()))
        self.fonts.append("TkDefaultFont")
        self.fonts.sort()
        for i in range(len(self.fonts)):
            self.fonts[i] = self.fonts[i].replace(" ", "\ ")
        max_length = int(2.5 * max([len(font) for font in self.fonts])) // 3
        self.sizes = ["%i" % i for i in (list(range(6, 17)) + list(range(18, 32, 2)))]
        # --- font default
        font_dict["weight"] = font_dict.get("weight", "normal")
        font_dict["slant"] = font_dict.get("slant", "roman")
        font_dict["underline"] = font_dict.get("underline", False)
        font_dict["overstrike"] = font_dict.get("overstrike", False)
        font_dict["family"] = font_dict.get("family",
                                            self.fonts[0].replace('\ ', ' '))
        font_dict["size"] = font_dict.get("size", 10)

        # --- creation of the widgets
        # ------ style parameters (bold, italic ...)
        options_frame = Frame(self, relief='groove', borderwidth=2)
        self.font_family = StringVar(self, " ".join(self.fonts))
        self.font_size = StringVar(self, " ".join(self.sizes))
        self.var_bold = BooleanVar(self, font_dict["weight"] == "bold")
        b_bold = Checkbutton(options_frame, text=TR["Bold"],
                             command=self.toggle_bold,
                             variable=self.var_bold)
        b_bold.grid(row=0, sticky="w", padx=4, pady=(4, 2))
        self.var_italic = BooleanVar(self, font_dict["slant"] == "italic")
        b_italic = Checkbutton(options_frame, text=TR["Italic"],
                               command=self.toggle_italic,
                               variable=self.var_italic)
        b_italic.grid(row=1, sticky="w", padx=4, pady=2)
        self.var_underline = BooleanVar(self, font_dict["underline"])
        b_underline = Checkbutton(options_frame, text=TR["Underline"],
                                  command=self.toggle_underline,
                                  variable=self.var_underline)
        b_underline.grid(row=2, sticky="w", padx=4, pady=2)
        self.var_overstrike = BooleanVar(self, font_dict["overstrike"])
        b_overstrike = Checkbutton(options_frame, text=TR["Overstrike"],
                                   variable=self.var_overstrike,
                                   command=self.toggle_overstrike)
        b_overstrike.grid(row=3, sticky="w", padx=4, pady=(2, 4))
        # ------ Size and family
        self.var_size = StringVar(self)
        self.entry_family = Entry(self, width=max_length, validate="key",
                                  validatecommand=(self._validate_family, "%d", "%S",
                                                   "%i", "%s", "%V"))
        self.entry_size = Entry(self, width=4, validate="key",
                                textvariable=self.var_size,
                                validatecommand=(self._validate_size, "%d", "%P", "%V"))
        self.list_family = Listbox(self, selectmode="browse",
                                   listvariable=self.font_family,
                                   highlightthickness=0,
                                   exportselection=False,
                                   width=max_length)
        self.list_size = Listbox(self, selectmode="browse",
                                 listvariable=self.font_size,
                                 highlightthickness=0,
                                 exportselection=False,
                                 width=4)
        scroll_family = Scrollbar(self, orient='vertical',
                                  command=self.list_family.yview)
        scroll_size = Scrollbar(self, orient='vertical',
                                command=self.list_size.yview)
        self.preview_font = Font(self, **font_dict)
        if len(text) > 30:
            text = text[:30]
        self.preview = Label(self, relief="groove", style="prev.TLabel",
                             text=text, font=self.preview_font,
                             anchor="center")

        # --- widget configuration
        self.list_family.configure(yscrollcommand=scroll_family.set)
        self.list_size.configure(yscrollcommand=scroll_size.set)

        self.entry_family.insert(0, font_dict["family"])
        self.entry_family.selection_clear()
        self.entry_family.icursor("end")
        self.entry_size.insert(0, font_dict["size"])

        try:
            i = self.fonts.index(self.entry_family.get().replace(" ", "\ "))
        except ValueError:
            # unknown font
            i = 0
        self.list_family.selection_clear(0, "end")
        self.list_family.selection_set(i)
        self.list_family.see(i)
        try:
            i = self.sizes.index(self.entry_size.get())
            self.list_size.selection_clear(0, "end")
            self.list_size.selection_set(i)
            self.list_size.see(i)
        except ValueError:
            # size not in list
            pass

        self.entry_family.grid(row=0, column=0, sticky="ew",
                               pady=(10, 1), padx=(10, 0))
        self.entry_size.grid(row=0, column=2, sticky="ew",
                             pady=(10, 1), padx=(10, 0))
        self.list_family.grid(row=1, column=0, sticky="nsew",
                              pady=(1, 10), padx=(10, 0))
        self.list_size.grid(row=1, column=2, sticky="nsew",
                            pady=(1, 10), padx=(10, 0))
        scroll_family.grid(row=1, column=1, sticky='ns', pady=(1, 10))
        scroll_size.grid(row=1, column=3, sticky='ns', pady=(1, 10))
        options_frame.grid(row=0, column=4, rowspan=2,
                           padx=10, pady=10, ipadx=10)

        self.preview.grid(row=2, column=0, columnspan=5, sticky="eswn",
                          padx=10, pady=(0, 10), ipadx=4, ipady=4)

        button_frame = Frame(self)
        button_frame.grid(row=3, column=0, columnspan=5, pady=(0, 10), padx=10)

        Button(button_frame, text="Ok",
               command=self.ok).grid(row=0, column=0, padx=4, sticky='ew')
        Button(button_frame, text=TR["Cancel"],
               command=self.quit).grid(row=0, column=1, padx=4, sticky='ew')
        self.list_family.bind('<<ListboxSelect>>', self.update_entry_family)
        self.list_size.bind('<<ListboxSelect>>', self.update_entry_size,
                            add=True)
        self.list_family.bind("<KeyPress>", self.keypress)
        self.entry_family.bind("<Return>", self.change_font_family)
        self.entry_family.bind("<Tab>", self.tab)
        self.entry_size.bind("<Return>", self.change_font_size)

        self.entry_family.bind("<Down>", self.down_family)
        self.entry_size.bind("<Down>", self.down_size)

        self.entry_family.bind("<Up>", self.up_family)
        self.entry_size.bind("<Up>", self.up_size)

        # bind Ctrl+A to select all instead of go to beginning
        self.bind_class("TEntry", "<Control-a>", self.select_all)

        self.wait_visibility(self)
        self.grab_set()
        self.entry_family.focus_set()
        self.lift()

    def select_all(self, event):
        """Select all entry content."""
        event.widget.selection_range(0, "end")

    def keypress(self, event):
        """Select the first font whose name begin by the key pressed."""
        key = event.char.lower()
        l = [i for i in self.fonts if i[0].lower() == key]
        if l:
            i = self.fonts.index(l[0])
            self.list_family.selection_clear(0, "end")
            self.list_family.selection_set(i)
            self.list_family.see(i)
            self.update_entry_family()

    def up_family(self, event):
        """Navigate in the family listbox with up key."""
        try:
            i = self.list_family.curselection()[0]
            self.list_family.selection_clear(0, "end")
            if i <= 0:
                i = len(self.fonts)
            self.list_family.see(i - 1)
            self.list_family.select_set(i - 1)
        except TclError:
            self.list_family.selection_clear(0, "end")
            i = len(self.fonts)
            self.list_family.see(i - 1)
            self.list_family.select_set(i - 1)
        self.list_family.event_generate('<<ListboxSelect>>')

    def up_size(self, event):
        """Navigate in the size listbox with up key."""
        try:
            s = self.var_size.get()
            if s in self.sizes:
                i = self.sizes.index(s)
            elif s:
                sizes = list(self.sizes)
                sizes.append(s)
                sizes.sort(key=lambda x: int(x))
                i = sizes.index(s)
            else:
                i = 0
            self.list_size.selection_clear(0, "end")
            if i <= 0:
                i = len(self.sizes)
            self.list_size.see(i - 1)
            self.list_size.select_set(i - 1)
        except TclError:
            i = len(self.sizes)
            self.list_size.see(i - 1)
            self.list_size.select_set(i - 1)
        self.list_size.event_generate('<<ListboxSelect>>')

    def down_family(self, event):
        """Navigate in the family listbox with down key."""
        try:
            i = self.list_family.curselection()[0]
            self.list_family.selection_clear(0, "end")
            if i >= len(self.fonts):
                i = -1
            self.list_family.see(i + 1)
            self.list_family.select_set(i + 1)
        except TclError:
            self.list_family.selection_clear(0, "end")
            self.list_family.see(0)
            self.list_family.select_set(0)
        self.list_family.event_generate('<<ListboxSelect>>')

    def down_size(self, event):
        """Navigate in the size listbox with down key."""
        try:
            s = self.var_size.get()
            if s in self.sizes:
                i = self.sizes.index(s)
            elif s:
                sizes = list(self.sizes)
                sizes.append(s)
                sizes.sort(key=lambda x: int(x))
                i = sizes.index(s) - 1
            else:
                s = len(self.sizes) - 1
            self.list_size.selection_clear(0, "end")
            if i < len(self.sizes) - 1:
                self.list_size.selection_set(i + 1)
                self.list_size.see(i + 1)
            else:
                self.list_size.see(0)
                self.list_size.select_set(0)
        except TclError:
            self.list_size.selection_set(0)
        self.list_size.event_generate('<<ListboxSelect>>')

    def toggle_bold(self):
        """Update font preview weight."""
        b = self.var_bold.get()
        self.preview_font.configure(weight=["normal", "bold"][b])

    def toggle_italic(self):
        """Update font preview slant."""
        b = self.var_italic.get()
        self.preview_font.configure(slant=["roman", "italic"][b])

    def toggle_underline(self):
        """Update font preview underline."""
        b = self.var_underline.get()
        self.preview_font.configure(underline=b)

    def toggle_overstrike(self):
        """Update font preview overstrike."""
        b = self.var_overstrike.get()
        self.preview_font.configure(overstrike=b)

    def change_font_family(self, event=None):
        """Update font preview family."""
        family = self.entry_family.get()
        if family.replace(" ", "\ ") in self.fonts:
            self.preview_font.configure(family=family)

    def change_font_size(self, event=None):
        """Update font preview size."""
        size = int(self.var_size.get())
        self.preview_font.configure(size=size)

    def validate_font_size(self, d, ch, V):
        """Validation of the size entry content."""
        l = [i for i in self.sizes if i[:len(ch)] == ch]
        i = None
        if l:
            i = self.sizes.index(l[0])
        elif ch.isdigit():
            sizes = list(self.sizes)
            sizes.append(ch)
            sizes.sort(key=lambda x: int(x))
            i = min(sizes.index(ch), len(self.sizes))
        if i is not None:
            self.list_size.selection_clear(0, "end")
            self.list_size.selection_set(i)
            deb = self.list_size.nearest(0)
            fin = self.list_size.nearest(self.list_size.winfo_height())
            if V != "forced":
                if i < deb or i > fin:
                    self.list_size.see(i)
                return True
        if d == '1':
            return ch.isdigit()
        else:
            return True

    def tab(self, event):
        """Move at the end of selected text on tab press."""
        self.entry_family = event.widget
        self.entry_family.selection_clear()
        self.entry_family.icursor("end")
        return "break"

    def validate_font_family(self, action, modif, pos, prev_txt, V):
        """Completion of the text in the entry with existing font names."""
        if self.entry_family.selection_present():
            sel = self.entry_family.selection_get()
            txt = prev_txt.replace(sel, '')
        else:
            txt = prev_txt
        if action == "0":
            txt = txt[:int(pos)] + txt[int(pos) + 1:]
            return True
        else:
            txt = txt[:int(pos)] + modif + txt[int(pos):]
            ch = txt.replace(" ", "\ ")
            l = [i for i in self.fonts if i[:len(ch)] == ch]
            if l:
                i = self.fonts.index(l[0])
                self.list_family.selection_clear(0, "end")
                self.list_family.selection_set(i)
                deb = self.list_family.nearest(0)
                fin = self.list_family.nearest(self.list_family.winfo_height())
                index = self.entry_family.index("insert")
                self.entry_family.delete(0, "end")
                self.entry_family.insert(0, l[0].replace("\ ", " "))
                self.entry_family.selection_range(index + 1, "end")
                self.entry_family.icursor(index + 1)
                if V != "forced":
                    if i < deb or i > fin:
                        self.list_family.see(i)
                return True
            else:
                return False

    def update_entry_family(self, event=None):
        """Update family entry when an item is selected in the family listbox."""
        #  family = self.list_family.get("@%i,%i" % (event.x , event.y))
        family = self.list_family.get(self.list_family.curselection()[0])
        self.entry_family.delete(0, "end")
        self.entry_family.insert(0, family)
        self.entry_family.selection_clear()
        self.entry_family.icursor("end")
        self.change_font_family()

    def update_entry_size(self, event):
        """Update size entry when an item is selected in the size listbox."""
        #  size = self.list_size.get("@%i,%i" % (event.x , event.y))
        size = self.list_size.get(self.list_size.curselection()[0])
        self.var_size.set(size)
        self.change_font_size()

    def ok(self):
        """Validate choice."""
        self.res = self.preview_font.actual()
        self.quit()

    def get_res(self):
        """Return chosen font."""
        return self.res

    def quit(self):
        self.destroy()
Exemplo n.º 10
0
class FontChooser(Toplevel):
    """ Font chooser toplevel """
    def __init__(self,
                 master,
                 font_dict={},
                 text="Abcd",
                 title="Font Chooser",
                 **kwargs):
        """
            Create a new FontChooser instance.

            font: dictionnary, like the one returned by the .actual
                  method of a Font object

                    {'family': 'DejaVu Sans',
                     'overstrike':False,
                     'size': 12,
                     'slant': 'italic' or 'roman',
                     'underline': False,
                     'weight': 'bold' or 'normal'}

            text: text to be displayed in the preview label

            title: window title

            **kwargs: additional keyword arguments to be passed to
                      Toplevel.__init__
        """
        Toplevel.__init__(self, master, **kwargs)
        self.title(title)
        self.resizable(False, False)
        self.protocol("WM_DELETE_WINDOW", self.quit)
        self._validate_family = self.register(self.validate_font_family)
        self._validate_size = self.register(self.validate_font_size)

        # variable storing the chosen font
        self.res = ""

        style = Style(self)
        style.configure("prev.TLabel", background="white")
        bg = style.lookup("TLabel", "background")
        self.configure(bg=bg)

        # family list
        self.fonts = list(set(families()))
        self.fonts.append("TkDefaultFont")
        self.fonts.sort()
        for i in range(len(self.fonts)):
            self.fonts[i] = self.fonts[i].replace(" ", "\ ")
        max_length = int(2.5 * max([len(font) for font in self.fonts])) // 3
        self.sizes = [
            "%i" % i for i in (list(range(6, 17)) + list(range(18, 32, 2)))
        ]
        # font default
        font_dict["weight"] = font_dict.get("weight", "normal")
        font_dict["slant"] = font_dict.get("slant", "roman")
        font_dict["family"] = font_dict.get("family",
                                            self.fonts[0].replace('\ ', ' '))
        font_dict["size"] = font_dict.get("size", 10)

        # Widgets creation
        options_frame = Frame(self, relief='groove', borderwidth=2)
        self.font_family = StringVar(self, " ".join(self.fonts))
        self.font_size = StringVar(self, " ".join(self.sizes))
        self.var_bold = BooleanVar(self, font_dict["weight"] == "bold")
        b_bold = Checkbutton(options_frame,
                             text=TR["Bold"],
                             command=self.toggle_bold,
                             variable=self.var_bold)
        b_bold.grid(row=0, sticky="w", padx=4, pady=(4, 2))
        self.var_italic = BooleanVar(self, font_dict["slant"] == "italic")
        b_italic = Checkbutton(options_frame,
                               text=TR["Italic"],
                               command=self.toggle_italic,
                               variable=self.var_italic)
        b_italic.grid(row=1, sticky="w", padx=4, pady=2)
        self.var_size = StringVar(self)
        self.entry_family = Entry(self,
                                  width=max_length,
                                  validate="key",
                                  validatecommand=(self._validate_family, "%d",
                                                   "%S", "%i", "%s", "%V"))
        entry_size = Entry(self,
                           width=4,
                           validate="key",
                           textvariable=self.var_size,
                           validatecommand=(self._validate_size, "%d", "%P",
                                            "%V"))
        self.list_family = Listbox(self,
                                   selectmode="browse",
                                   listvariable=self.font_family,
                                   highlightthickness=0,
                                   exportselection=False,
                                   width=max_length)
        self.list_size = Listbox(self,
                                 selectmode="browse",
                                 listvariable=self.font_size,
                                 highlightthickness=0,
                                 exportselection=False,
                                 width=4)
        scroll_family = Scrollbar(self,
                                  orient='vertical',
                                  command=self.list_family.yview)
        scroll_size = Scrollbar(self,
                                orient='vertical',
                                command=self.list_size.yview)
        self.preview_font = Font(self, **font_dict)
        if len(text) > 30:
            text = text[:30]
        self.preview = Label(self,
                             relief="groove",
                             style="prev.TLabel",
                             text=text,
                             font=self.preview_font,
                             anchor="center")

        # Widget configuration
        self.list_family.configure(yscrollcommand=scroll_family.set)
        self.list_size.configure(yscrollcommand=scroll_size.set)

        self.entry_family.insert(0, font_dict["family"])
        self.entry_family.selection_clear()
        self.entry_family.icursor("end")
        entry_size.insert(0, font_dict["size"])

        i = self.fonts.index(self.entry_family.get().replace(" ", "\ "))
        self.list_family.selection_clear(0, "end")
        self.list_family.selection_set(i)
        self.list_family.see(i)
        i = self.sizes.index(entry_size.get())
        self.list_size.selection_clear(0, "end")
        self.list_size.selection_set(i)
        self.list_size.see(i)

        self.entry_family.grid(row=0,
                               column=0,
                               sticky="ew",
                               pady=(10, 1),
                               padx=(10, 0))
        entry_size.grid(row=0,
                        column=2,
                        sticky="ew",
                        pady=(10, 1),
                        padx=(10, 0))
        self.list_family.grid(row=1,
                              column=0,
                              sticky="nsew",
                              pady=(1, 10),
                              padx=(10, 0))
        self.list_size.grid(row=1,
                            column=2,
                            sticky="nsew",
                            pady=(1, 10),
                            padx=(10, 0))
        scroll_family.grid(row=1, column=1, sticky='ns', pady=(1, 10))
        scroll_size.grid(row=1, column=3, sticky='ns', pady=(1, 10))
        options_frame.grid(row=0,
                           column=4,
                           rowspan=2,
                           padx=10,
                           pady=10,
                           ipadx=10)

        self.preview.grid(row=2,
                          column=0,
                          columnspan=5,
                          sticky="eswn",
                          padx=10,
                          pady=(0, 10),
                          ipadx=4,
                          ipady=4)

        button_frame = Frame(self)
        button_frame.grid(row=3, column=0, columnspan=5, pady=(0, 10), padx=10)

        Button(button_frame, text="Ok", command=self.ok).grid(row=0,
                                                              column=0,
                                                              padx=4,
                                                              sticky='ew')
        Button(button_frame, text=TR["Cancel"],
               command=self.quit).grid(row=0, column=1, padx=4, sticky='ew')
        self.list_family.bind('<<ListboxSelect>>', self.update_entry_family)
        self.list_size.bind('<<ListboxSelect>>',
                            self.update_entry_size,
                            add=True)
        self.list_family.bind("<KeyPress>", self.keypress)
        self.entry_family.bind("<Return>", self.change_font_family)
        self.entry_family.bind("<Tab>", self.tab)
        entry_size.bind("<Return>", self.change_font_size)

        self.entry_family.bind("<Down>", self.down_family)
        entry_size.bind("<Down>", self.down_size)

        self.entry_family.bind("<Up>", self.up_family)
        entry_size.bind("<Up>", self.up_size)

        # bind Ctrl+A to select all instead of go to beginning
        self.bind_class("TEntry", "<Control-a>", self.select_all)

        self.update_idletasks()
        self.grab_set()
        self.entry_family.focus_set()
        self.lift()

    def select_all(self, event):
        event.widget.selection_range(0, "end")

    def keypress(self, event):
        key = event.char.lower()
        l = [i for i in self.fonts if i[0].lower() == key]
        if l:
            i = self.fonts.index(l[0])
            self.list_family.selection_clear(0, "end")
            self.list_family.selection_set(i)
            self.list_family.see(i)
            self.update_entry_family()

    def up_family(self, event):
        try:
            txt = self.entry_family.get().replace(" ", "\ ")
            l = [i for i in self.fonts if i[:len(txt)] == txt]
            if l:
                self.list_family.selection_clear(0, "end")
                i = self.fonts.index(l[0])
                if i > 0:
                    self.list_family.selection_set(i - 1)
                    self.list_family.see(i - 1)
                else:
                    i = len(self.fonts)
                    self.list_family.see(i - 1)
                    self.list_family.select_set(i - 1)

        except TclError:
            i = len(self.fonts)
            self.list_family.see(i - 1)
            self.list_family.select_set(i - 1)
        self.list_family.event_generate('<<ListboxSelect>>')

    def up_size(self, event):
        try:
            s = self.var_size.get()
            i = self.sizes.index(s)
            self.list_size.selection_clear(0, "end")
            if i > 0:
                self.list_size.selection_set(i - 1)
                self.list_size.see(i - 1)
            else:
                i = len(self.sizes)
                self.list_size.see(i - 1)
                self.list_size.select_set(i - 1)
        except TclError:
            i = len(self.sizes)
            self.list_size.see(i - 1)
            self.list_size.select_set(i - 1)
        self.list_size.event_generate('<<ListboxSelect>>')

    def down_family(self, event):
        try:
            txt = self.entry_family.get().replace(" ", "\ ")
            l = [i for i in self.fonts if i[:len(txt)] == txt]
            if l:
                self.list_family.selection_clear(0, "end")
                i = self.fonts.index(l[0])
                if i < len(self.fonts) - 1:
                    self.list_family.selection_set(i + 1)
                    self.list_family.see(i + 1)
                else:
                    self.list_family.see(0)
                    self.list_family.select_set(0)

        except TclError:
            self.list_family.selection_set(0)
        self.list_family.event_generate('<<ListboxSelect>>')

    def down_size(self, event):
        try:
            s = self.var_size.get()
            i = self.sizes.index(s)
            self.list_size.selection_clear(0, "end")
            if i < len(self.sizes) - 1:
                self.list_size.selection_set(i + 1)
                self.list_size.see(i + 1)
            else:
                self.list_size.see(0)
                self.list_size.select_set(0)
        except TclError:
            self.list_size.selection_set(0)
        self.list_size.event_generate('<<ListboxSelect>>')

    def toggle_bold(self):
        b = self.var_bold.get()
        self.preview_font.configure(weight=["normal", "bold"][b])

    def toggle_italic(self):
        b = self.var_italic.get()
        self.preview_font.configure(slant=["roman", "italic"][b])

    def toggle_underline(self):
        b = self.var_underline.get()
        self.preview_font.configure(underline=b)

    def toggle_overstrike(self):
        b = self.var_overstrike.get()
        self.preview_font.configure(overstrike=b)

    def change_font_family(self, event=None):
        family = self.entry_family.get()
        if family.replace(" ", "\ ") in self.fonts:
            self.preview_font.configure(family=family)

    def change_font_size(self, event=None):
        size = int(self.var_size.get())
        self.preview_font.configure(size=size)

    def validate_font_size(self, d, ch, V):
        ''' Validation of the size entry content '''
        l = [i for i in self.sizes if i[:len(ch)] == ch]
        if l:
            i = self.sizes.index(l[0])
            self.list_size.selection_clear(0, "end")
            self.list_size.selection_set(i)
            deb = self.list_size.nearest(0)
            fin = self.list_size.nearest(self.list_size.winfo_height())
            if V != "forced":
                if i < deb or i > fin:
                    self.list_size.see(i)
                return True
        if d == '1':
            return ch.isdigit()
        else:
            return True

    def tab(self, event):
        self.entry_family = event.widget
        self.entry_family.selection_clear()
        self.entry_family.icursor("end")
        return "break"

    def validate_font_family(self, action, modif, pos, prev_txt, V):
        """ completion of the text in the path entry with existing
            folder/file names """
        if self.entry_family.selection_present():
            sel = self.entry_family.selection_get()
            txt = prev_txt.replace(sel, '')
        else:
            txt = prev_txt
        if action == "0":
            txt = txt[:int(pos)] + txt[int(pos) + 1:]
            return True
        else:
            txt = txt[:int(pos)] + modif + txt[int(pos):]
            ch = txt.replace(" ", "\ ")
            l = [i for i in self.fonts if i[:len(ch)] == ch]
            if l:
                i = self.fonts.index(l[0])
                self.list_family.selection_clear(0, "end")
                self.list_family.selection_set(i)
                deb = self.list_family.nearest(0)
                fin = self.list_family.nearest(self.list_family.winfo_height())
                index = self.entry_family.index("insert")
                self.entry_family.delete(0, "end")
                self.entry_family.insert(0, l[0].replace("\ ", " "))
                self.entry_family.selection_range(index + 1, "end")
                self.entry_family.icursor(index + 1)
                if V != "forced":
                    if i < deb or i > fin:
                        self.list_family.see(i)
                return True
            else:
                return False

    def update_entry_family(self, event=None):
        #  family = self.list_family.get("@%i,%i" % (event.x , event.y))
        family = self.list_family.get(self.list_family.curselection()[0])
        self.entry_family.delete(0, "end")
        self.entry_family.insert(0, family)
        self.entry_family.selection_clear()
        self.entry_family.icursor("end")
        self.change_font_family()

    def update_entry_size(self, event):
        #  size = self.list_size.get("@%i,%i" % (event.x , event.y))
        size = self.list_size.get(self.list_size.curselection()[0])
        self.var_size.set(size)
        self.change_font_size()

    def ok(self):
        self.res = self.preview_font.actual()
        self.quit()

    def get_res(self):
        return self.res

    def quit(self):
        self.destroy()