Speeds up font compilation by around 200%

Cython is used to compile some hot paths into native Python extensions.
These hot paths were identified through running ufocompile with the hotshot
profiler and then converting file by file to Cython, starting with the "hottest"
paths and continuing until returns were deminishing. This means that only a few
Python files were converted to Cython.

Closes #23
Closes #20 (really this time)
This commit is contained in:
Rasmus Andersson 2017-09-03 23:03:17 -04:00
parent 31ae014e0c
commit 8234b62ab7
108 changed files with 26933 additions and 110 deletions

View file

@ -0,0 +1,14 @@
"""
Directory for interface related modules. Stuff like widgets,
dialog modules. Please keep them sorted by platform.
interfaces/all : modules that are platform independent
interfaces/mac : modules that are mac specific
interfaces/win : modules that are windows specific
"""

View file

@ -0,0 +1,14 @@
"""
Directory for interface related modules. Stuff like widgets,
dialog modules. Please keep them sorted by platform.
interfaces/all : modules that are platform independent
interfaces/mac : modules that are mac specific
interfaces/win : modules that are windows specific
"""

View file

@ -0,0 +1,278 @@
"""
Restructured dialogs for Robofab
dialog file dialogs
* FontLab 5.04 10.6 dialogKit fl internal * theoretically that should work under windows as well, untested
* FontLab 5.1 10.6 dialogKit fl internal
* FontLab 5.1 10.7 raw cocao fl internal
Glyphs any vanilla vanilla
RoboFont any vanilla vanilla
This module does a fair amount of sniffing in order to guess
which dialogs to load. Linux and Windows environments are
underrepresented at the moment. Following the prototypes in dialogs_default.py
it is possible (with knowledge of the platform) to extend support.
The platformApplicationSupport table contains very specific
versions with which certain apps need to work. Moving forward,
it is likely that these versions will change and need to be updated.
# this calls the new dialogs infrastructure:
from robofab.interface.all.dialogs import Message
# this calls the old original legacy dialogs infrastructure:
from robofab.interface.all.dialogs_legacy import Message
"""
# determine platform and application
import sys, os
import platform as _platform
__verbose__ = False
platform = None
platformVersion = None
application = None
applicationVersion = None
if sys.platform in (
'mac',
'darwin',
):
platform = "mac"
v = _platform.mac_ver()[0]
platformVersion = float('.'.join(v.split('.')[:2]))
elif sys.platform in (
'linux1',
'linux2', # Ubuntu = others?
):
platform = "linux"
elif os.name == 'nt':
platform = "win"
# determine application
try:
# FontLab
# alternative syntax to cheat on the FL import filtering in RF
__import__("FL")
application = "fontlab"
#applicationVersion = fl.version
except ImportError:
pass
if application is None:
try:
# RoboFont
import mojo
application = 'robofont'
try:
from AppKit import NSBundle
b = NSBundle.mainBundle()
applicationVersion = b.infoDictionary()["CFBundleVersion"]
except ImportError:
pass
except ImportError:
pass
if application is None:
try:
# Glyphs
import GlyphsApp
application = "glyphs"
except ImportError:
pass
if application is None:
try:
# fontforge
# note that in some configurations, fontforge can be imported in other pythons as well
# so the availability of the fontforge module is no garuantee that we are in fontforge.
import fontforge
application = "fontforge"
except ImportError:
pass
pyVersion = sys.version_info[:3]
# with that out of the way, perhaps we can have a look at where we are
# and which modules we have available. This maps any number of platform / application
# combinations so an independent list of module names. That should make it
# possible to map multiple things to one module.
platformApplicationSupport = [
#
# switchboard for platform, application, python version -> dialog implementations
# platform applicatiom python sub module
# | | | |
('mac', 'fontlab', (2,3,5), "dialogs_fontlab_legacy1"),
# because FontLab 5.01 and earlier on 2.3.5 can run EasyDialogs
# | | | |
# because FontLab 5.1 on mac 10.6 should theoretically be able to run cocoa dialogs,
# but they are very unreliable. So until we know what's going on, FL5.1 on 10.6
# is going to have to live with DialogKit dialogs.
# | | | |
('mac', 'fontlab', None, "dialogs_fontlab_legacy2"),
# because FontLab 5.1 on mac, 10.7+ should run cocoa / vanilla
# | | | |
('mac', None, None, "dialogs_mac_vanilla"),
# perhaps nonelab scripts can run vanilla as well?
# | | | |
('win', None, None, "dialogs_legacy"),
# older windows stuff might be able to use the legacy dialogs
]
platformModule = None
foundPlatformModule = False
dialogs = {}
if __verbose__:
print "robofab.interface.all __init__ - finding out where we were."
# do we have a support module?
for pl, app, py, platformApplicationModuleName in platformApplicationSupport:
if __verbose__:
print "looking at", pl, app, py, platformApplicationModuleName
if pl is None or pl == platform:
if app is None or app == application:
if py is None or py == pyVersion:
break
if __verbose__:
print "nope"
if __verbose__:
print "searched for", pl, app, py, platformApplicationModuleName
# preload the namespace with default functions that do nothing but raise NotImplementedError
from robofab.interface.all.dialogs_default import *
# now import the module we selected.
if platformApplicationModuleName == "dialogs_fontlab_legacy1":
try:
from robofab.interface.all.dialogs_fontlab_legacy1 import *
foundPlatformModule = True
if __verbose__:
print "loaded robofab.interface.all.dialogs_fontlab_legacy1"
if platform == "mac":
from robofab.interface.mac.getFileOrFolder import GetFile, GetFileOrFolder
except ImportError:
print "can't import", platformApplicationModuleName
elif platformApplicationModuleName == "dialogs_fontlab_legacy2":
try:
from robofab.interface.all.dialogs_fontlab_legacy2 import *
foundPlatformModule = True
if __verbose__:
print "loaded robofab.interface.all.dialogs_fontlab_legacy2"
if platform == "mac":
#
#
#
#
#
from robofab.interface.all.dialogs_legacy import AskString, TwoChecks, TwoFields, SelectGlyph, FindGlyph, OneList, SearchList, SelectFont, SelectGlyph
except ImportError:
print "can't import", platformApplicationModuleName
elif platformApplicationModuleName == "dialogs_mac_vanilla":
try:
from robofab.interface.all.dialogs_mac_vanilla import *
foundPlatformModule = True
if __verbose__:
print "loaded robofab.interface.all.dialogs_mac_vanilla"
except ImportError:
print "can't import", platformApplicationModuleName
elif platformApplicationModuleName == "dialogs_legacy":
try:
from robofab.interface.all.dialogs_legacy import *
foundPlatformModule = True
if __verbose__:
print "loaded robofab.interface.all.dialogs_legacy"
except ImportError:
print "can't import", platformApplicationModuleName
__all__ = [
"AskString",
"AskYesNoCancel",
"FindGlyph",
"GetFile",
"GetFolder",
"GetFileOrFolder",
"Message",
"OneList",
"PutFile",
"SearchList",
"SelectFont",
"SelectGlyph",
"TwoChecks",
"TwoFields",
"ProgressBar",
]
def test():
""" This is a test that prints the available functions and where they're imported from.
The report can be useful for debugging.
For instance:
from robofab.interface.all.dialogs import test
test()
testing RoboFab Dialogs:
python version: (2, 7, 1)
platform: mac
application: None
applicationVersion: None
platformVersion: 10.7
looking for module: dialogs_mac_vanilla
did we find it? True
Available dialogs and source:
AskString robofab.interface.all.dialogs_mac_vanilla
AskYesNoCancel robofab.interface.all.dialogs_mac_vanilla
FindGlyph robofab.interface.all.dialogs_mac_vanilla
GetFile robofab.interface.all.dialogs_mac_vanilla
GetFolder robofab.interface.all.dialogs_mac_vanilla
GetFileOrFolder robofab.interface.all.dialogs_mac_vanilla
Message robofab.interface.all.dialogs_mac_vanilla
OneList robofab.interface.all.dialogs_mac_vanilla
PutFile robofab.interface.all.dialogs_mac_vanilla
SearchList robofab.interface.all.dialogs_mac_vanilla
SelectFont robofab.interface.all.dialogs_mac_vanilla
SelectGlyph robofab.interface.all.dialogs_mac_vanilla
TwoChecks robofab.interface.all.dialogs_default
TwoFields robofab.interface.all.dialogs_default
ProgressBar robofab.interface.all.dialogs_mac_vanilla
"""
print
print "testing RoboFab Dialogs:"
print "\tpython version:", pyVersion
print "\tplatform:", platform
print "\tapplication:", application
print "\tapplicationVersion:", applicationVersion
print "\tplatformVersion:", platformVersion
print "\tlooking for module:", platformApplicationModuleName
print "\t\tdid we find it?", foundPlatformModule
print
print "Available dialogs and source:"
for name in __all__:
if name in globals().keys():
print "\t", name, "\t", globals()[name].__module__
else:
print "\t", name, "\t not loaded."
if __name__ == "__main__":
test()

