From d87d16826ac55f260b706cb63d8ee0a7d3c6d893 Mon Sep 17 00:00:00 2001
From: Terry Jan Reedy <tjreedy@udel.edu>
Date: Sat, 1 Aug 2015 18:57:33 -0400
Subject: Issue 24745: Switch from Courier to platform-sensitive TkFixedFont as
 default editor font.  This should not affect current customized font
 selections. Patch by Mark Roseman.

---
 Lib/idlelib/EditorWindow.py  | 17 +++--------------
 Lib/idlelib/config-main.def  |  2 +-
 Lib/idlelib/configDialog.py  | 40 ++++++++++++++++++++--------------------
 Lib/idlelib/configHandler.py | 27 +++++++++++++++++++++++++++
 4 files changed, 51 insertions(+), 35 deletions(-)

diff --git a/Lib/idlelib/EditorWindow.py b/Lib/idlelib/EditorWindow.py
index 7bc2aa7..6dbbe09 100644
--- a/Lib/idlelib/EditorWindow.py
+++ b/Lib/idlelib/EditorWindow.py
@@ -230,13 +230,7 @@ class EditorWindow(object):
         vbar['command'] = text.yview
         vbar.pack(side=RIGHT, fill=Y)
         text['yscrollcommand'] = vbar.set
-        fontWeight = 'normal'
-        if idleConf.GetOption('main', 'EditorWindow', 'font-bold', type='bool'):
-            fontWeight='bold'
-        text.config(font=(idleConf.GetOption('main', 'EditorWindow', 'font'),
-                          idleConf.GetOption('main', 'EditorWindow',
-                                             'font-size', type='int'),
-                          fontWeight))
+        text['font'] = idleConf.GetFont(self.root, 'main', 'EditorWindow')
         text_frame.pack(side=LEFT, fill=BOTH, expand=1)
         text.pack(side=TOP, fill=BOTH, expand=1)
         text.focus_set()
@@ -797,13 +791,8 @@ class EditorWindow(object):
     def ResetFont(self):
         "Update the text widgets' font if it is changed"
         # Called from configDialog.py
-        fontWeight='normal'
-        if idleConf.GetOption('main','EditorWindow','font-bold',type='bool'):
-            fontWeight='bold'
-        self.text.config(font=(idleConf.GetOption('main','EditorWindow','font'),
-                idleConf.GetOption('main','EditorWindow','font-size',
-                                   type='int'),
-                fontWeight))
+
+        self.text['font'] = idleConf.GetFont(self.root, 'main','EditorWindow')
 
     def RemoveKeybindings(self):
         "Remove the keybindings before they are changed."
diff --git a/Lib/idlelib/config-main.def b/Lib/idlelib/config-main.def
index 0d203cb..3622cb2 100644
--- a/Lib/idlelib/config-main.def
+++ b/Lib/idlelib/config-main.def
@@ -53,7 +53,7 @@ delete-exitfunc= 1
 [EditorWindow]
 width= 80
 height= 40
-font= courier
+font= TkFixedFont
 font-size= 10
 font-bold= 0
 encoding= none
diff --git a/Lib/idlelib/configDialog.py b/Lib/idlelib/configDialog.py
index b0247f0..9ed6336 100644
--- a/Lib/idlelib/configDialog.py
+++ b/Lib/idlelib/configDialog.py
@@ -465,9 +465,9 @@ class ConfigDialog(Toplevel):
         return frame
 
     def AttachVarCallbacks(self):
-        self.fontSize.trace_variable('w', self.VarChanged_fontSize)
-        self.fontName.trace_variable('w', self.VarChanged_fontName)
-        self.fontBold.trace_variable('w', self.VarChanged_fontBold)
+        self.fontSize.trace_variable('w', self.VarChanged_font)
+        self.fontName.trace_variable('w', self.VarChanged_font)
+        self.fontBold.trace_variable('w', self.VarChanged_font)
         self.spaceNum.trace_variable('w', self.VarChanged_spaceNum)
         self.colour.trace_variable('w', self.VarChanged_colour)
         self.builtinTheme.trace_variable('w', self.VarChanged_builtinTheme)
@@ -484,15 +484,15 @@ class ConfigDialog(Toplevel):
         self.autoSave.trace_variable('w', self.VarChanged_autoSave)
         self.encoding.trace_variable('w', self.VarChanged_encoding)
 
-    def VarChanged_fontSize(self, *params):
-        value = self.fontSize.get()
-        self.AddChangedItem('main', 'EditorWindow', 'font-size', value)
-
-    def VarChanged_fontName(self, *params):
+    def VarChanged_font(self, *params):
+        '''When one font attribute changes, save them all, as they are
+        not independent from each other. In particular, when we are
+        overriding the default font, we need to write out everything.
+        '''
         value = self.fontName.get()
         self.AddChangedItem('main', 'EditorWindow', 'font', value)
-
-    def VarChanged_fontBold(self, *params):
+        value = self.fontSize.get()
+        self.AddChangedItem('main', 'EditorWindow', 'font-size', value)
         value = self.fontBold.get()
         self.AddChangedItem('main', 'EditorWindow', 'font-bold', value)
 
@@ -958,24 +958,24 @@ class ConfigDialog(Toplevel):
         fonts.sort()
         for font in fonts:
             self.listFontName.insert(END, font)
-        configuredFont = idleConf.GetOption(
-                'main', 'EditorWindow', 'font', default='courier')
-        lc_configuredFont = configuredFont.lower()
-        self.fontName.set(lc_configuredFont)
+        configuredFont = idleConf.GetFont(self, 'main', 'EditorWindow')
+        fontName = configuredFont[0].lower()
+        fontSize = configuredFont[1]
+        fontBold  = configuredFont[2]=='bold'
+        self.fontName.set(fontName)
         lc_fonts = [s.lower() for s in fonts]
-        if lc_configuredFont in lc_fonts:
-            currentFontIndex = lc_fonts.index(lc_configuredFont)
+        try:
+            currentFontIndex = lc_fonts.index(fontName)
             self.listFontName.see(currentFontIndex)
             self.listFontName.select_set(currentFontIndex)
             self.listFontName.select_anchor(currentFontIndex)
+        except ValueError:
+            pass
         ##font size dropdown
-        fontSize = idleConf.GetOption(
-                'main', 'EditorWindow', 'font-size', type='int', default='10')
         self.optMenuFontSize.SetMenu(('7', '8', '9', '10', '11', '12', '13',
                                       '14', '16', '18', '20', '22'), fontSize )
         ##fontWeight
-        self.fontBold.set(idleConf.GetOption(
-                'main', 'EditorWindow', 'font-bold', default=0, type='bool'))
+        self.fontBold.set(fontBold)
         ##font sample
         self.SetFontSample()
 
diff --git a/Lib/idlelib/configHandler.py b/Lib/idlelib/configHandler.py
index b94b8f1..db3bcbc 100644
--- a/Lib/idlelib/configHandler.py
+++ b/Lib/idlelib/configHandler.py
@@ -22,6 +22,7 @@ import os
 import sys
 
 from configparser import ConfigParser
+from tkinter.font import Font, nametofont
 
 class InvalidConfigType(Exception): pass
 class InvalidConfigSet(Exception): pass
@@ -670,6 +671,32 @@ class IdleConf:
                 self.GetExtraHelpSourceList('user') )
         return allHelpSources
 
+    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')
+
     def LoadCfgFiles(self):
         "Load all configuration files."
         for key in self.defaultCfg:
-- 
cgit v0.12

