summaryrefslogtreecommitdiff
path: root/misc/pylib/robofab/interface
diff options
context:
space:
mode:
Diffstat (limited to 'misc/pylib/robofab/interface')
-rwxr-xr-xmisc/pylib/robofab/interface/__init__.py14
-rwxr-xr-xmisc/pylib/robofab/interface/all/__init__.py14
-rwxr-xr-xmisc/pylib/robofab/interface/all/dialogs.py278
-rw-r--r--misc/pylib/robofab/interface/all/dialogs_default.py76
-rw-r--r--misc/pylib/robofab/interface/all/dialogs_fontlab_legacy1.py73
-rw-r--r--misc/pylib/robofab/interface/all/dialogs_fontlab_legacy2.py373
-rwxr-xr-xmisc/pylib/robofab/interface/all/dialogs_legacy.py737
-rw-r--r--misc/pylib/robofab/interface/all/dialogs_mac_vanilla.py267
-rwxr-xr-xmisc/pylib/robofab/interface/mac/__init__.py10
-rwxr-xr-xmisc/pylib/robofab/interface/mac/getFileOrFolder.py80
-rwxr-xr-xmisc/pylib/robofab/interface/win/__init__.py10
11 files changed, 1932 insertions, 0 deletions
diff --git a/misc/pylib/robofab/interface/__init__.py b/misc/pylib/robofab/interface/__init__.py
new file mode 100755
index 000000000..154c42b70
--- /dev/null
+++ b/misc/pylib/robofab/interface/__init__.py
@@ -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
+
+"""
+
+
+
+
diff --git a/misc/pylib/robofab/interface/all/__init__.py b/misc/pylib/robofab/interface/all/__init__.py
new file mode 100755
index 000000000..154c42b70
--- /dev/null
+++ b/misc/pylib/robofab/interface/all/__init__.py
@@ -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
+
+"""
+
+
+
+
diff --git a/misc/pylib/robofab/interface/all/dialogs.py b/misc/pylib/robofab/interface/all/dialogs.py
new file mode 100755
index 000000000..8fdfe847b
--- /dev/null
+++ b/misc/pylib/robofab/interface/all/dialogs.py
@@ -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()
+
diff --git a/misc/pylib/robofab/interface/all/dialogs_default.py b/misc/pylib/robofab/interface/all/dialogs_default.py
new file mode 100644
index 000000000..c513aa9b7
--- /dev/null
+++ b/misc/pylib/robofab/interface/all/dialogs_default.py
@@ -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
+
diff --git a/misc/pylib/robofab/interface/all/dialogs_fontlab_legacy1.py b/misc/pylib/robofab/interface/all/dialogs_fontlab_legacy1.py
new file mode 100644
index 000000000..73c3d7a15
--- /dev/null
+++ b/misc/pylib/robofab/interface/all/dialogs_fontlab_legacy1.py
@@ -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()
+
diff --git a/misc/pylib/robofab/interface/all/dialogs_fontlab_legacy2.py b/misc/pylib/robofab/interface/all/dialogs_fontlab_legacy2.py
new file mode 100644
index 000000000..460b73f1e
--- /dev/null
+++ b/misc/pylib/robofab/interface/all/dialogs_fontlab_legacy2.py
@@ -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
+
diff --git a/misc/pylib/robofab/interface/all/dialogs_legacy.py b/misc/pylib/robofab/interface/all/dialogs_legacy.py
new file mode 100755
index 000000000..8223a7d64
--- /dev/null
+++ b/misc/pylib/robofab/interface/all/dialogs_legacy.py
@@ -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)
diff --git a/misc/pylib/robofab/interface/all/dialogs_mac_vanilla.py b/misc/pylib/robofab/interface/all/dialogs_mac_vanilla.py
new file mode 100644
index 000000000..d4b76f9c7
--- /dev/null
+++ b/misc/pylib/robofab/interface/all/dialogs_mac_vanilla.py
@@ -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 \ No newline at end of file
diff --git a/misc/pylib/robofab/interface/mac/__init__.py b/misc/pylib/robofab/interface/mac/__init__.py
new file mode 100755
index 000000000..15f7d59c5
--- /dev/null
+++ b/misc/pylib/robofab/interface/mac/__init__.py
@@ -0,0 +1,10 @@
+"""
+
+Directory for interface related modules.
+Stuff for MacOSX, widgets, quartz
+
+"""
+
+
+
+
diff --git a/misc/pylib/robofab/interface/mac/getFileOrFolder.py b/misc/pylib/robofab/interface/mac/getFileOrFolder.py
new file mode 100755
index 000000000..da7edff61
--- /dev/null
+++ b/misc/pylib/robofab/interface/mac/getFileOrFolder.py
@@ -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)
diff --git a/misc/pylib/robofab/interface/win/__init__.py b/misc/pylib/robofab/interface/win/__init__.py
new file mode 100755
index 000000000..fe360c4ea
--- /dev/null
+++ b/misc/pylib/robofab/interface/win/__init__.py
@@ -0,0 +1,10 @@
+"""
+
+Directory for interface related modules.
+Stuff for Windows
+
+"""
+
+
+
+