View file

@ -0,0 +1,76 @@
"""
Dialog prototypes.
These are loaded before any others. So if a specific platform implementation doesn't
have all functions, these will make sure a NotImplemtedError is raised.
http://www.robofab.org/tools/dialogs.html
"""
__all__ = [
"AskString",
"AskYesNoCancel",
"FindGlyph",
"GetFile",
"GetFolder",
"GetFileOrFolder",
"Message",
"OneList",
"PutFile",
"SearchList",
"SelectFont",
"SelectGlyph",
"TwoChecks",
"TwoFields",
"ProgressBar",
]
# start with all the defaults.
def AskString(message, value='', title='RoboFab'):
raise NotImplementedError
def AskYesNoCancel(message, title='RoboFab', default=0):
raise NotImplementedError
def FindGlyph(font, message="Search for a glyph:", title='RoboFab'):
raise NotImplementedError
def GetFile(message=None):
raise NotImplementedError
def GetFolder(message=None):
raise NotImplementedError
def GetFileOrFolder(message=None):
raise NotImplementedError
def Message(message, title='RoboFab'):
raise NotImplementedError
def OneList(list, message="Select an item:", title='RoboFab'):
raise PendingDeprecationWarning
def PutFile(message=None, fileName=None):
raise NotImplementedError
def SearchList(list, message="Select an item:", title='RoboFab'):
raise NotImplementedError
def SelectFont(message="Select a font:", title='RoboFab'):
raise NotImplementedError
def SelectGlyph(font, message="Select a glyph:", title='RoboFab'):
raise NotImplementedError
def TwoChecks(title_1="One", title_2="Two", value1=1, value2=1, title='RoboFab'):
raise PendingDeprecationWarning
def TwoFields(title_1="One:", value_1="0", title_2="Two:", value_2="0", title='RoboFab'):
raise PendingDeprecationWarning
class ProgressBar(object):
pass

View file

@ -0,0 +1,73 @@
"""
Dialogs for FontLab < 5.1.
This one should be loaded for various platforms, using dialogKit
http://www.robofab.org/tools/dialogs.html
"""
from FL import *
from dialogKit import ModalDialog, Button, TextBox, EditText
__all__ = [
#"AskString",
#"AskYesNoCancel",
#"FindGlyph",
"GetFile",
"GetFolder",
#"Message",
#"OneList",
#"PutFile",
#"SearchList",
#"SelectFont",
#"SelectGlyph",
#"TwoChecks",
#"TwoFields",
"ProgressBar",
]
def GetFile(message=None, title=None, directory=None, fileName=None, allowsMultipleSelection=False, fileTypes=None):
strFilter = "All Files (*.*)|*.*|"
defaultExt = ""
# using fontlab's internal file dialogs
return fl.GetFileName(1, defaultExt, message, strFilter)
def GetFolder(message=None, title=None, directory=None, allowsMultipleSelection=False):
# using fontlab's internal file dialogs
if message is None:
message = ""
return fl.GetPathName(message)
def PutFile(message=None, fileName=None):
# using fontlab's internal file dialogs
# message is not used
if message is None:
message = ""
if fileName is None:
fileName = ""
defaultExt = ""
return fl.GetFileName(0, defaultExt, fileName, '')
class ProgressBar(object):
def __init__(self, title="RoboFab...", ticks=0, label=""):
self._tickValue = 1
fl.BeginProgress(title, ticks)
def getCurrentTick(self):
return self._tickValue
def tick(self, tickValue=None):
if not tickValue:
tickValue = self._tickValue
fl.TickProgress(tickValue)
self._tickValue = tickValue + 1
def label(self, label):
pass
def close(self):
fl.EndProgress()

View file

