2011-05-07 12:52:50 +00:00
2008-01-07 17:40:34 +00:00
"""
2011-05-07 12:52:50 +00:00
2008-01-07 17:40:34 +00:00
Dialogs . Not just for FontLab any more .
2011-05-07 12:52:50 +00:00
Cross - platform and cross - application compatible . Some of them anyway .
2008-01-07 17:40:34 +00:00
( 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 .
2011-05-07 12:52:50 +00:00
"""
2008-01-07 17:40:34 +00:00
import os
import sys
2011-05-07 12:52:50 +00:00
from robofab import RoboFabError
2011-05-07 18:39:13 +00:00
from warnings import warn
2008-01-07 17:40:34 +00:00
MAC = False
PC = False
haveMacfs = False
if sys . platform in ( ' mac ' , ' darwin ' ) :
MAC = True
elif os . name == ' nt ' :
PC = True
else :
2011-05-07 18:39:13 +00:00
warn ( " dialogs.py only supports Mac and PC platforms. " )
2008-01-07 17:40:34 +00:00
pyVersion = sys . version_info [ : 3 ]
inFontLab = False
try :
from FL import *
inFontLab = True
except ImportError : pass
2011-05-07 12:52:50 +00:00
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
2008-01-07 17:40:34 +00:00
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 '
2011-05-07 12:52:50 +00:00
else :
p = sys . platform
raise RoboFabError ( " %s is not currently available on the %s platform " % ( dialog , p ) )
2008-01-07 17:40:34 +00:00
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 ( )
2011-05-07 12:52:50 +00:00
class _MacOneListW :
2008-01-07 17:40:34 +00:00
""" 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 ( )
2011-05-07 12:52:50 +00:00
class _MacTwoChecksW :
""" Version using W """
2008-01-07 17:40:34 +00:00
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 )
2011-05-07 12:52:50 +00:00
elif MAC and hasEasyDialogs :
2008-01-07 17:40:34 +00:00
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 :
2011-05-07 12:52:50 +00:00
if hasW :
d = _MacOneListW ( list , message )
sel = d . selected
if sel is None :
return None
else :
return list [ sel ]
2008-01-07 17:40:34 +00:00
else :
2011-05-07 12:52:50 +00:00
_raisePlatformError ( ' OneList ' )
2008-01-07 17:40:34 +00:00
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 :
2011-05-07 12:52:50 +00:00
if hasW :
tc = _MacTwoChecksW ( title_1 , title_2 , value1 , value2 , title )
else :
_raisePlatformError ( ' TwoChecks ' )
else :
2008-01-07 17:40:34 +00:00
_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 )
2011-05-07 12:52:50 +00:00
else :
2008-01-07 17:40:34 +00:00
_raisePlatformError ( ' Message ' )
def AskString ( prompt , value = ' ' , title = ' RoboFab ' ) :
"""
Returns entered string .
Availability : FontLab , Macintosh
"""
if inFontLab :
2009-09-03 04:09:29 +00:00
askString = _FontLabDialogAskString ( prompt , value , title )
askString . Run ( )
v = askString . value
2008-01-07 17:40:34 +00:00
if v is None :
return None
else :
return v
elif MAC :
import EasyDialogs
2009-09-03 04:09:29 +00:00
askString = EasyDialogs . AskString ( prompt )
if askString is None :
2008-01-07 17:40:34 +00:00
return None
2009-09-03 04:09:29 +00:00
if len ( askString ) == 0 :
2008-01-07 17:40:34 +00:00
return None
else :
2009-09-03 04:09:29 +00:00
return askString
2011-05-07 12:52:50 +00:00
else :
2008-01-07 17:40:34 +00:00
_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
2011-05-07 12:52:50 +00:00
else :
2008-01-07 17:40:34 +00:00
_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
2011-05-07 12:52:50 +00:00
2008-01-07 17:40:34 +00:00
if __name__ == ' __main__ ' :
2011-05-07 12:52:50 +00:00
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 )
#