# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Library General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Library General Public License for more details.
#
# You should have received a copy of the GNU Library General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
from styletext import StyleText,Style
import Tkinter
from Tkconstants import *
from tkFileDialog import asksaveasfilename,asksaveasfilename,\
askopenfilename
from Sketch.Graphics import font
from Sketch import _
from cPickle import loads,dumps
import os
def raw2styling(raw):
styling = []
for l, line, char in raw:
if l == 0:
style = None
else:
style = apply(Style, [], {l[0] : l[1]})
styling.append((style, line, char))
return styling
def styling2raw(styling):
raw_styling = []
for style, line, char in styling:
if style is not None:
l = (style.sort, style.options)
else:
l = 0
raw_styling.append((l, line, char))
return raw_styling
st_signature = '## styletext '
def load_text(name):
file = open(name, 'r')
s = file.read()
file.close()
styling = []
len_sig = len(st_signature)
if s[:len_sig] == st_signature:
text, raw = loads(s[len_sig:])
styling = raw2styling(raw)
else:
# assume plain text otherwise
text = s
return text, styling
def save_text(name, text, styling=[]):
file = open(name, 'w')
if name[-3:] == '.st':
raw = styling2raw(styling)
s = st_signature + dumps((text, raw))
else:
s = text
file.write(s)
file.close()
class font_families:
def __init__(self):
self.family_to_fonts = font.make_family_to_fonts()
self.families = self.family_to_fonts.keys()
self.families.sort()
def xlfd(self, **kw):
fonts = self.family_to_fonts[kw['family']]
list = kw['attr'][:]
last = fonts[-1]
family, attrs, xlfd_start, encoding = font.fontmap[last]
list.append(attrs)
for name in fonts:
family, attrs, xlfd_start, encoding = font.fontmap[name]
if attrs in list:
return font.xlfd_template % (xlfd_start, kw['size'],
encoding)
def ps(self, **kw):
family = kw['family']
fonts = self.family_to_fonts[family]
list = kw['attr'][:]
last = fonts[-1]
family, attrs, xlfd_start, encoding = font.fontmap[last]
list.append(attrs)
for name in fonts:
family, attrs, xlfd_start, encoding = font.fontmap[name]
if attrs in list:
return name
return ''
font.read_font_dirs()
FONTS = font_families()
std_sizes = (8, 9, 10, 12, 14, 18, 24, 36, 48, 72)
class TextEditor(StyleText):
def __init__(self, parent=None, **kw):
self.top = parent
apply(StyleText.__init__, (self, parent), kw)
self.register_sort('family', self.FamilySort, 'Times' )
self.register_sort('bold', self.BoldSort, 0)
self.register_sort('italic', self.ItalicSort, 0)
self.register_sort('size', self.SizeSort, 12)
self.register_sort('color', self.ColorSort, 'black' )
self.register_sort('supersub', self.SupersubSort, 'normal' )
self.plain_options = {'size':14, 'color':'black'}
bar = Tkinter.Frame(parent)
self._make_menu()
self.bind('<ButtonRelease-1>', lambda e, s=self: s.Update())
self.bind('<KeyRelease>', lambda e, s=self: s.Update())
rightFrame = Tkinter.Frame(bar)
self.button_apply = Tkinter.Button(rightFrame, text='apply')
self.button_apply.pack()
rightFrame.pack(side='right')
bar.pack(side = 'top', fill = 'x')
def _make_menu(self):
# make menu button
menu = Tkinter.Menu(self)
menu.file = Tkinter.Menu(menu)
menu.file.add_command(label='Load', command=self.load)
menu.file.add_command(label='Save', command=self.saveas)
menu.file.add_command(label='Insert', command=self.insert_file)
menu.options = Tkinter.Menu(menu)
self._plainmode_state = Tkinter.IntVar()
menu.options.add_checkbutton(label='Plain mode', \
variable = self._plainmode_state,
command = lambda s=self: s.fontify('1.0', 'end'))
menu.family = Tkinter.Menu(menu)
for f in FONTS.families:
menu.family.add_command(label=f,
command=lambda s=self, f=f: s.change_family(f))
menu.size = Tkinter.Menu(menu)
for f in std_sizes:
menu.size.add_command(label=f,
command=lambda s=self, f=f: s.change_size(f))
menu.color = Tkinter.Menu(menu)
for f in ('black', 'darkgray', 'gray', 'lightgray', 'blue', 'cyan',
'green', 'magenta', 'red', 'yellow', 'white'):
menu.color.add_command(label=f, \
command=lambda s=self, f=f: s.change_color(f),
background = f)
# definition of the menu one level up...
menu.add_cascade(
label='File',
menu=menu.file)
menu.add_cascade(
label='Options',
menu=menu.options)
menu.add_separator()
menu.add_cascade(
label='Font Family',
menu=menu.family)
menu.add_cascade(
label='Size',
menu=menu.size)
menu.add_cascade(
label='Color',
menu=menu.color)
self._bold_state = Tkinter.IntVar()
self._italic_state = Tkinter.IntVar()
menu.add_checkbutton(label=_('Bold'), \
variable=self._bold_state,
command=lambda s=self, i=self._bold_state: \
s.change_bold(i.get())
)
menu.add_checkbutton(label=_("Italic"),
variable=self._italic_state,
command=lambda s=self, i=self._italic_state: \
s.change_italic(i.get())
)
self._subscript_state = Tkinter.IntVar()
self._superscript_state = Tkinter.IntVar()
menu.add_checkbutton(label=_("Subscript"), \
variable=self._subscript_state,
command=lambda s=self, i=self._subscript_state: \
s.change_subscript(i.get())
)
menu.add_checkbutton(label=_("Superscript"), \
variable=self._superscript_state,
command=lambda s=self, i=self._superscript_state: \
s.change_superscript(i.get())
)
self.menu = menu
self.bind('<Button-3>',
lambda e, s=self: s.menu.tk_popup(e.x_root, e.y_root))
def warn(self, title, message):
# This will be overridden
pass
def _update_menu(self):
styles = self.style_get('insert')
dict = {}
for style in styles:
dict[style.sort] = style.options
self.menu.entryconfigure(4, label=dict['family'])
self.menu.entryconfigure(5, label=dict['size'])
self.menu.entryconfigure(6, foreground=dict['color'])
supersub = dict['supersub']
self._superscript_state.set(supersub=='superscript')
self._subscript_state.set(supersub=='subscript')
self._bold_state.set(dict['bold'])
self._italic_state.set(dict['italic'])
def Update(self):
self._update_menu()
def ColorSort(self, tagoptions, alloptions):
if not self._plainmode_state.get():
tagoptions['foreground'] = alloptions['color']
else:
tagoptions['foreground'] = self.plain_options['color']
def SupersubSort(self, tagoptions, alloptions):
if self._plainmode_state.get():
size = self.plain_options['size']
else:
size = alloptions['size']
option = alloptions['supersub']
if option == 'subscript':
alloptions['size'] = size * 0.5
tagoptions['offset'] = -size * 0.2
elif option == 'superscript':
alloptions['size'] = size * 0.5
tagoptions['offset'] = size * 0.6
def FamilySort(self, tagoptions, alloptions):
pass
def ItalicSort(self, tagoptions, alloptions):
pass
def BoldSort(self, tagoptions, alloptions):
pass
def SizeSort(self, tagoptions, alloptions):
dict = {}
if not self._plainmode_state.get():
dict['size'] = int(round(alloptions['size']))
else:
dict['size'] = self.plain_options['size']
dict['family'] = alloptions['family']
bold = alloptions['bold']
italic = alloptions['italic']
if bold and italic:
dict['attr'] = ['Bold Italic', 'Bold Oblique', 'Demi Oblique', 'Demi Italic', 'Medium Italic', 'Demi Bold Italic']
elif bold:
dict['attr'] = ['Bold', 'Demi', 'Medium', 'Demi Bold']
elif italic:
dict['attr'] = ['Italic', 'Oblique', 'Book Oblique', 'Light Italic', 'Regular Oblique', 'Regular Italic']
else:
dict['attr'] = ['Roman', 'Book', 'Light', 'Regular']
xfont = apply(FONTS.xlfd, (), dict)
tagoptions['font'] = xfont
def change_set(self, style):
range = self.tag_ranges('sel')
if len(range) == 2:
apply(self.style_add,(style,)+self.tag_ranges('sel'))
else:
self.style_force.append(style)
self.Update()
def change_bold(self, state):
style = Style(bold=state)
self.change_set(style)
def change_subscript(self, state):
if state:
self._superscript_state.set(0)
style = Style(supersub='subscript')
else:
style = Style(supersub='normal')
self.change_set(style)
def change_superscript(self, state):
if state:
self._subscript_state.set(0)
style = Style(supersub='superscript')
else:
style = Style(supersub='normal')
self.change_set(style)
def change_italic(self, state):
style = Style(italic=state)
self.change_set(style)
def change_family(self, family):
style = Style(family=family)
self.change_set(style)
def change_size(self, size):
style = Style(size=size)
self.change_set(style)
def change_color(self, color):
style = Style(color=color)
self.change_set(style)
def load(self, event=None):
name = askopenfilename( \
filetypes=[(_("styletext files"), "*.st"), \
(_("all files"), "*")])
if name:
try:
text, styling = load_text(name)
except Exception, value:
self.warn(
title = _("Load File"),
message = _("Cannot load %(filename)s:\n"
"%(message)s") \
% {'filename':`os.path.split(name)[1]`,
'message':value})
return
index = '1.0'
self.style_removeall()
self.delete('1.0', 'end')
self.insert(index, text)
self.styling_apply(index, styling)
def saveas(self, event=None):
name = asksaveasfilename( \
filetypes=[(_("styletext files"), "*.st"), \
(_("all files"), "*")])
if name:
text = self.get('1.0', 'end')
styling = self.styling_get('1.0', 'end')
try:
save_text(name, text, styling)
except IOError, value:
self.warn(
title = _("Save File"),
message = _("Cannot Save %(filename)s:\n"
"%(message)s") \
% {'filename':`os.path.split(name)[1]`,
'message':value})
def insert_file(self, event=None):
name = askopenfilename( \
filetypes=[(_("styletext files"), "*.st"), \
(_("all files"), "*")])
if name:
try:
text, styling = load_text(name)
except Exception, value:
self.warn(
title = _("Insert File"),
message = _("Cannot insert %(filename)s:\n"
"%(message)s") \
% {'filename':`os.path.split(name)[1]`,
'message':value})
return
index = self.index('insert')
self.insert(index, text)
self.styling_apply(index, styling)
def test1():
tk = Tkinter.Tk()
text = TextEditor(tk, background='white')
text.pack(fill=BOTH, expand=1)
text.insert(END,'1\n2\n3\n4\n5\n')
text.fontify('1.0','end')
text.style_add(Style(size=24), '2.0','3.0')
text.style_add(Style(size=36), '4.0','5.0')
text.fontify('1.0','end')
text.bind('<Control-l>', text.load)
text.bind('<Control-s>', text.saveas)
text.bind('<Control-i>', text.insert_file)
raw_input()
def waste():
global text
print "profiling"
for i in range(1000):
text.insert('250.10', "x")
def test2():
#
# profiling
tk = Tkinter.Tk()
global text
text = TextEditor(tk, background='white')
text.pack(fill=BOTH, expand=1)
n = 500
print "n =", n
for i in range(n):
# print i
text.insert(END, '1234567890abcdefghij\n')
text.style_add(Style(sizesort, size=24), 'end -5 chars',
'end -3 chars')
text.style_add(Style(familysort, family="Helvetica"), 'end -5 chars',
'end -3 chars')
text.style_add(Style(attrsort, attr="Italic"), 'end -5 chars',
'end -3 chars')
from profile import run
run("waste()")
def test3():
tk = Tkinter.Tk()
text = TextEditor(tk, background='white')
text.pack(fill=BOTH, expand=1)
text.insert(END,'1234567890\n')
text.insert(END,'1234567890\n')
text.insert(END,'1234567890\n')
text.insert(END,'1234567890\n')
text.insert(END,'1234567890\n')
text.insert(END,'1234567890\n')
text.style_add(Style(size = 24), '1.0','4.0')
text.style_add(Style(size = 24), '2.0','3.0')
text.pool.dump()
def test4():
tk = Tkinter.Tk()
text = TextEditor(tk, background='white')
text.pack(fill=BOTH, expand=1)
text.insert(END,'1234567890\n')
text.insert(END,'1234567890\n')
text.insert(END,'1234567890\n')
text.insert(END,'1234567890\n')
text.insert(END,'1234567890\n')
text.insert(END,'1234567890\n')
text.style_add(Style(size = 24), '2.0','3.0')
text.style_add(Style(size = 24), '1.0','4.0')
text.pool.dump()
def test5():
tk = Tkinter.Tk()
text = TextEditor(tk, background='white')
text.pack(fill=BOTH, expand=1)
text.insert(END,'1234567890\n')
text.insert(END,'1234567890\n')
text.insert(END,'1234567890\n')
text.insert(END,'1234567890\n')
text.insert(END,'1234567890\n')
text.insert(END,'1234567890\n')
text.style_add(Style(size = 24), '1.0','3.0')
text.style_add(Style(size = 24), '2.0','4.0')
text.pool.dump()
if __name__=='__main__':
import sys
sys.path.append('/usr/lib/sketch-0.6.12/')
#
test1()
#
#~ for test in (test3, test4, test5):
#~ print "\n", test.__name__
#~ apply(test)
|