@ -0,0 +1,373 @@
"""
Dialogs for FontLab 5.1.
This might work in future versions of FontLab as well.
This is basically a butchered version of vanilla.dialogs.
No direct import of, or dependency on Vanilla
March 7 2012
It seems only the dialogs that deal with the file system
need to be replaced, the other dialogs still work.
As we're not entirely sure whether it is worth to maintain
these dialogs, let's fix the imports in dialogs.py.
This is the phenolic aldehyde version of dialogs.
"""
#__import__("FL")
from FL import *
from Foundation import NSObject
from AppKit import NSApplication, NSInformationalAlertStyle, objc, NSAlert, NSAlertFirstButtonReturn, NSAlertSecondButtonReturn, NSAlertThirdButtonReturn, NSSavePanel, NSOKButton, NSOpenPanel
NSApplication.sharedApplication()
__all__ = [
# "AskString",
"AskYesNoCancel",
# "FindGlyph",
"GetFile",
"GetFolder",
"GetFileOrFolder",
"Message",
# "OneList",
"PutFile",
# "SearchList",
# "SelectFont",
# "SelectGlyph",
# "TwoChecks",
# "TwoFields",
"ProgressBar",
]
class BaseMessageDialog(NSObject):
def initWithMessageText_informativeText_alertStyle_buttonTitlesValues_window_resultCallback_(self,
messageText="",
informativeText="",
alertStyle=NSInformationalAlertStyle,
buttonTitlesValues=None,
parentWindow=None,
resultCallback=None):
if buttonTitlesValues is None:
buttonTitlesValues = []
self = super(BaseMessageDialog, self).init()
self.retain()
self._resultCallback = resultCallback
self._buttonTitlesValues = buttonTitlesValues
#
alert = NSAlert.alloc().init()
alert.setMessageText_(messageText)
alert.setInformativeText_(informativeText)
alert.setAlertStyle_(alertStyle)
for buttonTitle, value in buttonTitlesValues:
alert.addButtonWithTitle_(buttonTitle)
self._value = None
code = alert.runModal()
self._translateValue(code)
return self
def _translateValue(self, code):
if code == NSAlertFirstButtonReturn:
value = 1
elif code == NSAlertSecondButtonReturn:
value = 2
elif code == NSAlertThirdButtonReturn:
value = 3
else:
value = code - NSAlertThirdButtonReturn + 3
self._value = self._buttonTitlesValues[value-1][1]
def windowWillClose_(self, notification):
self.autorelease()
class BasePutGetPanel(NSObject):
def initWithWindow_resultCallback_(self, parentWindow=None, resultCallback=None):
self = super(BasePutGetPanel, self).init()
self.retain()
self._parentWindow = parentWindow
self._resultCallback = resultCallback
return self
def windowWillClose_(self, notification):
self.autorelease()
class PutFilePanel(BasePutGetPanel):
def initWithWindow_resultCallback_(self, parentWindow=None, resultCallback=None):
self = super(PutFilePanel, self).initWithWindow_resultCallback_(parentWindow, resultCallback)
self.messageText = None
self.title = None
self.fileTypes = None
self.directory = None
self.fileName = None
self.canCreateDirectories = True
self.accessoryView = None
self._result = None
return self
def run(self):
panel = NSSavePanel.alloc().init()
if self.messageText:
panel.setMessage_(self.messageText)
if self.title:
panel.setTitle_(self.title)
if self.directory:
panel.setDirectory_(self.directory)
if self.fileTypes:
panel.setAllowedFileTypes_(self.fileTypes)
panel.setCanCreateDirectories_(self.canCreateDirectories)
panel.setCanSelectHiddenExtension_(True)
panel.setAccessoryView_(self.accessoryView)
if self._parentWindow is not None:
panel.beginSheetForDirectory_file_modalForWindow_modalDelegate_didEndSelector_contextInfo_(
self.directory, self.fileName, self._parentWindow, self, "savePanelDidEnd:returnCode:contextInfo:", 0)
else:
isOK = panel.runModalForDirectory_file_(self.directory, self.fileName)
if isOK == NSOKButton:
self._result = panel.filename()
def savePanelDidEnd_returnCode_contextInfo_(self, panel, returnCode, context):
panel.close()
if returnCode:
self._result = panel.filename()
if self._resultCallback is not None:
self._resultCallback(self._result)
savePanelDidEnd_returnCode_contextInfo_ = objc.selector(savePanelDidEnd_returnCode_contextInfo_, signature="v@:@ii")
class GetFileOrFolderPanel(BasePutGetPanel):
def initWithWindow_resultCallback_(self, parentWindow=None, resultCallback=None):
self = super(GetFileOrFolderPanel, self).initWithWindow_resultCallback_(parentWindow, resultCallback)
self.messageText = None
self.title = None
self.directory = None
self.fileName = None
self.fileTypes = None
self.allowsMultipleSelection = False
self.canChooseDirectories = True
self.canChooseFiles = True
self.resolvesAliases = True
self._result = None
return self
def run(self):
panel = NSOpenPanel.alloc().init()
if self.messageText:
panel.setMessage_(self.messageText)
if self.title:
panel.setTitle_(self.title)
if self.directory:
panel.setDirectory_(self.directory)
if self.fileTypes:
panel.setAllowedFileTypes_(self.fileTypes)
panel.setCanChooseDirectories_(self.canChooseDirectories)
panel.setCanChooseFiles_(self.canChooseFiles)
panel.setAllowsMultipleSelection_(self.allowsMultipleSelection)
panel.setResolvesAliases_(self.resolvesAliases)
if self._parentWindow is not None:
panel.beginSheetForDirectory_file_types_modalForWindow_modalDelegate_didEndSelector_contextInfo_(
self.directory, self.fileName, self.fileTypes, self._parentWindow, self, "openPanelDidEnd:returnCode:contextInfo:", 0)
else:
isOK = panel.runModalForDirectory_file_types_(self.directory, self.fileName, self.fileTypes)
if isOK == NSOKButton:
self._result = panel.filenames()
def openPanelDidEnd_returnCode_contextInfo_(self, panel, returnCode, context):
panel.close()
if returnCode:
self._result = panel.filenames()
if self._resultCallback is not None:
self._resultCallback(self._result)
openPanelDidEnd_returnCode_contextInfo_ = objc.selector(openPanelDidEnd_returnCode_contextInfo_, signature="v@:@ii")
def Message(message="", title='noLongerUsed', informativeText=""):
"""Legacy robofab dialog compatible wrapper."""
#def _message(messageText="", informativeText="", alertStyle=NSInformationalAlertStyle, parentWindow=None, resultCallback=None):
resultCallback = None
alert = BaseMessageDialog.alloc().initWithMessageText_informativeText_alertStyle_buttonTitlesValues_window_resultCallback_(
messageText=message,
informativeText=informativeText,
alertStyle=NSInformationalAlertStyle,
buttonTitlesValues=[("OK", 1)],
parentWindow=None,
resultCallback=None)
if resultCallback is None:
return 1
def AskYesNoCancel(message, title='noLongerUsed', default=None, informativeText=""):
"""
AskYesNoCancel Dialog
message the string
title* a title of the window
(may not be supported everywhere)
default* index number of which button should be default
(i.e. respond to return)
informativeText* A string with secundary information
* may not be supported everywhere
"""
parentWindow = None
alert = BaseMessageDialog.alloc().initWithMessageText_informativeText_alertStyle_buttonTitlesValues_window_resultCallback_(
messageText=message,
informativeText=informativeText,
alertStyle=NSInformationalAlertStyle,
buttonTitlesValues=[("Cancel", -1), ("Yes", 1), ("No", 0)],
parentWindow=None,
resultCallback=None)
return alert._value
def _askYesNo(messageText="", informativeText="", alertStyle=NSInformationalAlertStyle, parentWindow=None, resultCallback=None):
parentWindow = None
alert = BaseMessageDialog.alloc().initWithMessageText_informativeText_alertStyle_buttonTitlesValues_window_resultCallback_(
messageText=messageText, informativeText=informativeText, alertStyle=alertStyle, buttonTitlesValues=[("Yes", 1), ("No", 0)], parentWindow=parentWindow, resultCallback=resultCallback)
if resultCallback is None:
return alert._value
def GetFile(message=None, title=None, directory=None, fileName=None, allowsMultipleSelection=False, fileTypes=None):
""" Legacy robofab dialog compatible wrapper.
This will select UFO on OSX 10.7, FL5.1
"""
parentWindow = None
resultCallback=None
basePanel = GetFileOrFolderPanel.alloc().initWithWindow_resultCallback_(parentWindow, resultCallback)
basePanel.messageText = message
basePanel.title = title
basePanel.directory = directory
basePanel.fileName = fileName
basePanel.fileTypes = fileTypes
basePanel.allowsMultipleSelection = allowsMultipleSelection
basePanel.canChooseDirectories = False
basePanel.canChooseFiles = True
basePanel.run()
if basePanel._result is None:
return None
if not allowsMultipleSelection:
# compatibly return only one as we expect
return str(list(basePanel._result)[0])
else:
# return more if we explicitly expect
return [str(n) for n in list(basePanel._result)]
def GetFolder(message=None, title=None, directory=None, allowsMultipleSelection=False):
parentWindow = None
resultCallback = None
basePanel = GetFileOrFolderPanel.alloc().initWithWindow_resultCallback_(parentWindow, resultCallback)
basePanel.messageText = message
basePanel.title = title
basePanel.directory = directory
basePanel.allowsMultipleSelection = allowsMultipleSelection
basePanel.canChooseDirectories = True
basePanel.canChooseFiles = False
basePanel.run()
if basePanel._result is None:
return None
if not allowsMultipleSelection:
# compatibly return only one as we expect
return str(list(basePanel._result)[0])
else:
# return more if we explicitly expect
return [str(n) for n in list(basePanel._result)]
def GetFileOrFolder(message=None, title=None, directory=None, fileName=None, allowsMultipleSelection=False, fileTypes=None, parentWindow=None, resultCallback=None):
parentWindow = None
basePanel = GetFileOrFolderPanel.alloc().initWithWindow_resultCallback_(parentWindow, resultCallback)
basePanel.messageText = message
basePanel.title = title
basePanel.directory = directory
basePanel.fileName = fileName
basePanel.fileTypes = fileTypes
basePanel.allowsMultipleSelection = allowsMultipleSelection
basePanel.canChooseDirectories = True
basePanel.canChooseFiles = True
basePanel.run()
if basePanel._result is None:
return None
if not allowsMultipleSelection:
# compatibly return only one as we expect
return str(list(basePanel._result)[0])
else:
# return more if we explicitly expect
return [str(n) for n in list(basePanel._result)]
def PutFile(message=None, title=None, directory=None, fileName=None, canCreateDirectories=True, fileTypes=None):
parentWindow = None
resultCallback=None
accessoryView=None
basePanel = PutFilePanel.alloc().initWithWindow_resultCallback_(parentWindow, resultCallback)
basePanel.messageText = message
basePanel.title = title
basePanel.directory = directory
basePanel.fileName = fileName
basePanel.fileTypes = fileTypes
basePanel.canCreateDirectories = canCreateDirectories
basePanel.accessoryView = accessoryView
basePanel.run()
return str(basePanel._result)
class ProgressBar(object):
def __init__(self, title="RoboFab...", ticks=0, label=""):
self._tickValue = 1
fl.BeginProgress(title, ticks)
def getCurrentTick(self):
return self._tickValue
def tick(self, tickValue=None):
if not tickValue:
tickValue = self._tickValue
fl.TickProgress(tickValue)
self._tickValue = tickValue + 1
def label(self, label):
pass
def close(self):
fl.EndProgress()
# we seem to have problems importing from here.
# so let's see what happens if we make the robofab compatible wrappers here as well.
# start with all the defaults.
#def AskString(message, value='', title='RoboFab'):
# raise NotImplementedError
#def FindGlyph(aFont, message="Search for a glyph:", title='RoboFab'):
# raise NotImplementedError
#def OneList(list, message="Select an item:", title='RoboFab'):
# raise NotImplementedError
#def PutFile(message=None, fileName=None):
# raise NotImplementedError
#def SearchList(list, message="Select an item:", title='RoboFab'):
# raise NotImplementedError
#def SelectFont(message="Select a font:", title='RoboFab'):
# raise NotImplementedError
#def SelectGlyph(font, message="Select a glyph:", title='RoboFab'):
# raise NotImplementedError
#def TwoChecks(title_1="One", title_2="Two", value1=1, value2=1, title='RoboFab'):
# raise NotImplementedError
#def TwoFields(title_1="One:", value_1="0", title_2="Two:", value_2="0", title='RoboFab'):
# raise NotImplementedError

