Just van Rossum feb0046176 Moved Data, Lib and install.py one level down the tree
git-svn-id: http://svn.robofab.com/trunk@67 b5fa9d6c-a76f-4ffd-b3cb-f825fc41095c
2008-03-11 09:18:32 +00:00

669 lines
16 KiB
Python
Executable File

"""
Dialogs. Not just for FontLab any more.
Cross-platform and cross-application compatible. Mostly 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.
"""
#to add:
#W version of TwoFields
import os
import sys
#from robofab import RoboFabError
RoboFabError = "RoboFabError"
MAC = False
PC = False
haveMacfs = False
if sys.platform in ('mac', 'darwin'):
MAC = True
elif os.name == 'nt':
PC = True
else:
raise RoboFabError, "dialogs.py only supports Mac and PC platforms."
pyVersion = sys.version_info[:3]
inFontLab = False
try:
from FL import *
inFontLab = True
except ImportError: pass
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'
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, prompt, 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, prompt)
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 prompt 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 _MacOneList:
"""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 _MacTwoChecks:
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:
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:
d = _MacOneList(list, message)
sel = d.selected
if sel is None:
return None
else:
return list[sel]
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:
tc = _MacTwoChecks(title_1, title_2, value1, value2, title)
elif PC:
_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)
elif PC:
_raisePlatformError('Message')
def AskString(prompt, value='', title='RoboFab'):
"""
Returns entered string.
Availability: FontLab, Macintosh
"""
if inFontLab:
as = _FontLabDialogAskString(prompt, value, title)
as.Run()
v = as.value
if v is None:
return None
else:
return v
elif MAC:
import EasyDialogs
as = EasyDialogs.AskString(prompt)
if as is None:
return None
if len(as) == 0:
return None
else:
return as
elif PC:
_raisePlatformError('GetString')
def AskYesNoCancel(prompt, 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(prompt, title)
gync.Run()
v = gync.value
return v
elif MAC:
import EasyDialogs
gync = EasyDialogs.AskYesNoCancel(prompt, default=default)
return gync
elif PC:
_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, defaultName=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, defaultName)
if ok:
path = fss.as_pathname()
else:
import EasyDialogs
path = EasyDialogs.AskFileForSave(message, savedFileName=defaultName)
elif PC:
if inFontLab:
if not message:
message = ''
if not defaultName:
defaultName = ''
path = fl.GetFileName(0, message, defaultName, '')
else:
openFlags = win32con.OFN_OVERWRITEPROMPT|win32con.OFN_EXPLORER
mode_save = 0
myDialog = win32ui.CreateFileDialog(mode_save, None, defaultName, openFlags)
myDialog.SetOFNTitle(message)
is_OK = myDialog.DoModal()
if is_OK == 1:
path = myDialog.GetPathName()
else:
_raisePlatformError('GetFile')
return path
if __name__=='__main__':
#print TwoFields()
print TwoChecks('hello', 'world', 1, 0, 'ugh')
print OneList(['a', 'b', 'c'], 'hello world')
Message('hello world')
print AskString('hello world')
print AskYesNoCancel('hello world')
b = ProgressBar('hello', 50, 'world')
for i in range(50):
if i == 25:
b.label('ugh.')
b.tick(i)
b.close()