##############################################################################
# ThanCad 0.0.9 "DoesSomething": 2dimensional CAD with raster support for engineers.
#
# Copyright (c) 2001-2009 Thanasis Stamos, August 23, 2009
# URL: http://thancad.sourceforge.net
# e-mail: cyberthanasis@excite.com
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program 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 General Public License for more details (www.gnu.org/licenses/gpl.html).
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
##############################################################################
"""\
ThanCad 0.0.9 "DoesSomething": 2dimensional CAD with raster support for engineers.
It implements ThanCad command line window.
"""
import Tkinter, tkFont
import p_gtkwid, p_gtkuti
import thanvers, thancom
from thantkguilowget.thantkconst import *
from thanopt import thancadconf
from thanvar import Canc,thanLogTk,Win32
from thantrans import T
DEFMES = T["Command: "]
DEFCAN = T["Cancelled."]
# self.__crel: These are the coordinates of the previous points defined by the user.
# IT is used to aid the relative coordinates system. But what happens
# if the previous point were defined by the GUI, and not the command line?????
#class ThanTkCmd(p_gtkwid.ThanScrolledText1):
class ThanTkCmd(p_gtkwid.ThanScrolledText):
"A standard text which command line capabilities."
thanFonts = None
def __init__(self, proj, **kw):
p_gtkwid.ThanScrolledText.__init__(self, master=proj[2], **kw)
self.__enlarged = None
self.bindte("<Key>", self.thanOnChar)
self.bindte("<F3>", self.__onF3) # Toggle object snap
self.bindte("<F2>", self.__onF2) # So the text of the command window elnarged
self.bindte("<F7>", self.__onF7)
self.bindte("<F8>", self.__onF8) # Toggle ortho mode
self.bindte("<Control-Up>", proj[2].thanCanvas.thanPanpageup)
self.bindte("<Control-Down>", proj[2].thanCanvas.thanPanpagedown)
self.bindte("<Control-Left>", proj[2].thanCanvas.thanPanpageleft)
self.bindte("<Control-Right>",proj[2].thanCanvas.thanPanpageright)
self.bindte("<KP_Add>", self.__onGrayplus)
self.bindte("<KP_Subtract>", self.__onGrayminus)
self.__proj = proj # A reference to ThanCad project
if self.thanFonts == None:
font1 = tkFont.Font(family="Liberation Serif", size=12) # Negative size means size in pixels
font2 = font1.copy()
font2.config(weight=tkFont.BOLD)
font3 = font2.copy()
font3.config(size=14) # Negative size means size in pixels
self.__class__.thanFonts = font1, font2, font3
else:
font1, font2, font3 = self.thanFonts
self.config(font=font1, height=5)
col = "#%2xd%2xd%2xd" % (66, 182, 33)
self.tag_config("mes", foreground="blue", font=font2)
self.tag_config("com", foreground="darkcyan", font=font2)
self.tag_config("can", foreground="darkred", font=font2)
self.tag_config("can1", foreground="darkred", font=font1)
self.tag_config("info", foreground="darkgreen", font=font2)
self.tag_config("info1", foreground="darkgreen", font=font1)
self.tag_config("thancad", foreground="white", background=col, font=font3)
self.thanCadVer()
self.__crel = [0.0]*proj[1].thanVar["dimensionality"]
self.thanCleanup()
# self.thanPrompt()
self.thanPrevCom = ""
self.__oncharPreempt = False
def thanCadVer(self):
"Prints ThanCad's version."
self.thanAppend("%s %s" % (thanvers.thanCadName, thanvers.thanCadVersion), "thancad")
self.thanAppend("\n%s %s, %s\n" % (thanvers.thanCopyright, thanvers.thanAuthorName, thanvers.thanCadDate))
def thanPrompt(self, mes=DEFMES):
"Shows a prompt for the user to enter something."
self.thanMes = mes
self.__reprompt()
def __reprompt(self):
"Reshows the default prompt or a specific command's prompt."
if self.thanMes == DEFMES: self.thanAppend(self.thanMes, "mes") # Other colour for default prompt
else: self.thanAppend(self.thanMes)
def thanOnChar(self, event):
"Well, here is what should be done when user presses a key."
if self.__oncharPreempt:
thanLogTk.error("ThanTkCmd.thanOnChar: preemptive call: character(s) lost. It shouldn't happen.")
return
self.__oncharPreempt = True
# print "len(event.char)=", len(event.char)
# print "key code=", event.keycode
# print "key sym=", event.keysym
if len(event.char) == 1:
m = ord(event.char)
if m == 27: self.thanOnCharEsc(event)
elif m == 13 or m == 32: self.__onCharRet(event)
self.__oncharPreempt = False
def __onPageup(self, event):
"Pageup pressed; if idle, pan drawing 1 page up."
if self.thanState != THAN_STATE_NONE: return # Page-up goes to the command window
self.thanEnter("panpageup", "com")
return "break" # Pageup does not go to the command window
def __onPagedown(self, event):
"Pagedown pressed; if idle, pan drawing 1 page up."
if self.thanState != THAN_STATE_NONE: return # Page-up goes to the command window
self.thanEnter("panpagedown", "com")
return "break" # Pageup does not go to the command window
def __onPageleft(self, event):
"Page left pressed; if idle, pan drawing 1 page up."
if self.thanState != THAN_STATE_NONE: return # Page-up goes to the command window
self.thanEnter("panpageleft", "com")
return "break" # Pageup does not go to the command window
def __onPageright(self, event):
"Page right pressed; if idle, pan drawing 1 page up."
if self.thanState != THAN_STATE_NONE: return # Page-up goes to the command window
self.thanEnter("panpageright", "com")
return "break" # Pageup does not go to the command window
def __onGrayplus(self, event):
"Gray plus pressed; if idle, zoom in 2 times."
if self.thanState != THAN_STATE_NONE: return # Grayplus goes to the command window
self.thanEnter("zoomin2", "com")
return "break" # Grayplus does not go to the command window
def __onGrayminus(self, event):
"Gray minus pressed; if idle, zoom out 2 times."
if self.thanState != THAN_STATE_NONE: return # Grayminus goes to the command window
self.thanEnter("zoomout2", "com")
return "break" # Grayminus does not go to the command window
def __donothing(self, event):
"""Shift-Pageup pressed; do nothing.
This function exists so that shift-pageup will not trigger __onPageup.
Tkinter will happily route shift-pageup, control-pageup etc. to the
pageup handler, if specialised handlers do not exist for these key-presses.
"""
pass
def __onF3(self, event):
"Toggle object snap."
if self.__oncharPreempt: return "break" # Avoid preemptive call
if "ena" in thancadconf.thanOsnapModes:
del thancadconf.thanOsnapModes["ena"]
self.thanAppend(T["\nObject snap is off.\n"], "info")
else:
thancadconf.thanOsnapModes["ena"] = True
self.thanAppend(T["\nObject snap is on.\n"], "info")
self.__reprompt()
def __onF8(self, event):
"Toggle ortho mode."
if self.__oncharPreempt: return "break" # Avoid preemptive call
on = self.__proj[2].thanCanvas.thanOrtho.toggle()
if on: self.thanAppend(T["\nOrtho on.\n"], "info")
else: self.thanAppend(T["\nOrtho off.\n"], "info")
self.__reprompt()
def __onF7(self, event):
"Toggle view type of coordinates."
if self.__oncharPreempt: return "break" # Avoid preemptive call
typ = self.__proj[2].thanStatusBar.thanToggleCoord()
self.thanAppend(T["\nView %s coordinates.\n"] % typ, "info")
self.__reprompt()
def __onF2(self, event):
"Toggle enlarged text window."
if self.__enlarged:
self.__enlarged.destroy()
self.__enlarged = None
else:
title = "%s: Content of command window" % self.__proj[0]
self.__enlarged = ThanTkCmdbig(self.__proj, self.thanGet(), title, font=self.thanFonts[0])
self.__enlarged.thanTkSetFocus()
def thanNotifyF2(self):
"The enlarged command window killed itself."
self.__enlarged = None
def thanOnCharEsc(self, evt):
"Quits current task."
if self.thanState != THAN_STATE_NONE:
self.thanCleanup()
return
dc = self.__proj[2].thanCanvas
if dc.thanState != THAN_STATE_NONE:
dc.thanCleanup()
self.thanCleanup(T["\nThanTkGuiGet was cleared for debugging reasons."], "can")
self.thanPrompt()
return
if dc.thanFloatMenu != None and dc.thanFloatMenu.winfo_ismapped():
dc.thanCleanup() # Delete floating (rightclick) menu
return
sched = self.__proj[2].thanScheduler
if not sched.thanSchedIdle():
sched.thanSchedClear()
dc.thanCleanup()
self.thanCleanup(T["\nThanScheduler was cleared for debugging reasons."], "can")
self.thanPrompt()
return
dc.thanCleanup()
self.thanCleanup("\n%s" % T["Nothing to cancel."], "can")
self.thanPrompt()
def __onCharRet(self, evt):
"Gets the command entered by the user"
self.thanWaitingInput = False
# now = [int(c) for c in self.index(Tkinter.INSERT).split(".")]
# end = [int(c) for c in self.index(Tkinter.END).split(".")]
now = self.thanIndex(Tkinter.INSERT)
end = self.thanIndex(Tkinter.END)
if end[0]-now[0] > 1:
l = str(now[0])
t = self.thanGetPart(l+".0", l+".end")
self.thanInsert(Tkinter.END, "\n"+t)
self.set_insert(Tkinter.END+"-1c")
else:
t = self.thanGetPart(Tkinter.END+"-1l", Tkinter.END)
t = t.strip()
n = -1; n1 = t.find(":")
while n1 >= 0:
n = n1; n1 = t.find(":", n+1)
if n >= 0: t = t[n+1:].strip()
self.after(100, self.__processEntry, t)
def thanEnter(self, com, tags=()):
"Simulate keyboard and return immediately."
self.thanWaitingInput = False
self.thanAppend("%s\n" % com, tags)
self.after(100, self.__processEntry, com)
PNTSTATES = frozenset((THAN_STATE_POINT, THAN_STATE_LINE, THAN_STATE_LINE2,
THAN_STATE_RECTANGLE, THAN_STATE_MOVE, THAN_STATE_ROADP, THAN_STATE_POLAR,
THAN_STATE_CIRCLE, THAN_STATE_ARC))
def __processEntry(self, t):
"Deals with the text the user entered."
s = self.thanState
if self.thanState == THAN_STATE_NONE:
self.__beginCommand(t)
elif t[:1] == "'":
c, fun = thancom.thanComFun(t[1:])
if fun != None:
self.thanLastResult = "'"+c
self.thanState = THAN_STATE_NONE
else:
self.thanAppend(T["Invalid nested command. Try again.\n"], "can")
self.__reprompt()
elif s in self.PNTSTATES:
try:
nd = self.__proj[1].thanVar["dimensionality"]
elev = self.__proj[1].thanVar["elevation"]
if t[0] == "@":
if len(t) == 1:
cc = [0.0] * nd
else:
cc = [float(c1) for c1 in t[1:].split(",")]
if len(cc) > nd: raise ValueError, "Too many dimensions"
if len(cc) < 2: raise ValueError, "Too few dimensions"
cc.extend(elev[len(cc):])
for i in xrange(nd): cc[i] += self.__crel[i]
else:
cc = [float(c1) for c1 in t.split(",")]
if len(cc) > nd: raise ValueError, "Too many dimensions"
if len(cc) < 2: raise ValueError, "Too few dimensions"
cc.extend(elev[len(cc):])
except (IndexError,ValueError):
self.thanLastResult = t
print "cmd: last result string: '%s'" % t
else:
self.__crel = tuple(cc)
self.thanLastResult = cc
print "cmd: last result point: ", cc
self.thanState = THAN_STATE_NONE
elif s == THAN_STATE_RECTRATIO:
try: r = float(t)
except (IndexError,ValueError):
self.thanAppend(T["Invalid real number. Try again.\n"], "can")
self.__reprompt()
self.thanWaitingInput = True
return
cc = list(self.__cc1)
cc[0] += r
cc[1] += r*self.__t1
self.thanLastResult = cc
self.thanState = THAN_STATE_NONE
elif s == THAN_STATE_TEXT or s == THAN_STATE_SNAPELEM:
self.thanLastResult = t
self.thanState = THAN_STATE_NONE
elif s == THAN_STATE_ZOOMDYNAMIC or s == THAN_STATE_PANDYNAMIC:
pass # no keyboard entry by definition
else:
assert False, "Unknown state: "+str(s)
self.thanWaitingInput = True
def thanLastPoint(self, cc):
"Sets last point set by gui for relative coords."
self.__crel = list(cc)
def thanPrepare(self, state, cc1=None, cc2=None, r1=None, t1=None):
"Sets the appropriate state and prepares for user input."
self.__cc1 = cc1
self.__cc2 = cc2
self.__rr1 = r1
self.__t1 = t1
self.thanState = state
if state == THAN_STATE_POINT1: self.thanState = THAN_STATE_POINT
self.thanWaitingInput = True
def thanCleanup(self, message="", mesmode="info1"):
"User cancelled or gave the results in other way (e.g. gui)."
if message != "": self.thanAppend("%s\n" % message, mesmode)
self.thanState = THAN_STATE_NONE
self.thanLastResult = Canc
self.thanWaitingInput = True
def __beginCommand(self, t):
"The user entered a command; launch it."
w = self.__proj[2]
assert w.thanScheduler.thanSchedIdle(), "No command should be running!!!"
n = len(t); t = t.lower()
if t == "":
if self.thanPrevCom == "":
self.thanPrompt()
self.thanWaitingInput = True
else:
self.thanEnter(self.thanPrevCom, "com")
return
c, fun = thancom.thanComFun(t)
if fun != None:
if t != c: self.thanAppend("%s\n" % c, "com")
w.thanScheduler.thanSchedule(fun, self.__proj) # A command will run immediately; thanWaitingInput remains False
self.thanPrevCom = c
else:
self.thanAppend(T["Unrecognized command\n"], "can")
self.thanPrompt()
self.thanWaitingInput = True
def thanBeginCommandNest(self, t):
"The user entered a nested command; launch it."
w = self.__proj[2]
n = len(t); t = t.lower()
c, fun = thancom.thanComFun(t)
if fun != None:
if t != c: self.thanAppend("%s\n" % c, "com")
fun(self.__proj)
else:
self.thanAppend(T["Unrecognized command\n"], "can")
def thanClear(self): self.thanSet("")
def destroy(self):
"Deletes circular references."
del self.__proj
p_gtkwid.ThanScrolledText.destroy(self)
class ThanTkCmdbig(Tkinter.Toplevel):
"Just the text of the command window enlarged."
def __init__(self, proj, mes, title, hbar=0, vbar=1, width=80, height=25,
font="system 12", background="lightyellow", foreground="black"):
"Setup info."
Tkinter.Toplevel.__init__(self, proj[2])
self.title(title)
self.__proj = proj
self.thanHelp = p_gtkwid.ThanScrolledText(self, hbar=hbar, vbar=vbar, font=font,
background=background, foreground=foreground, width=width, height=height)
self.protocol("WM_DELETE_WINDOW", self.__onF2) # In case user closes window with window manager
self.thanHelp.thanSet(mes)
self.thanHelp.grid(sticky="wesn")
self.__position()
self.rowconfigure(0, weight=1)
self.columnconfigure(0, weight=1)
self.__keysallowed = frozenset("Up Down Left Right Prior Next Home End".split())
self.thanHelp.bindte("<F2>", self.__onF2)
self.thanHelp.bindte("<Key>", self.__format)
self.thanHelp.set_insert(Tkinter.END+"-1c")
def __position(self):
"Position self."
w = self.__proj[2]
w.update()
x = w.winfo_rootx() + 20
y = w.winfo_rooty() + 15
self.geometry("%+d%+d" % (x, y))
def __format(self, evt):
"Allow only certain keys."
if evt.keysym not in self.__keysallowed: return "break"
def __onF2(self, *args):
"Terminate the window."
self.__proj[2].thanCom.thanNotifyF2()
self.destroy()
def thanTkSetFocus(self):
"Sets focus to the command window."
self.lift()
self.focus_set()
self.thanHelp.focus_sette()
def destroy(self):
"Break circular references."
del self.thanHelp, self.__proj
Tkinter.Toplevel.destroy(self)
def __del__(self):
"Say that it is deleted for debugging reasons."
from p_ggen import prg
prg("ThanTkCmdbig %s is deleted." % self)
|