View file

@ -0,0 +1,737 @@
"""
Dialogs.
Cross-platform and cross-application compatible. Some of them anyway.
(Not all dialogs work on PCs outside of FontLab. Some dialogs are for FontLab only. Sorry.)
Mac and FontLab implementation written by the RoboFab development team.
PC implementation by Eigi Eigendorf and is (C)2002 Eigi Eigendorf.
"""
import os
import sys
from robofab import RoboFabError
from warnings import warn
MAC = False
PC = False
haveMacfs = False
if sys.platform in ('mac', 'darwin'):
MAC = True
elif os.name == 'nt':
PC = True
else:
warn("dialogs.py only supports Mac and PC platforms.")
pyVersion = sys.version_info[:3]
inFontLab = False
try:
from FL import *
inFontLab = True
except ImportError: pass
try:
import W
hasW = True
except ImportError:
hasW = False
try:
import dialogKit
hasDialogKit = True
except ImportError:
hasDialogKit = False
try:
import EasyDialogs
hasEasyDialogs = True
except:
hasEasyDialogs = False
if MAC:
if pyVersion < (2, 3, 0):
import macfs
haveMacfs = True
elif PC and not inFontLab:
from win32com.shell import shell
import win32ui
import win32con
def _raisePlatformError(dialog):
"""error raiser"""
if MAC:
p = 'Macintosh'
elif PC:
p = 'PC'
else:
p = sys.platform
raise RoboFabError("%s is not currently available on the %s platform"%(dialog, p))
class _FontLabDialogOneList:
"""A one list dialog for FontLab. This class should not be called directly. Use the OneList function."""
def __init__(self, list, message, title='RoboFab'):
self.message = message
self.selected = None
self.list = list
self.d = Dialog(self)
self.d.size = Point(250, 250)
self.d.title = title
self.d.Center()
self.d.AddControl(LISTCONTROL, Rect(12, 30, 238, 190), "list", STYLE_LIST, self.message)
self.list_index = 0
def Run(self):
return self.d.Run()
def on_cancel(self, code):
self.selected = None
def on_ok(self, code):
self.d.GetValue('list')
# Since FLS v5.2, the GetValue() method of the Dialog() class returns
# a 'wrong' index value from the specified LISTCONTROL.
# If the selected index is n, it will return n-1. For example, when
# the index is 1, it returns 0; when it's 2, it returns 1, and so on.
# If the selection is empty, FLS v5.2 returns -2, while the old v5.0
# returned None.
# See also:
# - http://forum.fontlab.com/index.php?topic=8807.0
# - http://forum.fontlab.com/index.php?topic=9003.0
#
# Edited based on feedback from Adam Twardoch
if fl.buildnumber > 4600 and sys.platform == 'win32':
if self.list_index == -2:
self.selected = None
else:
self.selected = self.list_index + 1
else:
self.selected = self.list_index
class _FontLabDialogSearchList:
"""A dialog for searching through a list. It contains a text field and a results list FontLab. This class should not be called directly. Use the SearchList function."""
def __init__(self, aList, message, title="RoboFab"):
self.d = Dialog(self)
self.d.size = Point(250, 290)
self.d.title = title
self.d.Center()
self.message = message
self._fullContent = aList
self.possibleHits = list(aList)
self.possibleHits.sort()
self.possibleHits_index = 0
self.entryField = ""
self.selected = None
self.d.AddControl(STATICCONTROL, Rect(10, 10, 240, 30), "message", STYLE_LABEL, message)
self.d.AddControl(EDITCONTROL, Rect(10, 30, 240, aAUTO), "entryField", STYLE_EDIT, "")
self.d.AddControl(LISTCONTROL, Rect(12, 60, 238, 230), "possibleHits", STYLE_LIST, "")
def run(self):
self.d.Run()
def on_entryField(self, code):
self.d.GetValue("entryField")
entry = self.entryField
count = len(entry)
possibleHits = [
i for i in self._fullContent
if len(i) >= count
and i[:count] == entry
]
possibleHits.sort()
self.possibleHits = possibleHits
self.possibleHits_index = 0
self.d.PutValue("possibleHits")
def on_ok(self, code):
self.d.GetValue("possibleHits")
sel = self.possibleHits_index
if sel == -1:
self.selected = None
else:
self.selected = self.possibleHits[sel]
def on_cancel(self, code):
self.selected = None
class _FontLabDialogTwoFields:
"""A two field dialog for FontLab. This class should not be called directly. Use the TwoFields function."""
def __init__(self, title_1, value_1, title_2, value_2, title='RoboFab'):
self.d = Dialog(self)
self.d.size = Point(200, 125)
self.d.title = title
self.d.Center()
self.d.AddControl(EDITCONTROL, Rect(120, 10, aIDENT2, aAUTO), "v1edit", STYLE_EDIT, title_1)
self.d.AddControl(EDITCONTROL, Rect(120, 40, aIDENT2, aAUTO), "v2edit", STYLE_EDIT, title_2)
self.v1edit = value_1
self.v2edit = value_2
def Run(self):
return self.d.Run()
def on_cancel(self, code):
self.v1edit = None
self.v2edit = None
def on_ok(self, code):
self.d.GetValue("v1edit")
self.d.GetValue("v2edit")
self.v1 = self.v1edit
self.v2 = self.v2edit
class _FontLabDialogTwoChecks:
"""A two check box dialog for FontLab. This class should not be called directly. Use the TwoChecks function."""
def __init__(self, title_1, title_2, value1=1, value2=1, title='RoboFab'):
self.d = Dialog(self)
self.d.size = Point(200, 105)
self.d.title = title
self.d.Center()
self.d.AddControl(CHECKBOXCONTROL, Rect(10, 10, aIDENT2, aAUTO), "check1", STYLE_CHECKBOX, title_1)
self.d.AddControl(CHECKBOXCONTROL, Rect(10, 30, aIDENT2, aAUTO), "check2", STYLE_CHECKBOX, title_2)
self.check1 = value1
self.check2 = value2
def Run(self):
return self.d.Run()
def on_cancel(self, code):
self.check1 = None
self.check2 = None
def on_ok(self, code):
self.d.GetValue("check1")
self.d.GetValue("check2")
class _FontLabDialogAskString:
"""A one simple string prompt dialog for FontLab. This class should not be called directly. Use the GetString function."""
def __init__(self, message, value, title='RoboFab'):
self.d = Dialog(self)
self.d.size = Point(350, 130)
self.d.title = title
self.d.Center()
self.d.AddControl(STATICCONTROL, Rect(aIDENT, aIDENT, aIDENT, aAUTO), "label", STYLE_LABEL, message)
self.d.AddControl(EDITCONTROL, Rect(aIDENT, 40, aIDENT, aAUTO), "value", STYLE_EDIT, '')
self.value=value
def Run(self):
return self.d.Run()
def on_cancel(self, code):
self.value = None
def on_ok(self, code):
self.d.GetValue("value")
class _FontLabDialogMessage:
"""A simple message dialog for FontLab. This class should not be called directly. Use the SimpleMessage function."""
def __init__(self, message, title='RoboFab'):
self.d = Dialog(self)
self.d.size = Point(350, 130)
self.d.title = title
self.d.Center()
self.d.AddControl(STATICCONTROL, Rect(aIDENT, aIDENT, aIDENT, 80), "label", STYLE_LABEL, message)
def Run(self):
return self.d.Run()
class _FontLabDialogGetYesNoCancel:
"""A yes no cancel message dialog for FontLab. This class should not be called directly. Use the YesNoCancel function."""
def __init__(self, message, title='RoboFab'):
self.d = Dialog(self)
self.d.size = Point(350, 130)
self.d.title = title
self.d.Center()
self.d.ok = 'Yes'
self.d.AddControl(STATICCONTROL, Rect(aIDENT, aIDENT, aIDENT, 80), "label", STYLE_LABEL, message)
self.d.AddControl(BUTTONCONTROL, Rect(100, 95, 172, 115), "button", STYLE_BUTTON, "No")
self.value = 0
def Run(self):
return self.d.Run()
def on_ok(self, code):
self.value = 1
def on_cancel(self, code):
self.value = -1
def on_button(self, code):
self.value = 0
self.d.End()
class _MacOneListW:
"""A one list dialog for Macintosh. This class should not be called directly. Use the OneList function."""
def __init__(self, list, message='Make a selection'):
import W
self.list = list
self.selected = None
self.w = W.ModalDialog((200, 240))
self.w.message = W.TextBox((10, 10, -10, 30), message)
self.w.list = W.List((10, 35, -10, -50), list)
self.w.l = W.HorizontalLine((10, -40, -10, 1), 1)
self.w.cancel = W.Button((10, -30, 87, -10), 'Cancel', self.cancel)
self.w.ok = W.Button((102, -30, 88, -10), 'OK', self.ok)
self.w.setdefaultbutton(self.w.ok)
self.w.bind('cmd.', self.w.cancel.push)
self.w.open()
def ok(self):
if len(self.w.list.getselection()) == 1:
self.selected = self.w.list.getselection()[0]
self.w.close()
def cancel(self):
self.selected = None
self.w.close()
class _MacTwoChecksW:
""" Version using W """
def __init__(self, title_1, title_2, value1=1, value2=1, title='RoboFab'):
import W
self.check1 = value1
self.check2 = value2
self.w = W.ModalDialog((200, 100))
self.w.check1 = W.CheckBox((10, 10, -10, 16), title_1, value=value1)
self.w.check2 = W.CheckBox((10, 35, -10, 16), title_2, value=value2)
self.w.l = W.HorizontalLine((10, 60, -10, 1), 1)
self.w.cancel = W.Button((10, 70, 85, 20), 'Cancel', self.cancel)
self.w.ok = W.Button((105, 70, 85, 20), 'OK', self.ok)
self.w.setdefaultbutton(self.w.ok)
self.w.bind('cmd.', self.w.cancel.push)
self.w.open()
def ok(self):
self.check1 = self.w.check1.get()
self.check2 = self.w.check2.get()
self.w.close()
def cancel(self):
self.check1 = None
self.check2 = None
self.w.close()
class ProgressBar:
def __init__(self, title='RoboFab...', ticks=0, label=''):
"""
A progress bar.
Availability: FontLab, Mac
"""
self._tickValue = 1
if inFontLab:
fl.BeginProgress(title, ticks)
elif MAC and hasEasyDialogs:
import EasyDialogs
self._bar = EasyDialogs.ProgressBar(title, maxval=ticks, label=label)
else:
_raisePlatformError('Progress')
def getCurrentTick(self):
return self._tickValue
def tick(self, tickValue=None):
"""
Tick the progress bar.
Availability: FontLab, Mac
"""
if not tickValue:
tickValue = self._tickValue
if inFontLab:
fl.TickProgress(tickValue)
elif MAC:
self._bar.set(tickValue)
else:
pass
self._tickValue = tickValue + 1
def label(self, label):
"""
Set the label on the progress bar.
Availability: Mac
"""
if inFontLab:
pass
elif MAC:
self._bar.label(label)
else:
pass
def close(self):
"""
Close the progressbar.
Availability: FontLab, Mac
"""
if inFontLab:
fl.EndProgress()
elif MAC:
del self._bar
else:
pass
def SelectFont(message="Select a font:", title='RoboFab'):
"""
Returns font instance if there is one, otherwise it returns None.
Availability: FontLab
"""
from robofab.world import RFont
if inFontLab:
list = []
for i in range(fl.count):
list.append(fl[i].full_name)
name = OneList(list, message, title)
if name is None:
return None
else:
return RFont(fl[list.index(name)])
else:
_raisePlatformError('SelectFont')
def SelectGlyph(font, message="Select a glyph:", title='RoboFab'):
"""
Returns glyph instance if there is one, otherwise it returns None.
Availability: FontLab
"""
from fontTools.misc.textTools import caselessSort
if inFontLab:
tl = font.keys()
list = caselessSort(tl)
glyphname = OneList(list, message, title)
if glyphname is None:
return None
else:
return font[glyphname]
else:
_raisePlatformError('SelectGlyph')
def FindGlyph(font, message="Search for a glyph:", title='RoboFab'):
"""
Returns glyph instance if there is one, otherwise it returns None.
Availability: FontLab
"""
if inFontLab:
glyphname = SearchList(font.keys(), message, title)
if glyphname is None:
return None
else:
return font[glyphname]
else:
_raisePlatformError('SelectGlyph')
def OneList(list, message="Select an item:", title='RoboFab'):
"""
Returns selected item, otherwise it returns None.
Availability: FontLab, Macintosh
"""
if inFontLab:
ol = _FontLabDialogOneList(list, message)
ol.Run()
selected = ol.selected
if selected is None:
return None
else:
try:
return list[selected]
except:
return None
elif MAC:
if hasW:
d = _MacOneListW(list, message)
sel = d.selected
if sel is None:
return None
else:
return list[sel]
else:
_raisePlatformError('OneList')
elif PC:
_raisePlatformError('OneList')
def SearchList(list, message="Select an item:", title='RoboFab'):
"""
Returns selected item, otherwise it returns None.
Availability: FontLab
"""
if inFontLab:
sl = _FontLabDialogSearchList(list, message, title)
sl.run()
selected = sl.selected
if selected is None:
return None
else:
return selected
else:
_raisePlatformError('SearchList')
def TwoFields(title_1="One:", value_1="0", title_2="Two:", value_2="0", title='RoboFab'):
"""
Returns (value 1, value 2).
Availability: FontLab
"""
if inFontLab:
tf = _FontLabDialogTwoFields(title_1, value_1, title_2, value_2, title)
tf.Run()
try:
v1 = tf.v1
v2 = tf.v2
return (v1, v2)
except:
return None
else:
_raisePlatformError('TwoFields')
def TwoChecks(title_1="One", title_2="Two", value1=1, value2=1, title='RoboFab'):
"""
Returns check value:
1 if check box 1 is checked
2 if check box 2 is checked
3 if both are checked
0 if neither are checked
None if cancel is clicked.
Availability: FontLab, Macintosh
"""
tc = None
if inFontLab:
tc = _FontLabDialogTwoChecks(title_1, title_2, value1, value2, title)
tc.Run()
elif MAC:
if hasW:
tc = _MacTwoChecksW(title_1, title_2, value1, value2, title)
else:
_raisePlatformError('TwoChecks')
else:
_raisePlatformError('TwoChecks')
c1 = tc.check1
c2 = tc.check2
if c1 == 1 and c2 == 0:
return 1
elif c1 == 0 and c2 == 1:
return 2
elif c1 == 1 and c2 == 1:
return 3
elif c1 == 0 and c2 == 0:
return 0
else:
return None
def Message(message, title='RoboFab'):
"""
A simple message dialog.
Availability: FontLab, Macintosh
"""
if inFontLab:
_FontLabDialogMessage(message, title).Run()
elif MAC:
import EasyDialogs
EasyDialogs.Message(message)
else:
_raisePlatformError('Message')
def AskString(message, value='', title='RoboFab'):
"""
Returns entered string.
Availability: FontLab, Macintosh
"""
if inFontLab:
askString = _FontLabDialogAskString(message, value, title)
askString.Run()
v = askString.value
if v is None:
return None
else:
return v
elif MAC:
import EasyDialogs
askString = EasyDialogs.AskString(message)
if askString is None:
return None
if len(askString) == 0:
return None
else:
return askString
else:
_raisePlatformError('GetString')
def AskYesNoCancel(message, title='RoboFab', default=0):
"""
Returns 1 for 'Yes', 0 for 'No' and -1 for 'Cancel'.
Availability: FontLab, Macintosh
("default" argument only available on Macintosh)
"""
if inFontLab:
gync = _FontLabDialogGetYesNoCancel(message, title)
gync.Run()
v = gync.value
return v
elif MAC:
import EasyDialogs
gync = EasyDialogs.AskYesNoCancel(message, default=default)
return gync
else:
_raisePlatformError('GetYesNoCancel')
def GetFile(message=None):
"""
Select file dialog. Returns path if one is selected. Otherwise it returns None.
Availability: FontLab, Macintosh, PC
"""
path = None
if MAC:
if haveMacfs:
fss, ok = macfs.PromptGetFile(message)
if ok:
path = fss.as_pathname()
else:
from robofab.interface.mac.getFileOrFolder import GetFile
path = GetFile(message)
elif PC:
if inFontLab:
if not message:
message = ''
path = fl.GetFileName(1, message, '', '')
else:
openFlags = win32con.OFN_FILEMUSTEXIST|win32con.OFN_EXPLORER
mode_open = 1
myDialog = win32ui.CreateFileDialog(mode_open,None,None,openFlags)
myDialog.SetOFNTitle(message)
is_OK = myDialog.DoModal()
if is_OK == 1:
path = myDialog.GetPathName()
else:
_raisePlatformError('GetFile')
return path
def GetFolder(message=None):
"""
Select folder dialog. Returns path if one is selected. Otherwise it returns None.
Availability: FontLab, Macintosh, PC
"""
path = None
if MAC:
if haveMacfs:
fss, ok = macfs.GetDirectory(message)
if ok:
path = fss.as_pathname()
else:
from robofab.interface.mac.getFileOrFolder import GetFileOrFolder
# This _also_ allows the user to select _files_, but given the
# package/folder dichotomy, I think we have no other choice.
path = GetFileOrFolder(message)
elif PC:
if inFontLab:
if not message:
message = ''
path = fl.GetPathName('', message)
else:
myTuple = shell.SHBrowseForFolder(0, None, message, 64)
try:
path = shell.SHGetPathFromIDList(myTuple[0])
except:
pass
else:
_raisePlatformError('GetFile')
return path
GetDirectory = GetFolder
def PutFile(message=None, fileName=None):
"""
Save file dialog. Returns path if one is entered. Otherwise it returns None.
Availability: FontLab, Macintosh, PC
"""
path = None
if MAC:
if haveMacfs:
fss, ok = macfs.StandardPutFile(message, fileName)
if ok:
path = fss.as_pathname()
else:
import EasyDialogs
path = EasyDialogs.AskFileForSave(message, savedFileName=fileName)
elif PC:
if inFontLab:
if not message:
message = ''
if not fileName:
fileName = ''
path = fl.GetFileName(0, message, fileName, '')
else:
openFlags = win32con.OFN_OVERWRITEPROMPT|win32con.OFN_EXPLORER
mode_save = 0
myDialog = win32ui.CreateFileDialog(mode_save, None, fileName, openFlags)
myDialog.SetOFNTitle(message)
is_OK = myDialog.DoModal()
if is_OK == 1:
path = myDialog.GetPathName()
else:
_raisePlatformError('GetFile')
return path
if __name__=='__main__':
import traceback
print "dialogs hasW", hasW
print "dialogs hasDialogKit", hasDialogKit
print "dialogs MAC", MAC
print "dialogs PC", PC
print "dialogs inFontLab", inFontLab
print "dialogs hasEasyDialogs", hasEasyDialogs
def tryDialog(dialogClass, args=None):
print
print "tryDialog:", dialogClass, "with args:", args
try:
if args is not None:
apply(dialogClass, args)
else:
apply(dialogClass)
except:
traceback.print_exc(limit=0)
tryDialog(TwoChecks, ('hello', 'world', 1, 0, 'ugh'))
tryDialog(TwoFields)
tryDialog(TwoChecks, ('hello', 'world', 1, 0, 'ugh'))
tryDialog(OneList, (['a', 'b', 'c'], 'hello world'))
tryDialog(Message, ('hello world',))
tryDialog(AskString, ('hello world',))
tryDialog(AskYesNoCancel, ('hello world',))
try:
b = ProgressBar('hello', 50, 'world')
for i in range(50):
if i == 25:
b.label('ugh.')
b.tick(i)
b.close()
except:
traceback.print_exc(limit=0)

