
| Current Path : /home/cgabriel/20_dev/12_procpy/dataninja/ |
Linux ift1.ift-informatik.de 5.4.0-216-generic #236-Ubuntu SMP Fri Apr 11 19:53:21 UTC 2025 x86_64 |
| Current File : //home/cgabriel/20_dev/12_procpy/dataninja/block.py |
# coding: utf8
import os,sys,re,time,tkinter,random,procpy
try:
import tkinter.ttk,Pmw # ,tkintertable
except:
import pip
pip.main(["install","pyttk"])
pip.main(["install","Pmw"])
# pip.main(["install","tkintertable"])
import tkinter.ttk,Pmw # ,tkintertable
import tkinter.scrolledtext
import procpy.config
import pdb
#************************************************************************
class Block (object): # REQ-009:REQ-009
def __init__ (self,canvas,bbox,shape="r", looping=0):
self.canvas = canvas
self.bbox = bbox[:]
self.color = procpy.config.COLOR_BLOCK
self.arrows_in = [] # arrows coming in
self.arrows_out = [] # arrows going out
self.nr = 0 # the level of the block respecting the ancestor series
self.elems = {} # actual elems of the block (rectangle, triangle, rhombe, circle ...)
self.fontsize = 8
self.exit = "" # defines where arrows should come out of the block
self.entrance = "" # defines where arrows should enter the block
self.looping = looping
self.last_event = 0
self.generate_shape(shape)
self.format_shape()
# self.define_level()
#************************************************************************
def dump (self):
try:
return [self.bbox,self.shape, self.looping, self.content.get("1.0","end-1c")]
except:
return [self.bbox,self.shape, self.looping]
#************************************************************************
def box_coord (self):
x0 = self.bbox[0]
y0 = self.bbox[1]
x1 = self.bbox[2]
y1 = self.bbox[3]
x = 0.5 * (x0 + x1)
y = 0.5 * (y0 + y1)
w = x1 - x0
h = y1 - y0
return(x0,y0,x1,y1,x,y,w,h)
#************************************************************************
# Computes order numbers and path levels (series of branches in which the process runs)
def compute_level (self,touched_blocks,branch_counter):
predecessor_blocks = []
self.level = []
reduce_in = self.arrows_in_reduce() # do not consider formerly identified
reduce_out = self.arrows_out_reduce() # loop-forming arrows
if not self.shape == "r" and self.determine_shape() == "r": # do not change control shape to a rectngular shape
return(False)
if len(reduce_out) > 1 and len(reduce_in) == 0: # to avoid that a sequenze starts with a split
return(False)
for arrow in reduce_in: # all predecessor blocks have to be numbered, otherwise return
if arrow.source_block.nr == 0: # This has the impact, that in a backward connection case
return(True) # the blocks cannot be numbered -> they are in a loop
for arrow in reduce_in: # run through all arrows going into the block
self.nr = max(arrow.source_block.nr,self.nr) # compute the maximal order number of all predecessor blocks
self.level = arrow.source_block.level[:] # first assumption: path level should be the same as predecessor block
# print ("PRE",arrow.source_block.nr,arrow.source_block.level)
if not self.level == []: # we store in the array predecessor_blocks all
predecessor_blocks.append("-".join(self.level[:-1])) # former paths without the last level. If that
else: # 'upper' paths are alle the same, then the block
predecessor_blocks.append(".NULL.") # is properly joined to its predecessors
touched_blocks.append(self)
self.nr = self.nr + 1 # now increase the block order
if len(predecessor_blocks) > 1: # if there are more than one predecessor, then there is
if len(set(predecessor_blocks)) == 1: # a re-unification of branches, and the level goes up
self.level.pop() # but only if all predecessors have the same upper path
else:
return(False) # otherwise it is wrong joined
if branch_counter: # if there is a branch_counter given (aftera split)
self.level.append(str(branch_counter)) # then add it to the path level (split off branches)
if len(self.level) == 0: # condition to make sure that a join allways is induced by a split
return(False)
if len(reduce_out) > 1: # if the are more than one successors,
branch_counter = 1 # then they will be enumerated and all of them are put to sub-paths
else:
branch_counter = None
for arrow in reduce_out:
block = arrow.target_block
if block in touched_blocks:
continue
if not block.compute_level(touched_blocks,branch_counter):
return(False)
if branch_counter:
branch_counter = branch_counter + 1
self.canvas.create_text(self.bbox[0],self.bbox[1]-12,anchor=tkinter.NW, # only for debugging
text=str(self.nr)+"/"+"-".join(self.level),tag="debug")
return(True)
#************************************************************************
def clear_shape (self):
for elem in list(self.elems.values()):
self.canvas.delete(elem)
if 'content' in vars(self):
self.content_backup = self.content.get("1.0",tkinter.END)
self.content.place_forget()
del self.content
del self.contentframe
self.canvas.delete(self.window)
del self.window
#************************************************************************
def destroy (self, destroy_arrows=True):
# self.clear_shape()
if destroy_arrows:
blocks_to_reshape = []
for arrow in ( set(self.arrows_in) | set(self.arrows_out) ):
blocks_to_reshape.append(arrow.source_block)
arrow.destroy()
for block in blocks_to_reshape:
block.fit_shape()
self.clear_shape()
#************************************************************************
def arrows_in_reduce (self):
return(set(self.arrows_in) - self.canvas.loop_arrows)
#************************************************************************
def arrows_out_reduce (self):
return(set(self.arrows_out) - self.canvas.loop_arrows)
#************************************************************************
def determine_shape (self): # this function determines the shape of the block
# up to now, it takes in only the arrows to and from the block
# later, further arguments or algorrithm for determination fo the shape
# can be added
shape = { "00": "r", # the numbers give the in and out arrows
"01": "c", # c
"02": "c", # c
"10": "r", # e
"11": "r",
"12": "ifm",
"20": "w", # e
"21": "ws",
"22": "s" } [ str(min( len(self.arrows_in_reduce()) ,2)) +
str(min( len(self.arrows_out_reduce()) ,2)) ]
if shape == "ifm": # split off paths: shape depends on splitting case constraints
shape = "i"
wertebereiche = []
for arrow in self.arrows_out:
text = arrow.text.get("1.0")
m = re.search(r"(\d+?),?(\d*)",text)
if m:
try:
val = [int(m.group(1)),int(m.group(2))]
shape = "f"
except:
val = [int(m.group(1)),int(m.group(1))]
for val1 in wertebereiche:
if val1[1] > val[0] or val[1] > val1[0]:
shape = "m"
break
if shape == "m":
break
wertebereiche.append(val)
if shape == "ws":
shape = "w"
return(shape)
#***********************************************************************
def fit_shape (self,mode=0): # checks whether correct shape
# mode 0: make new only if shape has changed
shape = self.determine_shape()
if shape != self.shape or mode == 1: # if shape (or location) has changed
self.destroy(destroy_arrows=False) # clear old shape
self.generate_shape(shape) # create new shape
self.format_shape() # format the shape
#************************************************************************
def generate_shape (self,shape):
'''
Shapes:
r: Normale rectangle block
s: Subprocess (rectangle)
i: Case switch (diamond with X)
f: Forking block (diamond with cross)
m: Multiple switch (diamond with star)
w: Wait Block (diamond with circle)
c: Start Block (circle)
e: End Block (circle)
a: Swim lane
After defining the shape, the proper measures of the shape and the location
have to be done with format_shape()
'''
if shape in "rs": # Rectangle, normal block, r: rectangle, s: swimlane
print("-----QGraphicsRectItem--rs")
self.elems = { "SHAPE": self.canvas.create_rectangle(0,0,0,0,fill=self.color) }
self.contentframe = tkinter.Frame(self.canvas,background=self.color,bg=self.color,bd=0)
self.content = tkinter.Text(self.contentframe,wrap="none",font=("Courier",int(self.fontsize)),
borderwidth=0,insertborderwidth=0,bg=self.color,highlightcolor=self.color)
(x0,y0,x1,y1,x,y,w,h) = self.box_coord()
self.window = self.canvas.create_window(x,y,window=self.contentframe)
self.contentframe.grid_propagate(False)
self.content.config(state=tkinter.DISABLED)
if shape in "s":
self.elems['EXPAND'] = self.canvas.create_rectangle(0,0,0,0,width=1)
self.elems['X1'] = self.canvas.create_line(0,0,0,0,fill='black',width=1)
self.elems['X2'] = self.canvas.create_line(0,0,0,0,fill='black',width=1)
elif shape in "iwfm": # Diamond, i: X inside, f: + inside (fork), m: * inside (multi)
print("-----QGraphicsRectItem--iwfm")
self.elems = { "SHAPE": self.canvas.create_polygon(0,0,0,0,0,0,0,0,fill=self.color,outline='black') }
if shape in "im":
self.elems['CROSS1'] = self.canvas.create_line(0,0,0,0,fill='black',width=3)
self.elems['CROSS2'] = self.canvas.create_line(0,0,0,0,fill='black',width=3)
if shape in "fm":
self.elems['X1'] = self.canvas.create_line(0,0,0,0,fill='black',width=3)
self.elems['X2'] = self.canvas.create_line(0,0,0,0,fill='black',width=3)
if shape == "w":
self.elems['CIRCLE'] = self.canvas.create_oval(0,0,0,0,outline='black',width=3)
elif shape in "ce": # Circle
print("-----QGraphicsRectItem--ce")
self.elems = { "SHAPE": self.canvas.create_oval(0,0,0,0,fill=self.color,outline='black') }
self.contentframe = tkinter.Frame(self.canvas,background=self.color,bg=self.color)
self.content = tkinter.Text(self.contentframe,wrap="none",bg=self.color,
highlightcolor=self.color,borderwidth=0,insertborderwidth=0)
self.window = self.canvas.create_window(158,99,window=self.contentframe)
self.contentframe.grid_propagate(False)
self.content.config(state=tkinter.DISABLED)
elif shape in "t": # Triangle
print("-----QGraphicsRectItem--t")
self.elems = { "SHAPE": self.canvas.create_polygon(0,0,0,0,0,0,fill=self.color,outline='black') }
self.content = tkinter.Text(self.canvas,wrap="none",bg=self.color,highlightcolor=self.color,
borderwidth=0,insertborderwidth=0)
self.content.config(state=tkinter.DISABLED)
self.content.config(font=('Courier',int(self.fontsize)))
if 'content' in vars(self) and 'content_backup' in vars(self) and not self.content_backup.isspace():
if self.content.cget("state")==tkinter.DISABLED:
self.content.config(state=tkinter.NORMAL)
self.content.insert("1.0",self.content_backup.strip()) # text can be inserted only in NORMAL mode!!!
self.content.config(state=tkinter.DISABLED)
else:
self.content.insert(tkinter.END,self.content_backup) # text can be inserted only in NORMAL mode!!!
self.elem_bindings() # create event bindings on the shape
self.shape = shape
print("-----QGraphicsRectItem--generate")
self.define_exit_and_enter() # define where arrows should exit and enter
#************************************************************************
def elem_bindings (self):
if 'content' in vars(self):
self.content.bind("<ButtonPress-1>", lambda event: self.press_button_event(event))
self.content.bind("<ButtonRelease-1>", self.release_button_event)
self.content.bind("<B1-Motion>", self.move_mouse_event)
# self.content.bind("<Double-Button-1>", self.double_click_button_event)
for elem in list(self.elems.values()):
self.canvas.tag_bind(elem,"<ButtonPress-1>", lambda event: self.press_button_event(event))
self.canvas.tag_bind(elem,"<ButtonRelease-1>", self.release_button_event)
self.canvas.tag_bind(elem,"<B1-Motion>", self.move_mouse_event)
# self.canvas.tag_bind(elem,"<Double-Button-1>", self.double_click_button_event)
#************************************************************************
def syntax_error (self):
try: # some widgets dont contain text
text = self.content.get("1.0",tkinter.END)
except: # these widgets are "ok" anyway
return(0)
try: # if they do contain text
exec ("\n" + text + "\n")
except Exception as e: # return ok only if it is working code
# print str(e)
if re.search("invalid syntax",str(e)):
return(1)
return(0)
#************************************************************************
def format_shape (self):
(x0,y0,x1,y1,x,y,w,h) = self.box_coord()
if self.shape in "iwfmce":
if self.shape in "iwfm": # reduce the bounding box to a square
w = 40 * self.canvas.zoom_factor # always same size for diamonds
else: # because diamond shapes shall be always rectangular,
w = min(w,h)
h = w # and circles should be circles, not ovals
self.oldbbox = self.bbox # save old size for reusing if square needs to be changed back
self.bbox = [x-w/2,y-h/2 ,x+w/2,y+h/2] # bbox must be changed, otherwise problems with arrow length
if self.shape in "rs":
if 'oldbbox' in vars(self):
self.bbox = self.oldbbox
del self.oldbbox
self.canvas.coords(self.elems['SHAPE'],*self.bbox)
self.contentframe.config(width=int(0.9*w),height=int(0.9*h))
self.content.config(font=("Courier",int(self.fontsize)))
self.content.place(x=0,y=0,width=int(0.9*w),height=int(0.9*h))
(x9,y9) = self.canvas.coords(self.window)
self.canvas.move(self.window,x-x9,y-y9)
if self.shape == "s":
self.canvas.coords(self.elems['EXPAND'], x-0.09*w,y+0.32*h,x+0.09*w,y+0.5*h)
self.canvas.coords(self.elems['X1'], x-0.09*w,y+0.32*h,x+0.09*w,y+0.32*h)
self.canvas.coords(self.elems['X2'], x,y+0.4*h,x,y+0.5*h)
elif self.shape in "iwfm":
self.canvas.coords(self.elems['SHAPE'], x-w/2,y, x,y+h/2, x+w/2,y, x,y-h/2 )
if self.shape in "fm":
self.canvas.coords(self.elems['X1'], x-0.17*w,y-0.17*h, x+0.17*w,y+0.17*h)
self.canvas.coords(self.elems['X2'], x+0.17*w,y-0.17*h, x-0.17*w,y+0.17*h)
if self.shape in "im":
self.canvas.coords(self.elems['CROSS1'], x-0.2404*w,y, x+0.2404*w,y)
self.canvas.coords(self.elems['CROSS2'], x,y-0.2404*h, x,y+0.2404*h)
if self.shape == "w":
self.canvas.coords(self.elems['CIRCLE'], x-0.19*w,y-0.19*h, x+0.19*w,y+0.19*h)
elif self.shape in "ce":
self.canvas.coords(self.elems['SHAPE'], *self.bbox)
self.contentframe.config(width=int(0.7*w),height=int(0.7*h))
self.content.config(font=("Courier",int(self.fontsize)))
self.content.place(x=0,y=0,width=int(0.7*w),height=int(0.7*h))
(x9,y9) = self.canvas.coords(self.window)
self.canvas.move(self.window,x-x9,y-y9)
elif self.shape in "t":
self.canvas.coords(self.elems['SHAPE'], self.bbox[0],self.bbox[3],x,self.bbox[1],self.bbox[2],self.bbox[3])
self.content.place(x=int(x-0.28*w),y=int(y1-0.56*h),width=int(0.56*w),height=int(0.56*h))
for arrow in self.arrows_in + self.arrows_out:
arrow.fit_block_connections()
arrow.fit_description()
#**************************************************************************
# fix the code exit and enter by nxs 2018-04-04, email:xsnai@yahoo.com
def define_exit_and_enter(self, exit="", entrance=""): # SHAPE-001 PLANNED
# defines where arrows enter and exit the block depending on its shape
if procpy.config.ARROWDIRECTION =="NS":
if entrance:
self.entrance = entrance
elif self.shape in "rsifm": # rectangle, subprocess, case switch, forking block, multiple switch
self.entrance = "n" # arrows enter west ,self.entrance = "w"
elif self.shape in "w": # wait block
self.entrance = "wn" # arrows enter north ,west , self.entrance = "wns"
if exit:
self.exit = exit
elif self.shape in "rswce":
self.exit = "s" # arrows exit east, self.exit = "e"
elif self.shape in "fim":
self.exit = "nse" # arrows exit north and south and east , self.exit = "nse"
# ENDREQ
if procpy.config.ARROWDIRECTION == "EW":
if entrance:
self.entrance = entrance
elif self.shape in "rsifm": # rectangle, subprocess, case switch, forking block, multiple switch
self.entrance = "w" # arrows enter west ,self.entrance = "w"
elif self.shape in "w": # wait block
self.entrance = "wns" # arrows enter north and south and west, self.entrance = "wns"
if exit:
self.exit = exit
elif self.shape in "rswce":
self.exit = "e" # arrows exit east, self.exit = "e"
elif self.shape in "fim":
self.exit = "nse" # arrows exit north and south and east , self.exit = "nse"
# ENDREQ
###nxs
#************************************************************************
def press_button_event (self,event):
self.press_button(self.canvas.canvasx(event.x),self.canvas.canvasy(event.y),event.x_root,event.y_root)
#************************************************************************
def press_button (self,px,py,x_root,y_root):
timeclock = time.perf_counter()
if self.last_event == 1 and timeclock - self.last_pressed < procpy.config.DOUBLECLICK:
self.last_event = 2
self.last_pressed = -100
return()
self.canvas.configure(cursor='sizing') # Alternative mouse pointers: arrow circle
# clock cross dotbox exchange fleur heart
self.resize_box = "" # man mouse pirate plus shuttle sizing spider
# spraycan star target tcross trek watch
self.x_root = x_root
self.y_root = y_root
(x0,y0,x1,y1,x,y,w,h) = self.box_coord()
if self.shape in "rs":
if abs(y1 - py) < 4: # if pressing point is near the border of the box
self.resize_box = self.resize_box + "S" # mark the direction for resizing
if abs(y0 - py) < 4:
self.resize_box = self.resize_box + "N"
if abs(x0 - px) < 4:
self.resize_box = self.resize_box + "W"
if abs(x1 - px) < 4:
self.resize_box = self.resize_box + "E"
self.last_event = 1
self.mouse_moves = 0
self.last_pressed = timeclock
#*************************************************************************
def move_mouse_event (self,event):
dx = event.x_root - self.x_root
dy = event.y_root - self.y_root
if self.resize_box == "":
self.move(dx,dy)
else:
self.resize(dx,dy)
self.x_root = event.x_root
self.y_root = event.y_root
self.mouse_moves = self.mouse_moves + 1
# print ("MOVE_THE_MOUSE",self.mouse_moves)
if self.mouse_moves > 8:
self.last_event = 3
#************************************************************************
def move (self,dx,dy):
self.bbox[0] = self.bbox[0] + dx
self.bbox[1] = self.bbox[1] + dy
self.bbox[2] = self.bbox[2] + dx
self.bbox[3] = self.bbox[3] + dy
self.format_shape()
# self.canvas.rearr_grid(0.2)
#************************************************************************
def resize (self,dx,dy):
if "N" in self.resize_box:
self.bbox[1] = self.bbox[1] + dy
elif "S" in self.resize_box:
self.bbox[3] = self.bbox[3] + dy
if "W" in self.resize_box:
self.bbox[0] = self.bbox[0] + dx
elif "E" in self.resize_box:
self.bbox[2] = self.bbox[2] + dx
self.format_shape()
# self.canvas.rearr_grid(0.2)
for arrow in self.arrows_in + self.arrows_out:
arrow.fit_block_connections()
arrow.fit_description()
#************************************************************************
def scale (self,fac):
for i in (0,1,2,3):
self.bbox[i] = self.bbox[i] * fac
self.fontsize = self.fontsize * fac
for arrow in self.arrows_out:
arrow.scale(fac)
self.format_shape()
#****************************************************
def double_click_button_event (self,event):
pass
self.last_event = 2
#****************************************************
def release_button_event (self,event=None):
self.canvas.configure(cursor='arrow')
# print(self.last_event)
if not event or not self.last_event == 2: # press_button or move
self.hidden_highlight = not event
if not self.canvas.hl_block[0] == self: # if I am not yet highlighted, un-highlight the former highlighted block
self.canvas.highlight_block(self) # and set it to the last highlighted block, and set myself to highlighted
self.hl_arrow = None
for arrow in self.arrows_in: # now check all incoming arrows. The one where its
if arrow.source_block == self.canvas.hl_block[1]: # source_block is the last highlighted block,
self.hl_arrow = arrow # has also to be highlighted
if False and self.hl_arrow == None: ## DISABLED # check also inverted direction
for arrow in self.arrows_out:
if arrow.target_block == self.canvas.hl_block[1]:
self.hl_arrow = arrow
self.highlight_myself(0)
elif self.canvas.hl_block[0] and self.syntax_error():
self.content.focus_set() # if the block is highlighted, focus on content
self.content.mark_set("insert",tkinter.END) # important if syntax error is given
else: # last event was a double click
self.canvas.create_arrow()
# self.canvas.rearr_grid(procpy.config.MOVESPEED)
if self.last_event == 3:
self.canvas.rearr_grid(procpy.config.MOVESPEED)
#*****************************************************************************************************
def highlight_myself (self,nr,mode=0): # mode == 1: blinking
if 'old_color' in vars(self):
self.canvas.after(200,self.highlight_myself,nr,mode)
return()
fillcolor1 = self.color
if not self.hidden_highlight:
fillcolor1 = [procpy.config.COLOR_HIGHLIGHT_ALT[0],procpy.config.COLOR_HIGHLIGHT_ALT[0],
procpy.config.COLOR_HIGHLIGHT[0],procpy.config.COLOR_HIGHLIGHT[0]
][nr+mode]
self.colorize_block(fillcolor1)
if self.hl_arrow:
fillcolor2 = [procpy.config.COLOR_HIGHLIGHT[0],self.color,self.color,self.color][nr+mode]
if len(self.canvas.blocks) < 6:
# fillcolor2 = fillcolor1
fillcolor2 = procpy.config.COLOR_HIGHLIGHT[0]
self.hl_arrow.highlight(fillcolor2)
else:
if 'content' in vars(self):
if self.content.cget('state') == tkinter.DISABLED:
self.content.config(state=tkinter.NORMAL)
self.content.focus_set()
self.content.mark_set("insert",tkinter.END)
delay = -nr
if self.canvas.hl_block[0] == self:
delay = 180 + mode*120
if delay > -1:
self.canvas.after(delay,self.highlight_myself,1-nr,2*self.syntax_error())
else:
self.colorize_block(self.color)
if self.hl_arrow:
self.hl_arrow.highlight()
if not self.hl_arrow.text.get("1.0","end-1c"):
self.canvas.itemconfig(self.hl_arrow.window,state=tkinter.HIDDEN)
else:
self.hl_arrow.text.config(state=tkinter.DISABLED)
self.hl_arrow = None
if 'content' in vars(self):
self.content.config(state=tkinter.DISABLED)
#************************************************************************
def colorize_block (self,color1):
self.canvas.itemconfig(self.elems['SHAPE'],fill=color1)
if 'content' in vars(self):
self.content.config(bg=color1,highlightcolor=color1)
self.contentframe.config(background=color1,bg=color1,highlightcolor=color1)
self.canvas.update()
#************************************************************************
def mark_as_running (self,mode=0):
if 'old_color' in vars(self) and mode < 1:
self.colorize_block(self.old_color)
del self.old_color
elif not 'old_color' in vars(self) and mode > -1:
self.old_color = self.canvas.itemcget(self.elems['SHAPE'],'fill')
self.colorize_block(procpy.config.COLOR_RUNNING)
#************************************************************************
def get_shape_connection_point (self,p1):
'''
Computes the point on the the border of the surrounding shape of the block
which connects an outer point p to the block
'''
(x0,y0,x1,y1,x,y,w,h) = self.box_coord()
p = [ min(max(x0, p1[0]), x1), min(max(y0, p1[1]), y1) ]
# p2: touches the bounding box. This basic point has to be extended into the bounding box depending on the shape:
if not self.shape in "rs":
p2 = p[:]
if p2[0] == p1[0]:
p2[1] = y
if p2[1] == p1[1]:
p2[0] = x
if self.shape in "iwfm": # diamond
fac = 1
if p1[0] < x:
p3 = [x0,y]
else:
p3 = [x1,y]
fac = -fac
if p1[1] < y:
p4 = [x,y0]
else:
p4 = [x,y1]
fac = -fac
try:
m = ( p4[0] - p2[0] + fac * (p4[1] - p2[1]) ) / ( p1[0] - p2[0] + fac * (p1[1] - p2[1]) )
p = [ p1[0] * m + p2[0] * (1-m), p1[1] * m + p2[1] * (1-m) ]
except: # in this case, the outer point points to the closest edge
pass
elif self.shape in "ce": # circle
a = (p1[0]-p2[0])**2 + (p1[1]-p2[1])**2 # a * m*m - 2 * b * m + c = 0, quadratic equation to solve
b = (p1[0]-p2[0])*(x-p2[0]) + (p1[1]-p2[1])*(y-p2[1])
c = (x-p2[0])**2 + (y-p2[1])**2 - ((x0-x1)/2)**2
try:
m = ( b + (b**2 - a*c)**0.5 ) / a
p = [ p1[0] * m + p2[0] * (1-m), p1[1] * m + p2[1] * (1-m) ]
except: # in this case, the outer point points to the most west, east, north or south point of the circle
pass
elif self.shape in "t": # triangle
if p1[1] > y1: # point is underneath the bottom of the triangle.
pass # Nothing to do -> the same behaviour as in rectangle shape mode
else:
p3 = [x,y0]
if p1[0] < x:
p4 = [x0,y1]
else:
p4 = [x1,y1]
a = (p2[0]-p4[0])*(p3[1]-p4[1]) - (p2[1]-p4[1])*(p3[0]-p4[0])
b = (p2[0]-p1[0])*(p3[1]-p4[1]) - (p2[1]-p1[1])*(p3[0]-p4[0])
try:
m = a / b
p = [ p1[0] * m + p2[0] * (1-m), p1[1] * m + p2[1] * (1-m) ]
except: # in this case, the outer point points to the closest edge
pass
return(p)
#************************************************************************
def gridpos (self,i=None,j=None):
# if 'newbbox' in vars(self):
# return(tuple(self.ij))
px = (1-self.canvas.snap['OBJX']) * self.bbox[0] + self.canvas.snap['OBJX'] * self.bbox[2]
py = (1-self.canvas.snap['OBJY']) * self.bbox[1] + self.canvas.snap['OBJY'] * self.bbox[3]
if not i:
i = int((px - self.canvas.griddata['OFFSETX'] + (0.5+self.canvas.snap['GRIDX'])*self.canvas.griddata['X'])/self.canvas.griddata['X'])
j = int((py - self.canvas.griddata['OFFSETY'] + (0.5+self.canvas.snap['GRIDY'])*self.canvas.griddata['Y'])/self.canvas.griddata['Y'])
x = self.canvas.griddata['OFFSETX'] + (i + self.canvas.snap['GRIDX']) * self.canvas.griddata['X']
y = self.canvas.griddata['OFFSETY'] + (j + self.canvas.snap['GRIDY']) * self.canvas.griddata['Y']
self.newbbox = [ self.bbox[0] + (x-px), self.bbox[1] + (y-py), self.bbox[2] + (x-px), self.bbox[3] + (y-py) ]
self.ij = [i,j]
return(i,j)
#**************************************************************************
def bounding_box (self,extbox=None):
'''
Returns the bounding box of the block.
If an optional 4-elem array is given, this
will be extended to the bounding box.
'''
if extbox == None:
extbox = []
if len(extbox) == 0:
extbox.append(self.bbox[0])
extbox.append(self.bbox[1])
extbox.append(self.bbox[2])
extbox.append(self.bbox[3])
else:
extbox[0] = min(extbox[0],self.bbox[0])
extbox[1] = min(extbox[1],self.bbox[1])
extbox[2] = max(extbox[2],self.bbox[2])
extbox[3] = max(extbox[3],self.bbox[3])
return(extbox)
#************************************************************************
def run (self): # run the block with a certain variable set
locals().update(self.canvas.prgvars) # read the actual variables
try:
__block_program_code__ = self.content.get("1.0",tkinter.END)
except:
__block_program_code__ = ""
self.colorize_block(procpy.config.COLOR_RUNNING)
for arrow in self.arrows_in:
if arrow.source_block == self.canvas.hl_block[0]:
arrow.source_block.colorize_block(procpy.config.COLOR_HIGHLIGHT_ALT[0])
else:
arrow.source_block.colorize_block(procpy.config.COLOR_BLOCK)
exec(__block_program_code__) # execute the program in the block
reduce_in = self.arrows_in_reduce()
reduce_out = self.arrows_out_reduce()
loop_call_active = False
for arrow in self.arrows_out: # evaluate the conditions of the arrows at runtime
try:
__arrow_program_code__ = arrow.text.get("1.0",tkinter.END)
except:
__arrow_program_code__ = "True"
if not re.search(r"\S",__arrow_program_code__):
__arrow_program_code__ = "True"
try:
arrow.runtime_bed = eval(__arrow_program_code__)
except:
arrow.runtime_bed = False
if arrow.runtime_bed and arrow in self.canvas.loop_arrows:
loop_call_active = True
print("LA",loop_call_active)
if loop_call_active: # to avoid that process runs in a loop AND the same time
active_arrow_set = False # prcoeeds to another path. Only one loop arrow will be
for arrow in self.arrows_out: # set to go to the next block
if arrow.runtime_bed and arrow in self.canvas.loop_arrows and not active_arrow_set:
continue
arrow.runtime_bed = False
self.canvas.prgvars = locals().copy() # store the result variable status
token = self.token[:]
# print("NR0",self.nr,self.level,token,self.canvas.tokens[token[-1]])
if len(reduce_in) > 1:
if self.canvas.tokens[token[-1]] > 0:
self.canvas.tokens[token[-1]] -= 1
self.canvas.running_blocks -= 1
return()
else:
token = token[:-1]
# print("NR1",self.canvas.tokens[token[-1]])
if len(reduce_out) > 1:
token = token + [ self.canvas.new_token() ]
time.sleep(self.canvas.run_delay)
self.canvas.tokens[token[-1]] -= 1
self.canvas.running_blocks -= 1
proceeding_block_exists = False
for arrow in self.arrows_out:
if arrow.runtime_bed:
# print(123)
self.canvas.tokens[token[-1]] += 1
arrow.target_block.token = token[:]
self.canvas.after(random.randint(0,3),arrow.target_block.run) # the blocks run in parallel
self.canvas.running_blocks += 1
proceeding_block_exists = True
del arrow.runtime_bed
print("PP",proceeding_block_exists)
if not proceeding_block_exists:
if self == self.canvas.hl_block[0]:
self.colorize_block(procpy.config.COLOR_HIGHLIGHT_ALT[0])
else:
self.colorize_block(procpy.config.COLOR_BLOCK)
if self.canvas.running_blocks == 0:
self.canvas.end_process()
#************************************************************************
#************************************************************************
#************************************************************************
#************************************************************************
#************************************************************************
class Block1 (object):
def __init__ (self,mode,frame,obj):
self.mode = mode # no functionality
self.frame = frame # the gui_file-object
self.graphcanvas = frame.graphcanvas # the canvas
self.vars = [] # the variables of the block
self.text_invisible = [] # the hiddenvariables
self.arrows_in = [] # arrows coming in
self.arrows_out = [] # arrows going out
self.nr = 0 # the level of the block respecting the ancestor series
self.elems = {} # actual elems of the block (rectangle, triangle, rhombe, circle ...)
self.shape = "x" # the shape of the block
self.syntax_error = 0 # indicates whether text insinde block is valid python syntax
self.fontsize = self.frame.current_zoom_factor * procpy.config.TEXT_SIZE # size of inside text
self.fkt = obj._FKT_
(x,y,w,h) = obj.BLOCK[1:5]
self.bbox = [x-w/2,y-h/2,x+w/2,y+h/2]
self.color = procpy.config.COLOR_BLOCK
self.sync_variables_to_text(obj.__dict__,obj.BLOCK[5:])
self.text = re.sub(r"$","",self.text,99999999)
if len(obj.BLOCK) > 5 and not obj.BLOCK[5] == "":
self.color = obj.BLOCK[5]
m = re.search(r"^([A-Za-z]+)([0]+)$",self.fkt) # choose a new name
if m:
zaehler = 0
formheader = "%0"+str(len(m.group(2)))+"u"
while (0 == 0):
zaehler = zaehler + 1
self.fkt = m.group(1) + (formheader % zaehler)
for block in self.frame.blocks:
if self.fkt == block.fkt:
self.fkt = ""
break
if not self.fkt == "":
break
if self.bbox[0] <= 0: # make a swimlane # --> 078-SWIM
self.color = procpy.config.COLOR_SWIMLANE
self.bbox[0] = 0
self.bbox[2] = self.frame.current_zoom_factor * procpy.config.SWIMLANE_WIDTH
if self.bbox[3]-self.bbox[1]==40: # only make different size, if the block size 40 is given;
self.bbox[1] = max(0, y - 3 * self.bbox[2]) # this indicates, that the block was not predefined by the user
self.bbox[3] = y + 3 * self.bbox[2] # but it is defined for the first time (not save/open)
# <-- 078-SWIM
for block in self.frame.blocks: # check whether there is a proper space for the swimlane
if block.shape == "a":
if block.bbox[3] < y:
self.bbox[1] = max(self.bbox[1],block.bbox[3])
elif block.bbox[1] > y:
self.bbox[3] = min(self.bbox[3],block.bbox[1])
else:
self.not_valid = 1 # Clickpoint is inside of an existing swimlane
return()
self.fit_content("a")
else:
self.fit_content("x")
#************************************************************************
def sync_variables_to_text (self,varslist,varsorder):
blockvars = {}
maxv = 0
for v in varslist: # check all variables of the block object
if re.search(r"^(BLOCK|pars|JUMP|_FKT_)$",v):
continue
varskey = v
for v1 in varsorder: # special ordering
if v.find(v1) == 0:
varskey = "AAAAAAAA" + v
break
blockvars[varskey] = v
maxv = max(maxv,len(v)) # align '=' at left
blockvarskeys = list(blockvars.keys())
blockvarskeys.sort()
self.text = ""
for vkey in blockvarskeys:
v = blockvars[vkey]
self.text = self.text + "$" + (v+" "*maxv)[0:maxv] + " = " + str(obj.__dict__[v]) + "\n"
#************************************************************************
def sync_text_to_varslist (self,text=None):
if not text:
text = self.text
varslist = re.sub(r"[\n ]*([a-zA-Z\_][a-zA-Z0-9\_]*)[ =].*?(\n[\n ]*|$)","\\1,",text,99999999,re.DOTALL)
if re.sub(r"(^|,)[a-zA-\_][a-zA-Z0-9\_]*","",varslist,99999999,re.DOTALL) == ",":
return(varslist.split(","))
return(None)
#************************************************************************
# def sync_varslist_to_varsorder (self,varslist):
#
# varsorder = []
# var0 = ""
# for var in varslist: # Makes a sorting order array for the variables in varslist
# if var == "": # where sorting order patterns are as short as possible
# continue
# zaehler = 0
# while (0 == 0):
# zaehler = zaehler + 1
# var1 = var0[:zaehler]
# if not var0.find(var1) == 0:
# varsorder.append(var1)
# var0 = var
# break
# if var1 == var0:
# break
#
# return(varsorder)
#************************************************************************
def sync_content_to_fkt_and_text (self): # synchronize the content of the Text Area with fkt and text
if not 'content' in vars(self):
return(0)
fkt = self.content.get("1.0",tkinter.END)
# fkt = re.sub(r"\n([a-zA-Z])","\n\\1",fkt,re.DOTALL,99999999) # seems to be superfluous
text = ""
m = re.search(r"^(.*?)\n(.*?) *$",fkt,flags=re.DOTALL)
if m:
fkt = m.group(1)
text = m.group(2)
if not re.search(r"^[a-zA-Z][a-zA-Z\_0-9]+$",fkt):
return(-1) # not a valid fkt
if re.search(r"\S",text):
if self.shape == "a":
return(-1) # a swimlane should only carry a fkt, text shall be empty
if not self.sync_text_to_varslist(text): # no valid program code
return(-1)
try: # check also validity as python program code
exec(text)
except:
return(-1)
self.fkt = fkt
self.text = text
return(1)
#************************************************************************
def destroy (self,destroy_arrows=True):
for elem in list(self.elems.values()):
self.graphcanvas.delete(elem)
if 'content' in vars(self):
self.content.place_forget()
del self.content
del self.contentframe
self.graphcanvas.delete(self.window)
del self.window
if destroy_arrows:
for arrow in self.arrows_in:
arrow.source_block.arrows_out.remove(arrow)
arrow.destroy()
for arrow in self.arrows_out:
arrow.target_block.arrows_in.remove(arrow)
arrow.destroy()
#************************************************************************
def scale (self,fac):
for i in (0,1,2,3):
self.bbox[i] = self.bbox[i] * fac
for arrow in self.arrows_out:
arrow.scale(fac)
self.fontsize = self.fontsize * fac
self.fit_content(self.shape)
#************************************************************************
def zoom_text (self,fac):
self.fontsize = self.fontsize * fac
# self.fit_content(self.shape)
#************************************************************************
def fit_content (self,set_shape=None):
'''
Fits all contents of the block so that all is fitted
properly into the shape.
shape not None: includes checking and reformating header and text
Shapes:
r: Normale rectangle block
s: Subprocess (rectangle)
i: Case switch (diamond with X)
f: Forking block (diamond with cross)
m: Multiple switch (diamond with star)
w: Wait Block (diamond with circle)
c: Start Block (circle)
e: End Block (circle)
a: Swim lane
'''
if set_shape:
if set_shape in "rceifmwsa": # explicit definition of block shape
shape = set_shape
else: # implicit definiton of block shape by counting
shape = { "00": "r", # in and out arrows
"01": "c",
"02": "c",
"10": "r", # e
"11": "r",
"12": "ifm",
"20": "r", # e
"21": "ws",
"22": "s" } [ str(min(len(self.arrows_in),2)) + str(min(len(self.arrows_out),2)) ]
if shape == "ifm": # split off paths: shape depends on splitting case constraints
shape = "i"
wertebereiche = []
for arrow in self.arrows_out:
text = self.graphcanvas.itemcget(arrow.text,'text')
m = re.search(r"(\d+?),?(\d*)",text)
if m:
try:
val = [int(m.group(1)),int(m.group(2))]
shape = "f"
except:
val = [int(m.group(1)),int(m.group(1))]
for val1 in wertebereiche:
if val1[1] > val[0] or val[1] > val1[0]:
shape = "m"
break
if shape == "m":
break
wertebereiche.append(val)
if shape == "ws":
shape = "w"
if self.shape in shape:
shape = self.shape
if not shape == self.shape:
self.destroy(destroy_arrows=False)
x = (self.bbox[0]+self.bbox[2])/2
y = (self.bbox[1]+self.bbox[3])/2
self.content_text = self.fkt + "\n" + self.text
if shape in "ars": # Rectangle, normal block
if not shape == self.shape: # Shape has changed
self.elems = { "SHAPE": self.graphcanvas.create_rectangle(0,0,0,0,fill=self.color) }
self.contentframe = tkinter.Frame(self.graphcanvas,background=self.color,bg=self.color,bd=0)
self.content = tkinter.Text(self.contentframe,wrap={"r":"none","s":"none","a":"char"}[shape],
borderwidth=0,insertborderwidth=0,bg=self.color,highlightcolor=self.color)
self.window = self.graphcanvas.create_window(x,y,window=self.contentframe)
self.contentframe.grid_propagate(False)
self.content.insert("0.0",self.fkt + "\n" + self.text)
self.content.config(state=tkinter.DISABLED)
if shape in "s":
self.elems['EXPAND'] = self.graphcanvas.create_rectangle(0,0,0,0,width=1)
if shape in "s":
self.elems['X1'] = self.graphcanvas.create_line(0,0,0,0,fill='black',width=1)
self.elems['X2'] = self.graphcanvas.create_line(0,0,0,0,fill='black',width=1)
if shape in "a":
self.elems['X1'] = self.graphcanvas.create_line(0,0,0,0,fill='black',width=2)
self.elems['X2'] = self.graphcanvas.create_line(0,0,0,0,fill='black',width=2)
#Solution part 2: move the swim lane behind the blocks. Part 1 in the module Gui_file.
self.graphcanvas.tag_lower(self.elems['X1'])
self.graphcanvas.tag_lower(self.elems['X2'])
# self.elems['X3'] = self.graphcanvas.create_line(0,0,0,0,fill='black',width=3)
self.content.config(font=({"r":"Courier","s":"Courier","a":"Courier New Bold"}[shape],int(self.fontsize)))
elif shape in "iwfm": # Diamond
if not shape == self.shape: # Shape has changed
self.elems = { "SHAPE": self.graphcanvas.create_polygon(0,0,0,0,0,0,0,0,fill=self.color,outline='black'),
"HEADER": self.graphcanvas.create_text(0,0,anchor=tkinter.N,text=self.fkt),
"TEXT": self.graphcanvas.create_text(0,0,anchor=tkinter.CENTER,text=self.text)
}
if shape in "im":
self.elems['CROSS1'] = self.graphcanvas.create_line(0,0,0,0,fill='black',width=3)
self.elems['CROSS2'] = self.graphcanvas.create_line(0,0,0,0,fill='black',width=3)
if shape in "fm":
self.elems['X1'] = self.graphcanvas.create_line(0,0,0,0,fill='black',width=3)
self.elems['X2'] = self.graphcanvas.create_line(0,0,0,0,fill='black',width=3)
if shape == "w":
self.elems['CIRCLE'] = self.graphcanvas.create_oval(0,0,0,0,outline='black',width=3)
self.graphcanvas.itemconfig(self.elems['HEADER'],font=('Courier',int(self.fontsize)))
self.graphcanvas.itemconfig(self.elems['TEXT'], font=('Courier',int(self.fontsize)))
elif shape in "ce": # Circle
if not shape == self.shape: # Shape has changed
self.elems = { "SHAPE": self.graphcanvas.create_oval(0,0,0,0,fill=self.color,outline='black') }
self.contentframe = tkinter.Frame(self.graphcanvas,background=self.color,bg=self.color)
self.content = tkinter.Text(self.contentframe,wrap="none",bg=self.color,
highlightcolor=self.color,borderwidth=0,insertborderwidth=0)
self.window = self.graphcanvas.create_window(158,99,window=self.contentframe)
self.contentframe.grid_propagate(False)
self.content.insert("0.0",self.fkt + "\n" + self.text)
self.content.config(state=tkinter.DISABLED)
self.content.config(font=('Courier',int(self.fontsize)))
elif shape in "t": # Triangle
if not shape == self.shape: # Shape has changed
self.elems = { "SHAPE": self.graphcanvas.create_polygon(0,0,0,0,0,0,fill=self.color,outline='black') }
self.content = tkinter.Text(self.graphcanvas,wrap="none",bg=self.color,highlightcolor=self.color,
borderwidth=0,insertborderwidth=0)
self.content.insert("0.0",self.fkt + "\n" + self.text)
self.content.config(state=tkinter.DISABLED)
self.content.config(font=('Courier',int(self.fontsize)))
if not shape == self.shape: # Shape has changed
self.shape = shape
if 'content' in vars(self):
self.content.bind("<ButtonPress-1>", lambda event: self.press_button(event))
self.content.bind("<ButtonRelease-1>", self.release_button_event)
self.content.bind("<B1-Motion>", self.move_mouse_event)
self.content.bind("<Double-Button-1>", self.double_click_button_event)
for elem in list(self.elems.values()):
self.graphcanvas.tag_bind(elem,"<ButtonPress-1>", lambda event: self.press_button_event(event))
self.graphcanvas.tag_bind(elem,"<ButtonRelease-1>", self.release_button_event)
self.graphcanvas.tag_bind(elem,"<B1-Motion>", self.move_mouse_event)
self.graphcanvas.tag_bind(elem,"<Double-Button-1>", self.double_click_button_event)
x = (self.bbox[0]+self.bbox[2])/2
y = (self.bbox[1]+self.bbox[3])/2
w = self.bbox[2] - self.bbox[0]
h = self.bbox[3] - self.bbox[1]
if self.shape in "iwfmce": # reduce the bounding box to a square
if w > h: # because diamond shapes shall be always rectangular,
self.bbox[0] = x - h/2 # and circles should be circles, not ovals
self.bbox[2] = x + h/2
w = h
else:
self.bbox[1] = y - w/2
self.bbox[3] = y + w/2
h = w
if self.shape in "ars":
self.graphcanvas.coords(self.elems['SHAPE'], self.bbox[0],self.bbox[1],self.bbox[2],self.bbox[3])
self.contentframe.config(width=int(0.9*w),height=int(0.9*h))
self.content.place(x=0,y=0,width=int(0.9*w),height=int(0.9*h))
(x1,y1) = self.graphcanvas.coords(self.window)
self.graphcanvas.move(self.window,x-x1,y-y1)
if self.shape == "s":
self.graphcanvas.coords(self.elems['EXPAND'], x-0.09*w,y+0.32*h,x+0.09*w,y+0.5*h)
self.graphcanvas.coords(self.elems['X1'], x-0.09*w,y+0.32*h,x+0.09*w,y+0.32*h)
self.graphcanvas.coords(self.elems['X2'], x,y+0.4*h,x,y+0.5*h)
if self.shape == "a":
self.graphcanvas.coords(self.elems['X1'], x-0.5*w,y-0.5*h,99999999,y-0.5*h)
#self.graphcanvas.coords(self.elems['X2'], x-0.5*w,y+0.5*h,99999999,y+0.5*h)
self.graphcanvas.coords(self.elems['X2'], x-0.5*w,y+0.5*h,99,y+0.5*h)
# self.graphcanvas.coords(self.elems['X3'], x-0.5*w,y-0.5*h,x-0.5*w,y+0.5*h)
elif self.shape in "iwfm":
self.graphcanvas.coords(self.elems['SHAPE'], self.bbox[0],y,x,self.bbox[1],self.bbox[2],y,x,self.bbox[3])
self.graphcanvas.coords(self.elems['HEADER'],x,self.bbox[1])
self.graphcanvas.coords(self.elems['TEXT'], x,y)
if self.shape in "im":
self.graphcanvas.coords(self.elems['CROSS1'], x-0.17*w,y-0.17*h,x+0.17*w,y+0.17*h)
self.graphcanvas.coords(self.elems['CROSS2'], x+0.17*w,y-0.17*h,x-0.17*w,y+0.17*h)
if self.shape in "fm":
self.graphcanvas.coords(self.elems['X1'], x-0.17*w,y,x+0.17*w,y)
self.graphcanvas.coords(self.elems['X2'], x,y-0.17*h,x,y+0.17*h)
if self.shape == "w":
self.graphcanvas.coords(self.elems['CIRCLE'], x-0.19*w,y-0.19*h,x+0.19*w,y+0.19*h)
elif self.shape in "ce":
self.graphcanvas.coords(self.elems['SHAPE'], self.bbox[0],self.bbox[1],self.bbox[2],self.bbox[3])
self.contentframe.config(width=int(0.7*w),height=int(0.7*h))
self.content.place(x=0,y=0,width=int(0.7*w),height=int(0.7*h))
(x1,y1) = self.graphcanvas.coords(self.window)
self.graphcanvas.move(self.window,x-x1,y-y1)
elif self.shape in "t":
self.graphcanvas.coords(self.elems['SHAPE'], self.bbox[0],self.bbox[3],x,self.bbox[1],self.bbox[2],self.bbox[3])
self.content.place(x=int(x-0.28*w),y=int(y-0.28*h),width=int(0.56*w),height=int(0.56*h))
for arrow in self.arrows_in + self.arrows_out:
arrow.fit_block_connections()
arrow.fit_description()
if set_shape:
if set_shape in "rceifmwsa": # explicit definition of block shape
shape = set_shape
else: # implicit definiton of block shape by counting
shape = { "00": "r", # in and out arrows
"01": "c",
"02": "c",
"10": "r", # e
"11": "r",
"12": "ifm",
"20": "r", # e
"21": "ws",
"22": "s" } [ str(min(len(self.arrows_in),2)) + str(min(len(self.arrows_out),2)) ]
if shape == "ifm": # split off paths: shape depends on splitting case constraints
shape = "i"
wertebereiche = []
for arrow in self.arrows_out:
text = self.graphcanvas.itemcget(arrow.text,'text')
m = re.search(r"(\d+?),?(\d*)",text)
if m:
try:
val = [int(m.group(1)),int(m.group(2))]
shape = "f"
except:
val = [int(m.group(1)),int(m.group(1))]
for val1 in wertebereiche:
if val1[1] > val[0] or val[1] > val1[0]:
shape = "m"
break
if shape == "m":
break
wertebereiche.append(val)
if shape == "ws":
shape = "w"
if self.shape in shape:
shape = self.shape
if not shape == self.shape:
self.destroy(destroy_arrows=False)
x = (self.bbox[0]+self.bbox[2])/2
y = (self.bbox[1]+self.bbox[3])/2
self.content_text = self.fkt + "\n" + self.text
if shape in "ars": # Rectangle, normal block
if not shape == self.shape: # Shape has changed
self.elems = { "SHAPE": self.graphcanvas.create_rectangle(0,0,0,0,fill=self.color) }
self.contentframe = tkinter.Frame(self.graphcanvas,background=self.color,bg=self.color)
self.content = tkinter.Text(self.contentframe,wrap={"r":"none","s":"none","a":"char"}[shape],
bg=self.color,highlightcolor=self.color,borderwidth=0,insertborderwidth=0)
self.window = self.graphcanvas.create_window(x,y,window=self.contentframe)
self.contentframe.grid_propagate(False)
self.content.insert("0.0",self.fkt + "\n" + self.text)
self.content.config(state=tkinter.DISABLED)
if shape in "s":
self.elems['EXPAND'] = self.graphcanvas.create_rectangle(0,0,0,0,width=1)
if shape in "s":
self.elems['X1'] = self.graphcanvas.create_line(0,0,0,0,fill='black',width=1)
self.elems['X2'] = self.graphcanvas.create_line(0,0,0,0,fill='black',width=1)
if shape in "a":
self.elems['X1'] = self.graphcanvas.create_line(0,0,0,0,fill='black',width=2)
self.elems['X2'] = self.graphcanvas.create_line(0,0,0,0,fill='black',width=2)
#Solution part 2: move the swim lane behind the blocks. Part 1 in the module Gui_file.
self.graphcanvas.tag_lower(self.slems['X1'])
self.graphcanvas.tag_lower(self.slems['X2'])
# self.elems['X3'] = self.graphcanvas.create_line(0,0,0,0,fill='black',width=3)
self.content.config(font=({"r":"Courier","s":"Courier","a":"Courier New Bold"}[shape],int(self.fontsize)))
elif shape in "iwfm": # Diamond
if not shape == self.shape: # Shape has changed
self.elems = { "SHAPE": self.graphcanvas.create_polygon(0,0,0,0,0,0,0,0,fill=self.color,outline='black'),
"HEADER": self.graphcanvas.create_text(0,0,anchor=tkinter.N,text=self.fkt),
"TEXT": self.graphcanvas.create_text(0,0,anchor=tkinter.CENTER,text=self.text)
}
if shape in "im":
self.elems['CROSS1'] = self.graphcanvas.create_line(0,0,0,0,fill='black',width=3)
self.elems['CROSS2'] = self.graphcanvas.create_line(0,0,0,0,fill='black',width=3)
if shape in "fm":
self.elems['X1'] = self.graphcanvas.create_line(0,0,0,0,fill='black',width=3)
self.elems['X2'] = self.graphcanvas.create_line(0,0,0,0,fill='black',width=3)
if shape == "w":
self.elems['CIRCLE'] = self.graphcanvas.create_oval(0,0,0,0,outline='black',width=3)
self.graphcanvas.itemconfig(self.elems['HEADER'],font=('Courier',int(self.fontsize)))
self.graphcanvas.itemconfig(self.elems['TEXT'], font=('Courier',int(self.fontsize)))
elif shape in "ce": # Circle
if not shape == self.shape: # Shape has changed
self.elems = { "SHAPE": self.graphcanvas.create_oval(0,0,0,0,fill=self.color,outline='black') }
self.contentframe = tkinter.Frame(self.graphcanvas,background=self.color,bg=self.color)
self.content = tkinter.Text(self.contentframe,wrap="none",bg=self.color,
highlightcolor=self.color,borderwidth=0,insertborderwidth=0)
self.window = self.graphcanvas.create_window(158,99,window=self.contentframe)
self.contentframe.grid_propagate(False)
self.content.insert("0.0",self.fkt + "\n" + self.text)
self.content.config(state=tkinter.DISABLED)
self.content.config(font=('Courier',int(self.fontsize)))
elif shape in "t": # Triangle
if not shape == self.shape: # Shape has changed
self.elems = { "SHAPE": self.graphcanvas.create_polygon(0,0,0,0,0,0,fill=self.color,outline='black') }
self.content = tkinter.Text(self.graphcanvas,wrap="none",bg=self.color,highlightcolor=self.color,
borderwidth=0,insertborderwidth=0)
self.content.insert("0.0",self.fkt + "\n" + self.text)
self.content.config(state=tkinter.DISABLED)
self.content.config(font=('Courier',int(self.fontsize)))
if not shape == self.shape: # Shape has changed
self.shape = shape
if 'content' in vars(self):
self.content.bind("<ButtonPress-1>", lambda event: self.press_button(event))
self.content.bind("<ButtonRelease-1>", self.release_button)
self.content.bind("<B1-Motion>", self.move_mouse)
self.content.bind("<Double-Button-1>", self.double_click_button)
for elem in list(self.elems.values()):
self.graphcanvas.tag_bind(elem,"<ButtonPress-1>", lambda event: self.press_button(event))
self.graphcanvas.tag_bind(elem,"<ButtonRelease-1>", self.release_button)
self.graphcanvas.tag_bind(elem,"<B1-Motion>", self.move_mouse)
self.graphcanvas.tag_bind(elem,"<Double-Button-1>", self.double_click_button)
x = (self.bbox[0]+self.bbox[2])/2
y = (self.bbox[1]+self.bbox[3])/2
w = self.bbox[2] - self.bbox[0]
h = self.bbox[3] - self.bbox[1]
if self.shape in "iwfmce": # reduce the bounding box to a square
if w > h: # because diamond shapes shall be always rectangular,
self.bbox[0] = x - h/2 # and circles should be circles, not ovals
self.bbox[2] = x + h/2
w = h
else:
self.bbox[1] = y - w/2
self.bbox[3] = y + w/2
h = w
if self.shape in "ars":
self.graphcanvas.coords(self.elems['SHAPE'], self.bbox[0],self.bbox[1],self.bbox[2],self.bbox[3])
self.contentframe.config(width=int(0.9*w),height=int(0.9*h))
self.content.place(x=0,y=0,width=int(0.9*w),height=int(0.9*h))
(x1,y1) = self.graphcanvas.coords(self.window)
self.graphcanvas.move(self.window,x-x1,y-y1)
if self.shape == "s":
self.graphcanvas.coords(self.elems['EXPAND'], x-0.09*w,y+0.32*h,x+0.09*w,y+0.5*h)
self.graphcanvas.coords(self.elems['X1'], x-0.09*w,y+0.32*h,x+0.09*w,y+0.32*h)
self.graphcanvas.coords(self.elems['X2'], x,y+0.4*h,x,y+0.5*h)
if self.shape == "a":
self.graphcanvas.coords(self.elems['X1'], x-0.5*w,y-0.5*h,99999999,y-0.5*h)
self.graphcanvas.coords(self.elems['X2'], x-0.5*w,y+0.5*h,99999999,y+0.5*h)
# self.graphcanvas.coords(self.elems['X3'], x-0.5*w,y-0.5*h,x-0.5*w,y+0.5*h)
elif self.shape in "iwfm":
self.graphcanvas.coords(self.elems['SHAPE'], self.bbox[0],y,x,self.bbox[1],self.bbox[2],y,x,self.bbox[3])
self.graphcanvas.coords(self.elems['HEADER'],x,self.bbox[1])
self.graphcanvas.coords(self.elems['TEXT'], x,y)
if self.shape in "im":
self.graphcanvas.coords(self.elems['CROSS1'], x-0.17*w,y-0.17*h,x+0.17*w,y+0.17*h)
self.graphcanvas.coords(self.elems['CROSS2'], x+0.17*w,y-0.17*h,x-0.17*w,y+0.17*h)
if self.shape in "fm":
self.graphcanvas.coords(self.elems['X1'], x-0.17*w,y,x+0.17*w,y)
self.graphcanvas.coords(self.elems['X2'], x,y-0.17*h,x,y+0.17*h)
if self.shape == "w":
self.graphcanvas.coords(self.elems['CIRCLE'], x-0.19*w,y-0.19*h,x+0.19*w,y+0.19*h)
elif self.shape in "ce":
self.graphcanvas.coords(self.elems['SHAPE'], self.bbox[0],self.bbox[1],self.bbox[2],self.bbox[3])
self.contentframe.config(width=int(0.7*w),height=int(0.7*h))
self.content.place(x=0,y=0,width=int(0.7*w),height=int(0.7*h))
(x1,y1) = self.graphcanvas.coords(self.window)
self.graphcanvas.move(self.window,x-x1,y-y1)
elif self.shape in "t":
self.graphcanvas.coords(self.elems['SHAPE'], self.bbox[0],self.bbox[3],x,self.bbox[1],self.bbox[2],self.bbox[3])
self.content.place(x=int(x-0.28*w),y=int(y-0.28*h),width=int(0.56*w),height=int(0.56*h))
for arrow in self.arrows_in + self.arrows_out:
arrow.fit_block_connections()
arrow.fit_description()
#************************************************************************
def sync_content_to_text_and_header (self):
if 'content' in vars(self):
header = self.content.get("1.0",tkinter.END)
text = ""
m = re.search(r"^(.*?)\n(.*)$",header,re.DOTALL)
if m:
header = m.group(1)
text = m.group(2)
if not re.search(r"^[a-z][a-zA-Z\_0-9]+$",header):
return(-1) # not a valid header
try:
exec(text)
except:
return(-1) # no valid program code
self.header = header
self.text = text
return(1) # self.content successful synced
return(0) # no self.content variable
#************************************************************************
def get_shape_connection_point (self,p1):
'''
Computes the point on the the border of the surrounding shape of the block
which connects an outer point p to the block
'''
p = [ min(max(self.bbox[0], p1[0]), self.bbox[2]), min(max(self.bbox[1], p1[1]), self.bbox[3]) ]
# p2: touches the bounding box. This basic point has to be extended into the bounding box depending on the shape:
if not self.shape in "rs":
x = (self.bbox[0]+self.bbox[2])/2
y = (self.bbox[1]+self.bbox[3])/2
p2 = p[:]
if p2[0] == p1[0]:
p2[1] = y
if p2[1] == p1[1]:
p2[0] = x
if self.shape in "iwfm": # diamond
fac = 1
if p1[0] < x:
p3 = [self.bbox[0],y]
else:
p3 = [self.bbox[2],y]
fac = -fac
if p1[1] < y:
p4 = [x,self.bbox[1]]
else:
p4 = [x,self.bbox[3]]
fac = -fac
try:
m = ( p4[0] - p2[0] + fac * (p4[1] - p2[1]) ) / ( p1[0] - p2[0] + fac * (p1[1] - p2[1]) )
p = [ p1[0] * m + p2[0] * (1-m), p1[1] * m + p2[1] * (1-m) ]
except: # in this case, the outer point points to the closest edge
pass
elif self.shape in "ce": # circle
a = (p1[0]-p2[0])**2 + (p1[1]-p2[1])**2 # a * m*m - 2 * b * m + c = 0, quadratic equation to solve
b = (p1[0]-p2[0])*(x-p2[0]) + (p1[1]-p2[1])*(y-p2[1])
c = (x-p2[0])**2 + (y-p2[1])**2 - ((self.bbox[0]-self.bbox[2])/2)**2
try:
m = ( b + (b**2 - a*c)**0.5 ) / a
p = [ p1[0] * m + p2[0] * (1-m), p1[1] * m + p2[1] * (1-m) ]
except: # in this case, the outer point points to the most west, east, north or south point of the circle
pass
elif self.shape in "t": # triangle
if p1[1] > self.bbox[3]: # point is underneath the bottom of the triangle.
pass # Nothing to do -> the same behaviour as in rectangle shape mode
else:
p3 = [x,self.bbox[1]]
if p1[0] < x:
p4 = [self.bbox[0],self.bbox[3]]
else:
p4 = [self.bbox[2],self.bbox[3]]
a = (p2[0]-p4[0])*(p3[1]-p4[1]) - (p2[1]-p4[1])*(p3[0]-p4[0])
b = (p2[0]-p1[0])*(p3[1]-p4[1]) - (p2[1]-p1[1])*(p3[0]-p4[0])
try:
m = a / b
p = [ p1[0] * m + p2[0] * (1-m), p1[1] * m + p2[1] * (1-m) ]
except: # in this case, the outer point points to the closest edge
pass
return(p)
#************************************************************************
def xxget_varlen (self):
'''
Gives the maximal length of variable names.
Given as a value lower than 0 if no arrows exist where
the block is target. E.g. if the block is the starting node.
'''
maxv = 5
for textline in self.graphcanvas.itemcget(self.text,'text').split("\n"):
m = re.search(r"^(.*?)[ \=]",textline)
if m:
maxv = max(maxv,len(m.group(1)))
if not self.arrows_out:
maxv = -maxv
return(maxv)
#************************************************************************
def get_vars (self):
'''
Gives the variables with their actual values.
'''
block = [ self.graphcanvas.itemcget(self.fkt,'text') ] #hier stand: self.header collecting block informations
m = re.search(r"^ *(.*?)( *\/ *)(.*?) *$",block[0])
if m:
block = [ m.group(1), m.group(3) ]
coords = self.bbox
block.append( "%3.1f" % ((coords[0]+coords[2])/2) )
block.append( "%3.1f" % ((coords[1]+coords[3])/2) )
block.append( "%3.1f" % (coords[2]-coords[0]) )
block.append( "%3.1f" % (coords[3]-coords[1]) )
varsval = [ ['BLOCK',block] ]
varsval1 = {} # collecting other visible variables
for textline in self.graphcanvas.itemcget(self.text,'text').split("\n"):
m = re.search(r"^(.*?)( *\= *)(.*?) *$",textline)
if m:
varsval1[m.group(1)] = m.group(3)
varsval1_keys = list(varsval1.keys())
varsval1_keys.sort()
for item in varsval1_keys:
varsval.append([item,varsval1[item]])
jump = {} # collecting infos where to jump:
for arrow in self.arrows_out:
jumpinfo = [ self.graphcanvas.itemcget(arrow.text,'text') ]
for arrowline in arrow.arrowlines[1:]:
for c in self.graphcanvas.coords(arrowline)[:2]:
jumpinfo.append("%3.1f" % c)
jump[arrow.target_block] = jumpinfo
varsval.append( ['JUMP',jump] )
return(varsval)
#************************************************************************
def bounding_box (self,extbox=None):
'''
Returns the bounding box of the block.
If an optional 4-elem array is given, this
will be extended to the bounding box.
'''
if extbox == None:
extbox = []
if len(extbox) == 0:
extbox.append(self.bbox[0])
extbox.append(self.bbox[1])
extbox.append(self.bbox[2])
extbox.append(self.bbox[3])
else:
extbox[0] = min(extbox[0],self.bbox[0])
extbox[1] = min(extbox[1],self.bbox[1])
extbox[2] = max(extbox[2],self.bbox[2])
extbox[3] = max(extbox[3],self.bbox[3])
return(extbox)
#************************************************************************
def press_button (self,event=[]):
if type(event) == type([]): # Testschnittstelle
try:
self.x0 = event[0]
except:
self.x0 = self.bbox[0] + self.bbox[2]/2
try:
self.y0 = event[1]
except:
self.y0 = self.bbox[1] + self.bbox[3]/2
(self.x1,self.y1) = (self.x0,self.y0)
else:
(self.x0,self.y0) = (event.x,event.y)
(self.x1,self.y1) = (event.x_root,event.y_root)
self.graphcanvas.configure(cursor='sizing') # Alternative mouse pointers: arrow circle
# clock cross dotbox exchange fleur heart
self.resize_box = "" # man mouse pirate plus shuttle sizing spider
self.move_blocks = [] # spraycan star target tcross trek watch
self.move_arrows = {}
self.move_arrowlines_start = {}
self.move_arrowlines_end = {}
self.bbox_press = self.bbox[:]
self.w = self.bbox[2] - self.bbox[0]
self.h = self.bbox[3] - self.bbox[1]
if self.shape in "ars":
if abs(self.y0 - self.bbox[3]) < 4: # if pressing point is near the border of the box
self.resize_box = self.resize_box + "S" # mark the direction for resizing
if abs(self.y0 - self.bbox[1]) < 4:
self.resize_box = self.resize_box + "N"
if self.shape in "rs":
if abs(self.x0 - self.bbox[0]) < 4:
self.resize_box = self.resize_box + "W"
if abs(self.x0 - self.bbox[2]) < 4:
self.resize_box = self.resize_box + "E"
if self.resize_box == "" and self.shape == "a": # Shifting a swimlane means also shifting all blocks in its area
(self.move_blocks,self.move_arrows,self.move_singlepoints) = self.blocks_and_arrows_in_swimlane()
for block in self.frame.blocks:
if not self == block and block.shape == "a":
(block.move_blocks,block.move_arrows,block.move_singlepoints) = block.blocks_and_arrows_in_swimlane()
self.last_event = 1
return "break"
#**********************************************************
def blocks_and_arrows_in_swimlane (self,mode=0): # Returns the blocks which are in the swimlane if i am swimlane
erg = []
for block in self.frame.blocks:
if self.bbox[1] <= block.bbox[1] <= self.bbox[3]:
if not block.shape == "a":
erg.append(block)
arrows = []
for block in erg:
for arrow in block.arrows_in:
if arrow.source_block in erg:
arrows.append(arrow)
if mode > 0:
return(arrows)
exclude_arrows = self.arrows_covered_by_some_swimlane()
singlepoints = []
for block in self.frame.blocks:
for arrow in block.arrows_in:
if not arrow in exclude_arrows:
zaehler = 0
for arrowline in arrow.arrowlines:
coords = self.graphcanvas.coords(arrowline)
for i in (0,2):
if self.bbox[1] <= coords[i+1] <= self.bbox[3]:
singlepoints.append([arrow,zaehler,i])
zaehler = zaehler + 1
return(erg,arrows,singlepoints)
#**********************************************************
def arrows_covered_by_some_swimlane (self):
erg = []
for swimlane in self.frame.blocks:
if swimlane.shape == "a":
erg = erg + swimlane.blocks_and_arrows_in_swimlane(1)
pass
return(erg)
#**********************************************************
def blocks_in_swimlane (self,mode=0): # Returns the blocks which are in the swimlane if self is a swimlane
if not self.shape == "a":
return([])
erg = { 'BLOCKS': [], # Blocks in the swimlane
'ARROWLINES_BEGIN': {}, # Starting arrow lines in the swimlane
'ARROWLINES_END' : {}, # Ending arrow lines in the swimlane
'ARROWS' : {} } # Arrows from one block in the swimlane to another
sub_swimlanes = []
for block in self.frame.blocks:
if self.bbox[1] <= block.bbox[1] <= self.bbox[3]:
if self.bbox[0] <= block.bbox[0]:
if not block.shape == "a":
# print("a = ",block)
erg['BLOCKS'].append(block)
elif not block == self and ( not self.bbox[0] == block.bbox[0] or
self.bbox[1] < block.bbox[1] or
( self.bbox[1] == block.bbox[1] and self.bbox[3] < block.bbox[3] ) ):
sub_swimlanes.append(block)
#print("Blocks in swimlane: ",erg['BLOCKS'])
for block in erg['BLOCKS']:
for arrow in block.arrows_in + block.arrows_out:
erg['ARROWS'][arrow] = 1
for arrowline in arrow.arrowlines:
coords = self.graphcanvas.coords(arrowline)
bed1 = arrow in block.arrows_in and arrow.source_block in self.move_blocks
bed2 = arrow in block.arrows_out and arrow.target_block in self.move_blocks
if bed1 or bed2 or self.bbox[1] < coords[1] and coords[1] < self.bbox[3]:
erg['ARROWLINES_BEGIN'][arrowline] = 1
if bed1 or bed2 or self.bbox[1] < coords[3] and coords[3] < self.bbox[3]:
erg['ARROWLINES_END'][arrowline] = 1
for arrow in block.arrows_out:
erg['ARROWLINES_BEGIN'][arrow.arrowlines[0]] = 1
for arrow in block.arrows_in:
erg['ARROWLINES_END'][arrow.arrowlines[-1]] = 1
return(erg)
self.last_event = 1
#**********************************************************
def xxdouble_click_button (self,event):
(self.x0,self.y0) = (event.x,event.y)
(self.x1,self.y1) = (event.x_root,event.y_root)
self.last_event = 2
return "break"
#****************************************************
def release_button (self,event=None):
if (abs(self.bbox[0] - self.bbox_press[0]) + abs(self.bbox[1] - self.bbox_press[1]) +
abs(self.bbox[2] - self.bbox_press[2]) + abs(self.bbox[3] - self.bbox_press[3]) > 10):
return()
if self.shape == "a" and self.last_event == 3: #before: in (3,4): old version creates error with changing size of the swimlane
self.frame.rearr_swimlane(0.2)
if self.last_event in (1,3):
self.resize_box = ""
self.graphcanvas.configure(cursor='arrow')
if self.frame.hl_block == self:
self.syntax_error = 0
if not self.frame.hl_block == None:
if self.frame.hl_block.sync_content_to_fkt_and_text() == -1:
if not self.frame.hl_block == self:
self.frame.hl_block.syntax_error = 1
return()
self.frame.hl_block.syntax_error = 0
bed = None
if not self.frame.hl_block == self: # if I am not yet highlighted, un-highlight the former highlighted block
self.frame.hl_block_0 = self.frame.hl_block # and set it to the last highlighted block,
self.frame.hl_block = self # and set myself to highlighted
self.hl_arrow = None
for arrow in self.arrows_in: # now check all incoming arrows. The one where its
if arrow.source_block == self.frame.hl_block_0: # source_block is the last highlighted block,
self.hl_arrow = arrow # has also to be highlighted
if False and self.hl_arrow == None: ## DISABLED # check also inverted direction
for arrow in self.arrows_out:
if arrow.target_block == self.frame.hl_block_0:
self.hl_arrow = arrow
self.highlight_myself(0)
else:
self.syntax_error = 0
elif self.last_event == 2: # last event was a double click
self.frame.create_arrow()
# elif self.frame.griddata['SNAP']:
# self.frame.rearr_grid(0.2)
# else:
# self.frame.rearr_grid(0.2,1)
self.last_event = 1
return "break"
#****************************************************
def highlight_block (self,nr,mode=0): # mode == 1: blinking
fillcolor1 = [procpy.config.COLOR_HIGHLIGHT_ALT[0],procpy.config.COLOR_HIGHLIGHT_ALT[0],
procpy.config.COLOR_HIGHLIGHT[0],procpy.config.COLOR_HIGHLIGHT[0]
][nr+mode]
self.graphcanvas.itemconfig(self.elems['SHAPE'],fill=fillcolor1)
if 'content' in vars(self):
self.content.config(bg=fillcolor1,highlightcolor=fillcolor1)
self.contentframe.config(background=fillcolor1,bg=fillcolor1,highlightcolor=fillcolor1)
if self.hl_arrow:
fillcolor2 = [procpy.config.COLOR_HIGHLIGHT[0],self.color,self.color,self.color][nr+mode]
if len(self.frame.blocks) < 6:
# fillcolor2 = fillcolor1
fillcolor2 = procpy.config.COLOR_HIGHLIGHT[0]
self.hl_arrow.highlight(fillcolor2)
else:
if 'content' in vars(self):
if self.content.cget('state') == tkinter.DISABLED:
self.content.config(state=tkinter.NORMAL)
self.content.focus_set()
self.content.mark_set("insert",tkinter.END)
if self.sync_content_to_fkt_and_text() == -1:
self.syntax_error = 1
else:
self.syntax_error = 0
delay = -nr
if self.frame.hl_block == self:
delay = 180 + mode*120
if delay > -1:
self.frame.loopobj.after(delay,self.highlight_myself,1-nr,2*self.syntax_error)
else:
self.graphcanvas.itemconfig(self.elems['SHAPE'],fill=self.color)
if 'content' in vars(self):
self.content.config(bg=self.color,highlightcolor=self.color)
self.contentframe.config(background=self.color,bg=self.color,highlightcolor=self.color)
if self.hl_arrow:
self.hl_arrow.highlight()
self.hl_arrow = None
if 'content' in vars(self):
self.content.config(state=tkinter.DISABLED)
#************************************************************************
def move_mouse (self,event):
dx = event.x_root - self.x1
dy = event.y_root - self.y1
self.last_event = 3
if self.resize_box == "":
self.move(dx,dy)
else:
self.resize(dx,dy)
self.x1 = event.x_root
self.y1 = event.y_root
return "break"
#****************************************************
def move (self,dx,dy,swimlane_sub_move=None):
if ( self.bbox[0]+dx < 0 or False and self.bbox[2]+dx > self.graphcanvas.winfo_width() or
self.bbox[1]+dy < 0 or False and self.bbox[3]+dy > self.graphcanvas.winfo_height() ) :
return() # keine gute Loesung, um zu verhindern, dass die Objekte aus dem Zeichenbereich
# gehen. Insbesondere die rechte und untere Grenze wird mit dem obigen Code
# beim Scalen zu stark geschuetzt. Hier muss eine bessere Loesung her. Am besten
# waere es, den Mauszeiger auf das Gebiet des graphcanvas zu beschraenken, das scheint
# aber schwierig zu sein. --> task_001
if self.shape == "a":
bed = False
sublane = None # the sub swimlane also to have been moved (when a block or ancesters block is highlighted)
for swimlane in self.frame.blocks:
if swimlane == self or not swimlane.shape == "a":
continue
if (swimlane.bbox[1] < self.bbox[1] < swimlane.bbox[3] or swimlane.bbox[1] < self.bbox[3] < swimlane.bbox[3]
or self.bbox[1] < swimlane.bbox[1] < self.bbox[3] or self.bbox[1] < swimlane.bbox[3] < self.bbox[3]):
if swimlane_sub_move or self == self.frame.hl_block:
if (swimlane.bbox[1] - self.bbox[1]) * dy > 0:
if swimlane_sub_move or self == self.frame.hl_block:
sublane = swimlane
bed = True
break
else:
bed = True # block intersection
break
if bed:
if sublane:
sublane.move(dx,dy,1)
elif self.bbox[0] == 0:
self.bbox[0] = self.bbox[0] + self.frame.current_zoom_factor * procpy.config.SWIMLANE_WIDTH
self.bbox[2] = self.bbox[2] + self.frame.current_zoom_factor * procpy.config.SWIMLANE_WIDTH
else:
if not self.bbox[0] == 0:
self.bbox[0] = self.bbox[0] - self.frame.current_zoom_factor * procpy.config.SWIMLANE_WIDTH
self.bbox[2] = self.bbox[2] - self.frame.current_zoom_factor * procpy.config.SWIMLANE_WIDTH
self.bbox[1] = self.bbox[1] + dy
self.bbox[3] = self.bbox[3] + dy
if not self.shape == "a":
self.bbox[0] = self.bbox[0] + dx
self.bbox[2] = self.bbox[2] + dx
else:
for block in self.move_blocks:
block.move(0,dy)
for arrow in self.move_arrows:
arrow.move(0,dy)
for point in self.move_singlepoints:
arrow = point[0]
arrowline = arrow.arrowlines[point[1]]
coords = self.graphcanvas.coords(arrowline)
coords[point[2]] = coords[point[2]] + 0
coords[point[2]+1] = coords[point[2]+1] + dy
self.graphcanvas.coords(arrowline,tuple(coords))
arrow.fit_description()
self.fit_content()
#**********************************************************
def resize (self,dx,dy):
if re.search(r"N",self.resize_box):
self.bbox[1] = self.bbox[1] + dy
elif re.search(r"S",self.resize_box):
self.bbox[3] = self.bbox[3] + dy
if re.search(r"W",self.resize_box):
self.bbox[0] = self.bbox[0] + dx
elif re.search(r"E",self.resize_box):
self.bbox[2] = self.bbox[2] + dx
self.fit_content(self.shape)
for arrow in self.arrows_in + self.arrows_out:
arrow.fit_block_connections()
arrow.fit_description()
def __repr__(self):
return repr(self.arrows_in)+'-->['+repr(self.bbox)+']'+'--> '+repr(self.arrows_out)+'['+repr(self.elems)+']'
#****************************************************