fonttools/Lib/robofab/interface/all/dialogs_legacy.py

721 lines
17 KiB
Python
Executable File

"""
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')
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)
#