View file

@ -0,0 +1,267 @@
"""
Dialogs for environments that support cocao / vanilla.
"""
import vanilla.dialogs
from AppKit import NSApp, NSModalPanelWindowLevel, NSWindowCloseButton, NSWindowZoomButton, NSWindowMiniaturizeButton
__all__ = [
"AskString",
"AskYesNoCancel",
"FindGlyph",
"GetFile",
"GetFileOrFolder",
"GetFolder",
"Message",
"OneList",
"PutFile",
"SearchList",
"SelectFont",
"SelectGlyph",
# "TwoChecks",
# "TwoFields",
"ProgressBar",
]
class _ModalWindow(vanilla.Window):
nsWindowLevel = NSModalPanelWindowLevel
def __init__(self, *args, **kwargs):
super(_ModalWindow, self).__init__(*args, **kwargs)
self._window.standardWindowButton_(NSWindowCloseButton).setHidden_(True)
self._window.standardWindowButton_(NSWindowZoomButton).setHidden_(True)
self._window.standardWindowButton_(NSWindowMiniaturizeButton).setHidden_(True)
def open(self):
super(_ModalWindow, self).open()
self.center()
NSApp().runModalForWindow_(self._window)
def windowWillClose_(self, notification):
super(_ModalWindow, self).windowWillClose_(notification)
NSApp().stopModal()
class _baseWindowController(object):
def setUpBaseWindowBehavior(self):
self._getValue = None
self.w.okButton = vanilla.Button((-70, -30, -15, 20), "OK", callback=self.okCallback, sizeStyle="small")
self.w.setDefaultButton(self.w.okButton)
self.w.closeButton = vanilla.Button((-150, -30, -80, 20), "Cancel", callback=self.closeCallback, sizeStyle="small")
self.w.closeButton.bind(".", ["command"])
self.w.closeButton.bind(unichr(27), [])
self.cancelled = False
def okCallback(self, sender):
self.w.close()
def closeCallback(self, sender):
self.cancelled = True
self.w.close()
def get(self):
raise NotImplementedError
class _AskStringController(_baseWindowController):
def __init__(self, message, value, title):
self.w = _ModalWindow((370, 110), title)
self.w.infoText = vanilla.TextBox((15, 10, -15, 22), message)
self.w.input = vanilla.EditText((15, 40, -15, 22))
self.w.input.set(value)
self.setUpBaseWindowBehavior()
self.w.open()
def get(self):
if self.cancelled:
return None
return self.w.input.get()
class _listController(_baseWindowController):
def __init__(self, items, message, title, showSearch=False):
self.items = items
self.w = _ModalWindow((350, 300), title)
y = 10
self.w.infoText = vanilla.TextBox((15, y, -15, 22), message)
y += 25
if showSearch:
self.w.search = vanilla.SearchBox((15, y, -15, 22), callback=self.searchCallback)
y += 25
self.w.itemList = vanilla.List((15, y, -15, -40), self.items, allowsMultipleSelection=False)
self.setUpBaseWindowBehavior()
self.w.open()
def searchCallback(self, sender):
search = sender.get()
newItems = [item for item in self.items if repr(item).startswith(search)]
self.w.itemList.set(newItems)
if newItems:
self.w.itemList.setSelection([0])
def get(self):
index = self.w.itemList.getSelection()
if index:
index = index[0]
return self.w.itemList[index]
return None
def AskString(message, value='', title='RoboFab'):
"""
AskString Dialog
message the string
value a default value
title a title of the window (may not be supported everywhere)
"""
w = _AskStringController(message, value, title)
return w.get()
def AskYesNoCancel(message, title='RoboFab', default=0, informativeText=""):
"""
AskYesNoCancel Dialog
message the string
title* a title of the window
(may not be supported everywhere)
default* index number of which button should be default
(i.e. respond to return)
informativeText* A string with secundary information
* may not be supported everywhere
"""
return vanilla.dialogs.askYesNoCancel(messageText=message, informativeText=informativeText)
def FindGlyph(aFont, message="Search for a glyph:", title='RoboFab'):
items = aFont.keys()
items.sort()
w = _listController(items, message, title, showSearch=True)
glyphName = w.get()
if glyphName is not None:
return aFont[glyphName]
return None
def GetFile(message=None, title=None, directory=None, fileName=None, allowsMultipleSelection=False, fileTypes=None):
result = vanilla.dialogs.getFile(messageText=message, title=title, directory=directory, fileName=fileName, allowsMultipleSelection=allowsMultipleSelection, fileTypes=fileTypes)
if result is None:
return None
if not allowsMultipleSelection:
return str(list(result)[0])
else:
return [str(n) for n in list(result)]
def GetFolder(message=None, title=None, directory=None, allowsMultipleSelection=False):
result = vanilla.dialogs.getFolder(messageText=message, title=title, directory=directory, allowsMultipleSelection=allowsMultipleSelection)
if result is None:
return None
if not allowsMultipleSelection:
return str(list(result)[0])
else:
return [str(n) for n in list(result)]
def GetFileOrFolder(message=None, title=None, directory=None, fileName=None, allowsMultipleSelection=False, fileTypes=None):
result = vanilla.dialogs.getFileOrFolder(messageText=message, title=title, directory=directory, fileName=fileName, allowsMultipleSelection=allowsMultipleSelection, fileTypes=fileTypes)
if result is None:
return None
if not allowsMultipleSelection:
return str(list(result)[0])
else:
return [str(n) for n in list(result)]
def Message(message, title='RoboFab', informativeText=""):
vanilla.dialogs.message(messageText=message, informativeText=informativeText)
def OneList(items, message="Select an item:", title='RoboFab'):
w = _listController(items, message, title, showSearch=False)
return w.get()
def PutFile(message=None, fileName=None):
return vanilla.dialogs.putFile(messageText=message, fileName=fileName)
def SearchList(list, message="Select an item:", title='RoboFab'):
w = _listController(list, message, title, showSearch=True)
return w.get()
def SelectFont(message="Select a font:", title='RoboFab', allFonts=None):
if allFonts is None:
from robofab.world import AllFonts
fonts = AllFonts()
else:
fonts = allFonts
data = dict()
for font in fonts:
data["%s" %font] = font
items = data.keys()
items.sort()
w = _listController(items, message, title, showSearch=False)
value = w.get()
return data.get(value, None)
def SelectGlyph(aFont, message="Select a glyph:", title='RoboFab'):
items = aFont.keys()
items.sort()
w = _listController(items, message, title, showSearch=False)
glyphName = w.get()
if glyphName is not None:
return aFont[glyphName]
return None
def TwoChecks(title_1="One", title_2="Two", value1=1, value2=1, title='RoboFab'):
raise NotImplementedError
def TwoFields(title_1="One:", value_1="0", title_2="Two:", value_2="0", title='RoboFab'):
raise NotImplementedError
class ProgressBar(object):
def __init__(self, title="RoboFab...", ticks=None, label=""):
self.w = vanilla.Window((250, 60), title)
if ticks is None:
isIndeterminate = True
ticks = 0
else:
isIndeterminate = False
self.w.progress = vanilla.ProgressBar((15, 15, -15, 12), maxValue=ticks, isIndeterminate=isIndeterminate, sizeStyle="small")
self.w.text = vanilla.TextBox((15, 32, -15, 14), label, sizeStyle="small")
self.w.progress.start()
self.w.center()
self.w.open()
def close(self):
self.w.progress.stop()
self.w.close()
def getCurrentTick(self):
return self.w.progress.get()
def label(self, label):
self.w.text.set(label)
self.w.text._nsObject.display()
def tick(self, tickValue=None):
if tickValue is None:
self.w.progress.increment()
else:
self.w.progress.set(tickValue)
if __name__ == "__main__":
pass

