diff options
Diffstat (limited to 'misc/pylib/robofab/interface')
-rwxr-xr-x | misc/pylib/robofab/interface/__init__.py | 14 | ||||
-rwxr-xr-x | misc/pylib/robofab/interface/all/__init__.py | 14 | ||||
-rwxr-xr-x | misc/pylib/robofab/interface/all/dialogs.py | 278 | ||||
-rw-r--r-- | misc/pylib/robofab/interface/all/dialogs_default.py | 76 | ||||
-rw-r--r-- | misc/pylib/robofab/interface/all/dialogs_fontlab_legacy1.py | 73 | ||||
-rw-r--r-- | misc/pylib/robofab/interface/all/dialogs_fontlab_legacy2.py | 373 | ||||
-rwxr-xr-x | misc/pylib/robofab/interface/all/dialogs_legacy.py | 737 | ||||
-rw-r--r-- | misc/pylib/robofab/interface/all/dialogs_mac_vanilla.py | 267 | ||||
-rwxr-xr-x | misc/pylib/robofab/interface/mac/__init__.py | 10 | ||||
-rwxr-xr-x | misc/pylib/robofab/interface/mac/getFileOrFolder.py | 80 | ||||
-rwxr-xr-x | misc/pylib/robofab/interface/win/__init__.py | 10 |
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 + +""" + + + + |