##############################################################################
# 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.
This module defines functionality necessary for user lowlevel interaction in
a drawing window.
"""
from math import atan2,pi,fabs,hypot
import Tkinter
from thanvar import thanLogTk,Win32
from thantkguicroshair import *
from thantkconst import *
from thantkguiosnap import ThanOsnap,ThanOrtho
from thantkguistateless import ThanStateLess
from thantkguigeneric import ThanStateGeneric
from thantkguidrag import ThanStateDrag
from thantkguimove import ThanStateMove
from thantkguiline import ThanStateLine,ThanStateLine2,ThanStatePolar
from thantkguicircle import ThanStateCircle,ThanStateArc
from thantkguirect import ThanStateRectangle,ThanStateRectratio
from thantkguiroad import ThanStateRoadp,ThanStateRoadr
from thantkguivar import ThanStatePoint,ThanStateSelem
class ThanTkGuiLowGet(Tkinter.Canvas, ThanStateLess):
"Lowlevel input from a Tk canvas."
#============================================================================
def __init__(self, proj, *args, **kw):
"Initialise base class and then this class."
ThanStateLess.__init__(self)
Tkinter.Canvas.__init__(self, proj[2], *args, **kw)
self.__sb = proj[2].thanStatusBar
#-------Do some local initialisation
dc = self
dc.bind("<Key>", self.__onChar) # This should be deleted, or at least redirected to thanCom
dc.bind("<Double-Button-1>", self.__onDclick)
dc.bind("<Button-1>", self.__onClick)
dc.bind("<Button-3>", self.__onClickr)
dc.bind("<Motion>", self.__onMotion)
dc.bind("<B1-Motion>", self.__onMotionDrag)
dc.bind("<ButtonRelease-1>", self.__onReleaseDrag)
if Win32:
dc.bind("<MouseWheel>", self.__mouseWheel)
proj[2].bind("<MouseWheel>", self.__mouseWheelp) # Hack for Windows: Yeh, Windows "just works", no need for hacks
else:
dc.bind("<Button-4>", self.__downwheel)
dc.bind("<Button-5>", self.__upwheel)
if not Win32:
self.bind("<Page_Up>", self.thanPanpageup)
self.bind("<Shift-Page_Up>", self.__donothing)
self.bind("<Page_Down>", self.thanPanpagedown)
self.bind("<Shift-Page_Down>",self.__donothing)
self.bind("<Control-Up>", self.thanPanpageup)
self.bind("<Control-Down>", self.thanPanpagedown)
self.bind("<Control-Left>", self.thanPanpageleft)
self.bind("<Control-Right>", self.thanPanpageright)
self.bind("<F7>", self.__sb.thanToggleCoord)
self.thanState = THAN_STATE_NONE
self.thanOState = ThanStateGeneric(proj)
dc.update_idletasks() # _idletasks breaks WinDoze (98?) support. Skotistika
mx = dc.winfo_width() - 1
my = dc.winfo_height() - 1
self.thanXcu = dc.canvasx(mx / 2)
self.thanYcu = dc.canvasy(my / 2)
self.thanChs = ThanCrosHairs(proj)
self.thanCh = CrosHair(dc)
self.after(250, self.thanCh.resize) # Give the Canvas a fourth of a second, to stabilise
self.thanOsnap = ThanOsnap(proj)
self.thanOrtho = ThanOrtho()
self.thanFloatMenu = None
self.thanProj = proj
#============================================================================
def __mouseWheel(self, evt):
"Mouse wheel up or down; for windows only."
if evt.delta < 0: self.__upwheel(evt)
else: self.__downwheel(evt)
def __mouseWheelp(self, evt):
"Mouse wheel up or down when triggered on the parent; for windows only."
self.update_idletasks() # so that .winfo_xxx() works
evt.x = evt.x_root - self.winfo_rootx()
evt.y = evt.y_root - self.winfo_rooty()
if evt.delta < 0: self.__upwheel(evt)
else: self.__downwheel(evt)
#============================================================================
def __upwheel(self, evt): self.thanUpwheel(evt)
def __downwheel(self, evt): self.thanDownwheel(evt)
def __onMotionDrag(self, evt): self.thanOState.thanOnMotionDrag(evt)
def __onReleaseDrag(self, evt): self.thanOState.thanOnReleaseDrag(evt)
def __onClick(self, evt): self.thanOnClick(evt)
def __onClickr(self, evt): self.thanOnClickr(evt)
def thanPanpagedown (self, evt): return self.thanPanPage(evt, 0, -1)
def thanPanpageleft (self, evt): return self.thanPanPage(evt, -1, 0)
def thanPanpageright(self, evt): return self.thanPanPage(evt, 1, 0)
def thanPanpageup (self, evt): return self.thanPanPage(evt, 0, 1)
def __donothing(self, evt): pass
#============================================================================
def _resultCoorRel0(self, dxp, dyp):
"Convert relative pixel coordiantes to user data units."
self.thanLastResult = ([0.0]*self.thanProj[1].thanVar["dimensionality"], None)
self.thanLastResult[0][:2] = self.thanProj[2].thanCt.local2GlobalRel(dxp, dyp)
def _resultCoor(self, xp, yp):
"Convert relative pixel coordiantes to user data units."
self.thanLastResult = (list(self.thanProj[1].thanVar["elevation"]), None)
self.thanLastResult[0][:2] = self.thanProj[2].thanCt.local2Global(xp, yp)
#============================================================================
def __onMotion(self, event):
"Well, here is what should be drawn each time mouse moves."
self.thanOsnap.active = "ena" in self.thanOsnap.types
dc = self
x = dc.canvasx(event.x)
y = dc.canvasy(event.y)
self.thanCh.draw(x, y)
cc = list(self.thanProj[1].thanVar["elevation"])
cc[:2] = self.thanProj[2].thanCt.local2Global(x, y) # User coordinates (transformed from canvas coordinates)
self.__sb.thanCoorMouse(cc)
self.thanOState.thanOnMotion(event, x, y)
self.thanXcu = x
self.thanYcu = y
if self.thanState != THAN_STATE_NONE and self.thanOsnap.active:
self.after(10, self.thanOsnap.thanFind)
#============================================================================
def thanOnClick(self, event):
"Well, here is what should be done when mouse clicks."
dc = self
# dc.focus_set() # This is needed otherwise text control gets characters?
x = dc.canvasx(event.x)
y = dc.canvasy(event.y) # Click canvas coordinates
if self.thanOsnap.active and self.thanOsnap.items != (): # If object snap, change click coordinates
x = self.thanOsnap.x # Canvas coordinates
y = self.thanOsnap.y # Canvas coordinates
cc = self.thanOsnap.cc # User coordinates (from object snap)
else:
cc = list(self.thanProj[1].thanVar["elevation"])
x, y = self.thanOrtho.orthoxy(x, y) # In case ortho is active
cc[:2] = self.thanProj[2].thanCt.local2Global(x, y) # User coordinates (transformed from canvas coordinates)
self.__sb.thanCoorClick(cc) # Draw status text
self.thanOState.thanOnClick(event, x, y, cc)
self.thanXcu = x
self.thanYcu = y
#============================================================================
def thanOnClickr(self, event):
"Well, here is what should be done when right mouse clicks."
dc = self
# dc.focus_set() # This is needed otherwise text controls gets characters
x = dc.canvasx(event.x)
y = dc.canvasy(event.y)
if self.thanOsnap.active and self.thanOsnap.items != (): # If object snap, change click coordinates
x = self.thanOsnap.x # Canvas coordinates
y = self.thanOsnap.y # Canvas coordinates
cc = self.thanOsnap.cc # User coordinates (from object snap)
else:
cc = list(self.thanProj[1].thanVar["elevation"])
cc[:2] = self.thanProj[2].thanCt.local2Global(x, y) # User coordinates (transformed from canvas coordinates)
self.__sb.thanCoorClick(cc) # Draw status text
self.thanOState.thanOnClickr(event, x, y, cc)
if self.thanState == THAN_STATE_NONE:
if self.thanFloatMenu != None and self.thanFloatMenu.winfo_ismapped():
self.thanFloatMenu.unpost()
self.thanFloatMenu = self.__createFloatMenu()
self.thanFloatMenu.post(event.x_root, event.y_root)
def __createFloatMenu(self):
m = Tkinter.Menu(self, tearoff=False)
fbeg = self.thanProj[2].thanGudCommandBegin
m.add_command(label="Repeat last command", command=lambda fbeg=fbeg: fbeg(""))
m.add_command(label="Real time zoom", command=lambda fbeg=fbeg: fbeg("zoomrealtime"))
m.add_command(label="Real time pan", command=lambda fbeg=fbeg: fbeg("panrealtime"))
# m1 = Menu(m, tearoff=False)
# m1.add_checkbutton(label="zoom when window changes", variable=self.zoomWhenConf)
# m1.add_checkbutton(label="regen when window changes", variable=self.regenWhenConf)
# m1.add_separator()
# m1.add_checkbutton(label="regen when zoom", variable=self.regenWhenZoom)
# m1.add_checkbutton(label="regen when zoom all", variable=self.regenWhenZoomall)
# m1.add_checkbutton(label="center when zoom", variable=self.centerWhenZoom)
# m1.add_separator()
# m1.add_checkbutton(label="show menu bar", variable=self.showMenubar)
# m1.add_checkbutton(label="show tool bar", variable=self.showToolbar)
# m.add_cascade(label="options", menu=m1)
return m
#============================================================================
def __onDclick(self, event):
"On double click change to the next available croshair."
self.thanChs.thanRotate(self.canvasx(event.x), self.canvasy(event.y))
#============================================================================
def __onChar(self, event):
"Well, here is what should be done when user presses a key."
thanLogTk.error("onChar(): Unexpected Canvas <key> event redirected to ThanCom.")
win = self.thanProj[2]
win.thanTkSetFocus()
win.thanCom.thanOnChar(event)
#============================================================================
def thanPrepare(self, state, cc1=None, cc2=None, cc3=None, r1=None, t1=None):
"Sets the appropriate state and lets gui take on."
ct = self.thanProj[2].thanCt
x1, y1 = None, None
if cc1 != None: x1, y1 = ct.global2Local(cc1[0], cc1[1]) # Transform to local coordinates
x2, y2 = None, None
if cc2 != None: x2, y2 = ct.global2Local(cc2[0], cc2[1]) # Transform to local coordinates
x3, y3 = None, None
if cc3 != None: x3, y3 = ct.global2Local(cc3[0], cc3[1]) # Transform to local coordinates
r1, t1 = r1, t1
if r1 != None: r1, r = ct.global2LocalRel(r1, r1) # Transform to local coordinates
self.thanOsnap.cc1 = cc1
dc = self
dc.config(cursor=thanCursor.get(state, ""))
if state == THAN_STATE_POINT1: state = THAN_STATE_POINT
if state > THAN_STATE_DRAGFOLLOWS:
self.thanOState = ThanStateDrag(self.thanProj)
elif state == THAN_STATE_MOVE:
self.thanOState = ThanStateMove(self.thanProj, x1, y1)
elif state == THAN_STATE_LINE:
self.thanOState = ThanStateLine(self.thanProj, x1, y1)
elif state == THAN_STATE_LINE2:
self.thanOState = ThanStateLine2(self.thanProj, x1, y1, x2, y2)
elif state == THAN_STATE_POLAR:
self.thanOState = ThanStatePolar(self.thanProj, x1, y1, r1)
elif state == THAN_STATE_CIRCLE:
self.thanOState = ThanStateCircle(self.thanProj, x1, y1)
elif state == THAN_STATE_ARC:
self.thanOState = ThanStateArc(self.thanProj, x1, y1, r1, t1)
elif state == THAN_STATE_POINT:
self.thanOState = ThanStatePoint(self.thanProj)
elif state == THAN_STATE_RECTANGLE:
self.thanOState = ThanStateRectangle(self.thanProj, x1, y1, t1)
elif state == THAN_STATE_RECTRATIO:
self.thanOState = ThanStateRectratio(self.thanProj, x1, y1, t1, cc1)
elif state == THAN_STATE_ROADP:
self.thanOState = ThanStateRoadp(self.thanProj, x1, y1, x2, y2,
x3, y3, r1)
elif state == THAN_STATE_ROADR:
self.thanOState = ThanStateRoadr(self.thanProj, x1, y1, x2, y2,
x3, y3, r1)
elif state == THAN_STATE_SNAPELEM:
self.thanOState = ThanStateSelem(self.thanProj)
self.thanState = state
#============================================================================
def thanGudIdle(self):
"Returns true if not in the middle of a command."
return self.thanState == THAN_STATE_NONE
def thanTkClear(self):
"Clears a window."
dc = self
dc.delete(Tkinter.ALL) # Clear window
self.thanCh.resize()
def thanGudCoorChanged(self):
"System of canvas changed; redraw croshair."
self.thanCh.resize()
def destroy(self):
"Deletes circular references."
del self.__sb, self.thanProj, self.thanChs, self.thanCh,\
self.thanOState, self.thanOsnap
Tkinter.Canvas.destroy(self)
def __delete__(self):
"Show that self is really deleted."
print "thantklowget:", self, "has been freed."
#############################################################################
#############################################################################
#MODULE LEVEL CODE. IT IS EXECUTED ONLY ONCE
if __name__ == "__main__":
print __doc__
|