View file

@ -0,0 +1,10 @@
"""
Directory for interface related modules.
Stuff for MacOSX, widgets, quartz
"""

View file

@ -0,0 +1,80 @@
"""This module provides two functions, very similar to
EasyDialogs.AskFileForOpen() and EasyDialogs.AskFolder(): GetFile() and
GetFileOrFolder(). The main difference is that the functions here fully
support "packages" or "bundles", ie. folders that appear to be files in
the finder and open/save dialogs. The second difference is that
GetFileOrFolder() allows the user to select a file _or_ a folder.
"""
__all__ = ["GetFile", "GetFileOrFolder"]
from EasyDialogs import _process_Nav_args, _interact
import Nav
import Carbon.File
# Lots of copy/paste from EasyDialogs.py, for one because althought the
# EasyDialogs counterparts take a million options, they don't take the
# one option I need: the flag to support packages...
kNavSupportPackages = 0x00001000
def GetFile(message=None, title=None, directory=None, fileName=None, allowsMultipleSelection=False, fileTypes=None):
"""Ask the user to select a file.
Some of these arguments are not supported:
title, directory, fileName, allowsMultipleSelection and fileTypes are here for compatibility reasons.
"""
default_flags = 0x56 | kNavSupportPackages
args, tpwanted = _process_Nav_args(default_flags, message=message)
_interact()
try:
rr = Nav.NavChooseFile(args)
good = 1
except Nav.error, arg:
if arg[0] != -128: # userCancelledErr
raise Nav.error, arg
return None
if not rr.validRecord or not rr.selection:
return None
if issubclass(tpwanted, Carbon.File.FSRef):
return tpwanted(rr.selection_fsr[0])
if issubclass(tpwanted, Carbon.File.FSSpec):
return tpwanted(rr.selection[0])
if issubclass(tpwanted, str):
return tpwanted(rr.selection_fsr[0].as_pathname())
if issubclass(tpwanted, unicode):
return tpwanted(rr.selection_fsr[0].as_pathname(), 'utf8')
raise TypeError, "Unknown value for argument 'wanted': %s" % repr(tpwanted)
def GetFileOrFolder(message=None, title=None, directory=None, fileName=None, allowsMultipleSelection=False, fileTypes=None):
"""Ask the user to select a file or a folder.
Some of these arguments are not supported:
title, directory, fileName, allowsMultipleSelection and fileTypes are here for compatibility reasons.
"""
default_flags = 0x17 | kNavSupportPackages
args, tpwanted = _process_Nav_args(default_flags, message=message)
_interact()
try:
rr = Nav.NavChooseObject(args)
good = 1
except Nav.error, arg:
if arg[0] != -128: # userCancelledErr
raise Nav.error, arg
return None
if not rr.validRecord or not rr.selection:
return None
if issubclass(tpwanted, Carbon.File.FSRef):
return tpwanted(rr.selection_fsr[0])
if issubclass(tpwanted, Carbon.File.FSSpec):
return tpwanted(rr.selection[0])
if issubclass(tpwanted, str):
return tpwanted(rr.selection_fsr[0].as_pathname())
if issubclass(tpwanted, unicode):
return tpwanted(rr.selection_fsr[0].as_pathname(), 'utf8')
raise TypeError, "Unknown value for argument 'wanted': %s" % repr(tpwanted)

View file

@ -0,0 +1,10 @@
"""
Directory for interface related modules.
Stuff for Windows
"""