AW: [PythonCE] Minature IDLE for PythonCE
Anne Wangnick
anne.wangnick at t-online.de
Wed Jan 5 19:12:23 CET 2005
Hi Ed,
Nice work of yours!
Herewith some improvements (real menus on top, support for "foreign" Windows
CE versions like my German one, where the installation is in
C:\\Programme\\Python\\lib, support for VGA screen with HI_RES_AWARE python,
hide ugly additional Tkinter titlebar below PDA top taskbar).
Please give it a try on a real 240x320 PDA -- I can test it only in the
240x320 emulation mode of my VGA PDA.
Regards,
Sebastian Wangnick
-----Ursprungliche Nachricht-----
Von: pythonce-bounces at python.org [mailto:pythonce-bounces at python.org]Im
Auftrag von Ed Blake
Gesendet: Donnerstag, 30. Dezember 2004 23:09
An: pythonce at python.org
Betreff: [PythonCE] Minature IDLE for PythonCE
Something fun, and maybe usefull. Since popup-menus work I will probably
move most of the edit menu there.
-------------- next part --------------
#IdleCE
import sys
for p in sys.path:
if p[-12:].lower()=="python23.zip":
sys.path.append(p+"\\lib-tk")
break
import os
import re
from Tkinter import *
import tkMessageBox
import tkFileDialog
import keyword
from string import ascii_letters, digits, punctuation
OS = os.name.lower() #Should be 'ce' on WinCE
class idle:
"""The base class for the mini idle."""
def __init__(self,root):
self.root = root
root.grid_rowconfigure(1, weight=1)
root.grid_columnconfigure(0, weight=1)
frame = Frame(root)
frame.grid(row=0,column=0,columnspan=2,sticky=NSEW)
self.editor = SyntaxHighlightingText(root)
self.editor.grid(row=1,column=0,columnspan=2,sticky=N+S)
panbar = Scrollbar(root,orient=HORIZONTAL)
panbar.grid(row=2,column=0,columnspan=2,sticky=E+W)
scrollbar = Scrollbar(root)
scrollbar.grid(row=1,column=2,sticky=N+S)
self.editor.configure(xscrollcommand=panbar.set)
self.editor.configure(yscrollcommand=scrollbar.set)
scrollbar.config(command=self.editor.yview)
panbar.config(command=self.editor.xview)
btn = Menubutton(frame,text="File",padx=1,pady=1)
btn.pack(side=LEFT)
submenu = Menu(btn,tearoff=False)
btn["menu"] = submenu
submenu.add_command(label="New",command=self.new)
submenu.add_command(label="Open",command=self.open)
submenu.add_command(label="Save",command=self.save)
submenu.add_command(label="Save as",command=self.saveas)
submenu.add_command(label="Exit",command=self.exit)
btn = Menubutton(frame,text="Edit",padx=1,pady=1)
btn.pack(side=LEFT)
submenu = Menu(btn,tearoff=False)
btn["menu"] = submenu
submenu.add_command(label="Undo",command=self.editor.edit_undo)
submenu.add_command(label="Redo",command=self.editor.edit_redo)
submenu.add_command(label="Cut",command=self.editor.cut)
submenu.add_command(label="Copy",command=self.editor.copy)
submenu.add_command(label="Paste",command=self.editor.paste)
btn = Menubutton(frame,text="Help",padx=1,pady=1)
btn.pack(side=LEFT)
submenu = Menu(btn,tearoff=False)
btn["menu"] = submenu
submenu.add_command(label="About",command=self.about_dialog)
self.root.protocol("WM_DELETE_WINDOW", self.exit)
def about_dialog(self):
"""Sillyness"""
top = Toplevel()
top.title("about")
top.resizable(0,0)
top.focus_set()
about = """
IdleCE v0.6.1
A miniaturized imitation of
the python ide: idle.
This software is distibuted
under the Gnu-GPL. Please Visit
http://www.gnu.org/licenses/gpl.txt
to see the license.
"""
info = Label(top,text=about)
info.pack(side=TOP,padx=6)
button = Button(top, text="Dismiss", command=top.destroy)
button.pack(side=BOTTOM,fill=X)
def open(self):
# Opens a file and colorizes it
self.filename = tkFileDialog.askopenfilename()
if OS == 'ce': # Just passing filename fails...
self.filename = self.filename.replace('/','\\')
try:
file = open(self.filename)
self.editor.delete("1.0",END)
text = file.readlines()
file.close()
for i in range(len(text)-1):
self.editor.insert(END,text[i])
self.editor.colorize(i+1,len(text[i])) #colorize(textline,lastcolumn)
self.editor.see("1.0")
except IOError:
print self.filename
def saveas(self):
# Called if no filename is set or Saveas is picked
self.filename = tkFileDialog.asksaveasfilename()
if OS == 'ce':
self.filename = self.filename.replace('/','\\')
try:
file = open(self.filename,'w')
text = self.editor.get("1.0",END)
file.write(text)
file.flush()
file.close()
except Exception, info:
tkMessageBox.showerror('Exception!',info)
def save(self):
try:
file = open(self.filename,'w')
text = self.editor.get("1.0",END)
file.write(text)
file.flush()
file.close()
except:
self.saveas() # If no file has been accessed
def new(self):
if len(self.editor.get("1.0",END)) >= 2:
if tkMessageBox.askokcancel("New File","Discard current file?"):
self.editor.delete("1.0",END)
self.filename = ""
else:
self.editor.delete("1.0",END)
self.filename = ""
def exit(self):
# End the program firmly.
root.destroy()
root.quit()
class SyntaxHighlightingText(Text):
"""A syntax highlighting text widget from the web customized with
some methods from Idle and some special methods."""
tags = {'com':'#C00', #comment
'str':'#0A0', #string
'kw': 'orange', #keyword
'obj':'#00F', #function/class name
'int': 'blue' #integers
}
def __init__(self, root):
if OS == 'ce':
w = 40
h = 10
else:
w = 80
h = 25
Text.__init__(self,root,wrap=NONE,bd=0,width=w,height=h,undo=1,maxundo=50,padx=0,pady=0)
# Non-wrapping, no border, undo turned on, max undo 50
self.text = self # For the methods taken from IDLE
self.root = root
self.config_tags()
self.characters = ascii_letters + digits + punctuation
self.tabwidth = 8 # for IDLE use, must remain 8 until Tk is fixed
self.indentwidth = 4 # Should perhaps be 2 due to the small screen??
self.indention = 0 # The current indention level
self.set_tabwidth(self.indentwidth) # IDLE...
# create a popup menu
self.menu = Menu(root, tearoff=0)
self.menu.add_command(label="Undo", command=self.edit_undo)
self.menu.add_command(label="Redo", command=self.edit_redo)
#self.menu.add_command(type="separator")
self.menu.add_command(label="Cut", command=self.cut)
self.menu.add_command(label="Copy", command=self.copy)
self.menu.add_command(label="Paste", command=self.paste)
self.bind('<Key>', self.key_press) # For scanning input
self.bind('<Return>',self.autoindent) # Overides default binding
self.bind('<Tab>',self.autoindent) # increments self.indention
self.bind('<BackSpace>',self.autoindent)# decrements self.indention
self.bind('<Double-Button-1>',self.paste)# decrements self.indention
self.tag_bind(SEL,'<Button-1>',self.popup)
def popup(self, event):
"""Edit popup menu with a special attribute for cut and copy."""
Selection=self.get_selection_indices()
if len(Selection)>0:
SelectedText = self.get(Selection[0],Selection[1])
self.sel_store = list(Selection)
self.sel_store.extend([SelectedText])
self.menu.post(event.x_root, event.y_root)
def get_tabwidth(self):
# From IDLE
current = self['tabs'] or 5000
return int(current)
def set_tabwidth(self, newtabwidth):
# From IDLE
text = self
if self.get_tabwidth() != newtabwidth:
pixels = text.tk.call("font", "measure", text["font"],
"-displayof", text.master,
"n" * newtabwidth)
text.configure(tabs=pixels)
def config_tags(self):
# Sets up the tags and their colors
for tag, val in self.tags.items():
self.tag_config(tag, foreground=val)
def remove_tags(self, start, end):
for tag in self.tags.keys():
self.tag_remove(tag, start, end)
def get_selection_indices(self):
# If a selection is defined in the text widget, return (start,
# end) as Tkinter text indices, otherwise return (None, None)
try:
first = self.text.index("sel.first")
last = self.text.index("sel.last")
return first, last
except TclError:
return None, None
def cut(self,event=0):
self.clipboard_clear()
if self.sel_store: # Sent by the popup
self.delete(self.sel_store[0],self.sel_store[1])
self.clipboard_append(self.sel_store[2])
self.sel_store = []
else: # Sent by menu
Selection=self.get_selection_indices()
if len(Selection)>0:
SelectedText = self.get(Selection[0],Selection[1])
self.delete(Selection[0],Selection[1])
self.clipboard_append(SelectedText)
def copy(self,event=0):
self.clipboard_clear()
if self.sel_store: # Sent by the popup
self.clipboard_append(self.sel_store[2])
self.sel_store = []
else: # Sent by menu
Selection=self.get_selection_indices()
if len(Selection)>0:
SelectedText = self.get(Selection[0],Selection[1])
self.clipboard_append(SelectedText)
def paste(self,event=0):
# This should call colorize for the pasted lines.
SelectedText = self.root.selection_get(selection='CLIPBOARD')
self.insert(INSERT, SelectedText)
return "break"
def autoindent(self,event):
if event.keysym == 'Return':
self.edit_separator() # For undo/redo
index = self.index(INSERT).split('.')
print index
line = int(index[0])
column = int(index[1])
if self.get('%s.%d'%(line, column-1)) == ':':
self.indention += 1
print '\n',
print '\t'*self.indention
self.insert(INSERT,'\n')
self.insert(INSERT,'\t'*self.indention)
return 'break' # Overides standard bindings
elif event.keysym == 'Tab':
self.edit_separator()
self.indention += 1
print self.indention
elif event.keysym == 'BackSpace':
self.edit_separator()
index = self.index(INSERT).split('.')
print index
line = int(index[0])
column = int(index[1])
if self.get('%s.%d'%(line, column-1)) == '\t':
self.indention -= 1
def key_press(self, key):
"""This function was origonaly the home of the colorize code.
Now it is mostly useless unless you want to watch for a certain character."""
if key.char in ' :[(]),"\'':
self.edit_separator() # For undo/redo
cline = self.index(INSERT).split('.')[0]
lastcol = 0
char = self.get('%s.%d'%(cline, lastcol))
while char != '\n':
lastcol += 1
char = self.get('%s.%d'%(cline, lastcol))
self.colorize(cline,lastcol)
def colorize(self,cline,lastcol):
"""Not so simple syntax highlighting."""
buffer = self.get('%s.%d'%(cline,0),'%s.%d'%(cline,lastcol))
tokenized = buffer.split(' ')
self.remove_tags('%s.%d'%(cline, 0), '%s.%d'%(cline, lastcol))
quotes = 0
start = 0
for i in range(len(buffer)):
if buffer[i] in ['"',"'"]: # Doesn't distinguish between single and double quotes...
if quotes:
self.tag_add('str', '%s.%d'%(cline, start), '%s.%d'%(cline, i+1))
quotes = 0
else:
start = i
quotes = 1
elif buffer[i] == '#':
self.tag_add('com', '%s.%d'%(cline, i), '%s.%d'%(cline, len(buffer)))
break
start, end = 0, 0
obj_flag = 0
for token in tokenized:
end = start + len(token)
if obj_flag:
self.tag_add('obj', '%s.%d'%(cline, start), '%s.%d'%(cline, end))
obj_flag = 0
if token.strip() in keyword.kwlist:
self.tag_add('kw', '%s.%d'%(cline, start), '%s.%d'%(cline, end))
if token.strip() in ['def','class']:
obj_flag = 1
else:
for index in range(len(token)):
try:
int(token[index])
except ValueError:
pass
else:
self.tag_add('int', '%s.%d'%(cline, start+index))
start += len(token)+1
if __name__ == '__main__':
root = Tk()
root.title('IdleCE')
if OS=='ce':
sizex, sizey = root.wm_maxsize()
root.wm_geometry("%dx%d+0+%d"%(sizex-6,sizey*37/64+1,sizey/90))
app = idle(root)
root.mainloop()
More information about the PythonCE
mailing list