
| 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/graphmodel.py |
# coding: utf8
import os,re,sys,time,math,random,tkinter,codecs,procpy
import procpy.block
import procpy.swimlane
import procpy.arrow
import procpy.rearr_grid
import pdb
import procpy.procobj
try:
import tkinter.ttk,Pmw,xmltodict,json,svgwrite # ,tkintertable
except:
import pip
pip.main(["install","pyttk"])
pip.main(["install","Pmw"])
# pip.main(["install","tkintertable"])
pip.main(["install","xmltodict"])
pip.main(["install","json"])
pip.main(["install","svgwrite"])
import tkinter.ttk,Pmw,xmltodict,json,svgwrite # ,tkintertable
import tkinter.filedialog
import tkinter.font
#**************************************************************************
class Graphmodel (tkinter.Canvas):
def __init__ (self,graphproc,*pars,**args):
'''
The class procpy.graphmodel.Graphmodel provides a Tkinter.Canvas which contains
blocks and arrows. A special kind of blocks are swimlanes.
Blocks can be highlighted.
'''
tkinter.Canvas.__init__(self,*pars,**args)
self.config(background="white")
self.bind("<Button-1>", self.unhighlight_block)
self.bind("<ButtonRelease-1>", self.release_button_event)
self.bind("<B1-Motion>", self.move_mouse_event)
self.blocks = []
self.swimlanes = []
self.blockwidth = args.setdefault('blockwidth', 70)
self.blockheight = args.setdefault('blockheight', 40)
self.swimlane_width = args.setdefault('swimlane_width', 15)
self.zoom_factor = 1
self.hl_block = [None,None,None] # the high-lighted block, with history, contains None's or block objects
self.graphproc = graphproc # The calling widget, typically a Tkinter.Frame
self.config(scrollregion = (0,0,3000,1000))
self.hidden = 0
self.last_pressed = -100 # for computing doubleclicks
self.wait_for_doubleclick_in_milliseconds = int(1000*procpy.config.WAIT_FOR_DOUBLECLICK)
self.set_background_image(procpy.config.FILENAME)
#************************************************************************************
def mark (self,remark=""):
t = time.perf_counter()
if 't0' in vars(self):
print ( ("%9.2f" % ((t-self.t0)*1000)) + " ms for: " + remark )
self.t0 = t
#************************************************************************************
def hide (self,nr):
nr = nr - self.hidden
self.delete("reportitem")
if not nr == 0:
self.move("all",nr*99999,nr*99999)
self.hidden = (nr+1)/2
#************************************************************************************
def create_block_event (self,event): # the double mouseclick callback event
overlapping_elements = self.find_overlapping(event.x,event.y,event.x,event.y)
if overlapping_elements:
for overlapping_element in overlapping_elements:
if not self.type(overlapping_element) == "image":
return()
x0 = self.canvasx(event.x) - 0.5 * self.blockwidth * self.zoom_factor
x1 = self.canvasx(event.x) + 0.5 * self.blockwidth * self.zoom_factor
y0 = self.canvasy(event.y) - 0.5 * self.blockheight * self.zoom_factor
y1 = self.canvasy(event.y) + 0.5 * self.blockheight * self.zoom_factor
self.create_block(x0,y0,x1,y1)
#************************************************************************************
def create_block (self,x0,y0,x1,y1):
# if not self.new_block_is_possible():
# return()
self.after(self.wait_for_doubleclick_in_milliseconds,self.highlight_block,None) # wait: maybe we had a double-click
if x0 < 0: # if the block creating event is very much at the left side
w = self.swimlane_width * self.zoom_factor
self.swimlanes.append(procpy.swimlane.Swimlane(self,[0,y0,w,y1]))
else:
self.blocks.append(procpy.block.Block(self,[x0,y0,x1,y1]))
self.rearr_grid(procpy.config.MOVESPEED)
#***************************************************************************************
def xxnew_block_is_possible (self):
if not self.blocks: # create the start block
return(True)
if self.hl_block[0]: # there is a highlighted block
if self.hl_block[0].syntax_error() == 1:
return(False)
else:
return(True)
else:
return(False)
#***************************************************************************************
def compute_block_level (self,loop_arrows=set(),block_to_delete=None):
self.mark("start compute block level...")
self.loop_arrows = loop_arrows
zaehler = 1
while (0 == 0): # run repeatingly, reducing looping arrows
self.delete("debug")
touched_blocks = []
for block in self.blocks:
block.nr = 0
block.level = []
if len( set(block.arrows_in) - self.loop_arrows ) == 0:
if not block == block_to_delete:
touched_blocks.append(block)
zaehler = 1
for block in touched_blocks[:]:
if not block.compute_level(touched_blocks,zaehler):
return(False)
zaehler = zaehler + 1
loop_found = False
for block in self.blocks:
if not block.nr == 0: # investigate the blocks which could not be numbered, because
continue # predecessors where not be numbered
# for arrow in block.arrows_out: # check all the arrows going out of the block.
# print ("LOOP",arrow,arrow.target_block.nr)
# if arrow.target_block.nr > 0: # if an arrow is connected to a numbered block,
# self.loop_arrows.add(arrow) # then it has to be treated as an loop-building arrow
# loop_found = True
arrows_loop = set()
arrows_tied = set()
for arrow in ( set(block.arrows_in) - self.loop_arrows): # check whether there are incoming
if arrow.source_block.nr == 0: # arrows coming from numbered blocks
arrows_loop.add(arrow) # AND from unnumbered blocks
else:
arrows_tied.add(arrow)
if len(arrows_loop) > 0 and len(arrows_tied) > 0:
for arrow in arrows_loop:
if arrow.check_loop():
self.loop_arrows.add(arrow)
loop_found = True
if not loop_found:
break
# print (zaehler," <---")
zaehler = zaehler + 1
self.mark("end compute block nr...")
return(True)
#***************************************************************************************
def highlight_block (self,block):
if False and self.hl_block[1] == block and self.hl_block[0] == None: ## DISABLED
print("BLIND CODE EXECUTED: 22222")
# self.hl_block.pop(0)
# self.hl_block.insert(-1,None)
# else: # shift to the right, normal behaviour
self.hl_block.pop(-1)
self.hl_block.insert(0,block)
#************************************************************************************
def unhighlight_block (self,event):
timeclock = time.perf_counter()
if timeclock - self.last_pressed < procpy.config.DOUBLECLICK:
self.create_block_event(event)
self.last_pressed = -100
return()
if not self.find_overlapping(event.x,event.y,event.x,event.y):
self.highlight_block(None)
self.last_pressed = timeclock
#************************************************************************************
def create_arrow (self):
if self.hl_block[0] and self.hl_block[0].syntax_error() == 1:
return()
fkt = None # find out the source (fkt) and target (jump) block
jump = None
for block in self.blocks:
if not fkt and block == self.hl_block[1]:
fkt = block
if not jump and block == self.hl_block[0]:
jump = block
if fkt and jump:
break
if not fkt:
fkt = jump
if jump:
if fkt:
create_the_arrow = True
if fkt == jump: # don t create the arrow if source and target are identical
create_the_arrow = False
for arrow in fkt.arrows_out: # check all the out arrows from fkt whether there
if arrow.target_block == jump: # is already an arrow between fkt and jump. in case
create_the_arrow = False # don t provide any new arrow
break
if create_the_arrow:
jump.hl_arrow = procpy.arrow.Arrow(0,self,fkt,jump)
keep_the_new_arrow = self.compute_block_level()
if keep_the_new_arrow:
jump.fit_shape()
fkt.fit_shape()
self.rearr_grid(procpy.config.MOVESPEED)
for arrow in self.loop_arrows:
arrow.color = procpy.config.LOOPARROWCOLOR
else:
jump.hl_arrow.destroy()
jump.hl_arrow = None
self.compute_block_level()
else:
self.highlight_block(None)
return()
#************************************************************************************
def xxfind_loop_start (self,end_loop):
list1 = end_loop.all_blocks_before()
list2 = end_loop.all_blocks_after()
common = [x for x in list1 if x in list2]
loop_start = [x for x in common if len(x.arrows_out) >= 2]
return loop_start[0]
#************************************************************************************
def assign_elements_to_swimlanes (self):
self.swimlanes.sort(key=lambda swimlane: swimlane.bbox[3]) # order vertically
topline = 0
for swimlane in self.swimlanes:
bottomline = swimlane.bbox[3]
swimlane.move_blocks = []
swimlane.move_arrowpoints = []
for block in self.blocks:
if topline <= block.bbox[1] < bottomline:
swimlane.move_blocks.append(block)
for arrow in block.arrows_in:
zaehler = 0
for arrowline in arrow.arrowlines:
coords = self.coords(arrowline)
for i in (0,2):
if topline <= coords[i+1] < bottomline:
swimlane.move_arrowpoints.append([arrow,zaehler,i])
zaehler = zaehler + 1
topline = bottomline
#************************************************************************************
def run_process (self,notifier=None):
print("PROCESS_START")
self.process_runs = 1
self.prgvars = {}
self.running_blocks = 0
self.notifier = notifier
for block in self.starting_blocks():
if not block in self.swimlanes:
block.token = [ self.new_token() ]
self.running_blocks += 1
self.after(0,block.run)
#************************************************************************************
def end_process (self):
print("PROCESS_END")
self.repeats = self.repeats - 1
if self.notifier:
self.after(0,self.notifier.notify())
if self.repeats > 0:
self.after(0,self.run_process,self.notifier)
else:
del self.process_runs
#************************************************************************************
def move_mouse_event (self,event):
if 'x0' in vars(self):
(dx,dy) = (event.x-self.x0,event.y-self.y0)
if self.i0 > 0: # changing of the grid dimensions
(xquot,yquot) = (1.0/(self.x0-self.griddata['OFFSETX']),1.0/(self.y0-self.griddata['OFFSETY']))
else: # changing of the offstes
(dx_rel,dy_rel) = (dx,dy)
for line in self.grid_lines:
coords = self.graphcanvas.coords(line)
if coords[0] == coords[2]: # vertical line
if self.i0 > 0:
dx_rel = dx * (coords[2]-self.griddata['OFFSETX']) * xquot
self.graphcanvas.coords(line,coords[0]+dx_rel,coords[1],coords[2]+dx_rel,coords[3])
elif coords[1] == coords[3]: # horizontal line
if self.j0 > 0:
dy_rel = dy * (coords[3]-self.griddata['OFFSETY']) * yquot
self.graphcanvas.coords(line,coords[0],coords[1]+dy_rel,coords[2],coords[3]+dy_rel)
(self.x0,self.y0) = (event.x,event.y)
#************************************************************************************
def release_button_event (self,event):
if self.find_overlapping(event.x,event.y,event.x,event.y):
return()
if self.hl_block[0] and self.hl_block[0].syntax_error() == 1:
return()
#************************************************************************************
def xxrelease_line (self,event):
if self.i0 == 0:
self.griddata['OFFSETX'] = event.x
self.griddata['OFFSETY'] = event.y
else:
self.griddata['X'] = (event.x - self.griddata['OFFSETX'])/self.i0
self.griddata['Y'] = (event.y - self.griddata['OFFSETY'])/self.j0
del self.x0
del self.i0
del self.y0
del self.j0
#************************************************************************************
def delete_highlighted_element (self,event=None):
if self.hl_block[0]:
arrow = self.hl_block[0].hl_arrow
if arrow: # delete arrow
if self.compute_block_level(set([arrow])):
fkt = arrow.source_block
jump = arrow.target_block
arrow.destroy()
fkt.fit_shape()
jump.fit_shape()
self.highlight_block(None)
else: # delete block
block_arrows = set( self.hl_block[0].arrows_in ) | set( self.hl_block[0].arrows_out )
if self.compute_block_level(block_arrows,self.hl_block[0]):
self.hl_block[0].destroy()
self.blocks.remove(self.hl_block[0])
self.highlight_block(None)
self.compute_block_level()
for block in self.blocks:
for arrow in block.arrows_out:
if arrow in self.loop_arrows:
if arrow.color == 'black':
arrow.color = procpy.config.LOOPARROWCOLOR
arrow.highlight()
else:
if arrow.color == procpy.config.LOOPARROWCOLOR:
arrow.color = 'black'
arrow.highlight()
#************************************************************************************
def load (self,text):
for line in text.splitlines():
try: exec("self.obj_info_exec="+line)
except: continue
if self.obj_info_exec[0] == "Block":
# this part is for compatibility reasons (old saving concept); can be removed,
# when all files are saved including block.looping
if len(self.obj_info_exec)==3:
self.obj_info_exec.append(0)
elif isinstance(self.obj_info_exec[3],str):
self.obj_info_exec.append(self.obj_info_exec[3])
self.obj_info_exec[3] = 0
self.blocks.append(procpy.block.Block(self,self.obj_info_exec[1],self.obj_info_exec[2],self.obj_info_exec[3]))
try:
self.blocks[-1].content.config(state=tkinter.NORMAL)
self.blocks[-1].content.insert("1.0",self.obj_info_exec[4])
self.content.config(state=tkinter.DISABLED)
except:
pass
elif self.obj_info_exec[0] == "Swimlane":
self.swimlanes.append(procpy.swimlane.Swimlane(self, self.obj_info_exec[1], self.obj_info_exec[2]))
try:
self.swimlanes[-1].content.config(state=tkinter.NORMAL)
self.swimlanes[-1].content.insert("1.0",self.obj_info_exec[3])
self.content.config(state=tkinter.DISABLED)
except:
pass
elif self.obj_info_exec[0] == "Arrow":
source = self.blocks[int(self.obj_info_exec[1])]
target = self.blocks[int(self.obj_info_exec[2])]
procpy.arrow.Arrow(0,self,source,target,cond_string=self.obj_info_exec[3],cond_pos=self.obj_info_exec[4],
cond_anchor=self.obj_info_exec[5],arrow_points=[item for sublist in self.obj_info_exec[6] for item in sublist])
self.compute_block_level()
# self.rearr_grid(0.0)
#************************************************************************************
def save (self):
text = ""
# Auslesen der Bloecke
for block in self.blocks:
text = text + str(["Block"] + block.dump()) + "\n"
# Auslesen der Swimlanes
for block in self.swimlanes:
text = text + str(["Swimlane"] + block.dump()) + "\n"
# Auslesen der Pfeile
for block in self.blocks:
for arrow in block.arrows_out:
text = text + str(["Arrow"] + arrow.dump()) + "\n"
return text
#************************************************************************************
def new_token (self):
while (0 == 0):
token = random.randint(100000000000000,900000000000000)
if not token in self.tokens:
self.tokens[token] = 0
return(token)
#************************************************************************************
def name_blocks (self,export_list=False):
block_names = {}
counter = 0
if export_list:
self.blocks_by_names = {}
for block in self.blocks: # First run through the blocks
counter += 1
rand = random.randint(10,99)
name = "block"+str(counter)+str(rand)
block_names[block] = name
if export_list:
self.blocks_by_names[name] = block
return(block_names)
#************************************************************************************
def starting_blocks (self):
result = []
for block in self.blocks:
if len(block.arrows_in) == 0:
result.append(block)
return(result)
#************************************************************************************
def xxinitiate_class (self,classname):
print("INITIATE_CLASS")
text = '''
from random import randint
class ''' + classname + ''' ():
def __init__ (self):
self.JUMP = ''' + "['---FUNC---']" + '''
'''
bed = True
for block in self.blocks:
if block.nr < 2 and bed:
starting_block = block
text = re.sub(r"---FUNC---","Block"+str(self.blocks.index(block)),text)
if block.content.get("1.0",tkinter.END).strip():
text = "import " + block.content.get("1.0",tkinter.END).strip() + "\n" + text
bed = False
# add function for every block
for block in self.blocks: # Second run through the blocks.
text = text + '''
def ''' + "Block"+str(self.blocks.index(block)) + ''' (self):
exec ( "\\n".join(map(lambda x: x + " = self." + x,self.__dict__.keys())) )
''' # this code is for getting all variables local
if block.arrows_out: # add jump blocks if existing
text1 = " JUMP = []\n"
for arrow in block.arrows_out:
jump_name = "Block"+str(self.blocks.index(arrow.target_block))
jump_cond = arrow.text.get("1.0",'end-1c')
if (not jump_cond or jump_cond.isspace()) and len(block.arrows_out) == 1:
text1 = " JUMP = '" + jump_name + "'\n"
else:
if jump_cond and not jump_cond.isspace():
text1 = text1 + " if "+ jump_cond +":\n "
text1 = text1 + " JUMP.append('" + jump_name + "')\n"
if block.looping == 2:
text2 = '''
if len(JUMP)>1:
no = random.randint(0,len(JUMP)-1)
else:
no = 0
JUMP = JUMP[no]
'''
text1 = text1 + text2
text = text + text1
if block.arrows_in and len(block.arrows_in) > 1 and not block.looping==1:
text = text + " __WAIT__ = max(1,__WAIT__)\n"
# add text (python code) of the block
if not block == starting_block:
try:
text = text + "\n exec ('''" + block.content.get("1.0",tkinter.END)+ "\n''')\n"
except Exception as e:
pass
print (text)
# text = text + "\n print locals()\n\n"
text = text + "\n self.__dict__.update(locals())\n"
# text = text + "\n del self.self\n"
text = re.sub(r"\"([\d\.]+)\"","\\1",text,999999)
self.graphproc.storeproc.list_of_variables = {} # Statically found variables with their possible aggregate functions
open("model_prog.log","w").write(text)
return(text)
#************************************************************************************
def parser(self,blocktext):
'''
makes the text of the block readable in the program context
'''
if not blocktext:
return()
text = ""
for line in blocktext.splitlines():
text0 = line.split("=")
if not "self." in text0[0]:
text0[0]="self."+ text0[0]
text = text + "try:"+text0[0]+"+="+text0[1]+"\n"
text = text + "except:"+text0[0]+"="+text0[1]+"\n"
return text
#************************************************************************************
def xxnum_blocks (self,jump): # numerate a block
self.num_blocks_0(jump,999999) # 1. set the block and all ancestors to highest level
self.num_blocks_0(jump,0) # 2. now compute lower levels by arrows
if jump.nr == 999999:
self.num_blocks_0(jump,1) # 3. if jump.nr remains highest level, then number it with 1.
#************************************************************************************
def xxnum_blocks_0 (self,block,nr,touched_blocks={}): # determines the minimum level of a block
for arrow in block.arrows_in:
if nr == 0:
nr = 999999
nr = min(arrow.source_block.nr+1,nr)
if not block in touched_blocks:
touched_blocks[block] = block.nr
block.nr = nr
# block.fit_content("x")
for arrow in block.arrows_out:
jump = arrow.target_block
self.num_blocks_0(jump,min(nr+1,999999),touched_blocks)
#************************************************************************************
# def check_whether_point_is_inside_of_a_block (self,x=-1,y=-1):
#
# '''
# Returns the maximal width and height of all blocks,
# if the point (x,y) is not inside of any block.
# Otherwise it returns the fkt of the block.
# '''
#
# bbox_w = 0
# bbox_h = 0
#
# for block in self.blocks:
# if block.bbox[0] < x and x < block.bbox[2] and block.bbox[1] < y and y < block.bbox[3]:
# return(None,block)
# bbox_w = max(bbox_w,block.bbox[2]-block.bbox[0])
# bbox_h = max(bbox_h,block.bbox[3]-block.bbox[1])
#
# return(bbox_w,bbox_h)
#************************************************************************************
def xxtoggle_show_grid (self):
if self.griddata['SHOW']:
for line in self.grid_lines:
self.graphcanvas.delete(line)
self.grid_lines = []
self.griddata['SHOW'] = False
else:
# bbox = self.get_bounding_box()
maxx = max(bbox[2],self.graphcanvas.winfo_width())
maxy = max(bbox[3],self.graphcanvas.winfo_width())
self.grid_lines = []
x = self.griddata['X']
while x < maxx:
self.grid_lines.append(self.graphcanvas.create_line(x,0,x,maxy,width=1,fill="magenta",dash=(2,5)))
x = x + self.griddata['X']
y = self.griddata['Y']
while y < maxy:
self.grid_lines.append(self.graphcanvas.create_line(0,y,maxx,y,width=1,fill="magenta",dash=(2,5)))
y = y + self.griddata['Y']
for line in self.grid_lines:
self.graphcanvas.tag_bind(line,"<ButtonPress-1>", self.press_button)
self.graphcanvas.tag_bind(line,"<B1-Motion>", self.move_mouse)
self.graphcanvas.tag_bind(line,"<ButtonRelease-1>", self.release_line)
self.griddata['SHOW'] = True
self.gui.switch_tab()
#************************************************************************************
def xxgrid_select (self,l,event):
(x,y) = self.check_whether_point_is_inside_of_a_block()
if x:
(self.gx,self.gy) = (event.x,event.y)
else:
self.gx = None
#************************************************************************************
def xxgrid_move (self,event):
dx = event.x - self.gx
dy = event.y - self.gy
#************************************************************************************
def xxtoggle_snap_grid (self):
if self.griddata['SNAP']:
self.griddata['SNAP'] = False
else:
self.griddata['SNAP'] = True
self.gui.switch_tab()
#************************************************************************************
def xxfit_blocks_to_grid (self):
g = self.griddata
for block in self.blocks:
x = g['X'] * int((block.bbox[0] - g['OFFSETX'] + 0.5*g['X'])/g['X'])
y = g['Y'] * int((block.bbox[1] - g['OFFSETY'] + 0.5*g['Y'])/g['Y'])
dx = block.bbox[0] - x - g['OFFSETX']
dy = block.bbox[1] - y - g['OFFSETY']
block.newbbox = [ block.bbox[0] - dx, block.bbox[1] - dy,
block.bbox[2] - dx, block.bbox[3] - dy ]
#************************************************************************************
def xxrearrange_blocks(self): # arranges block without overlap
block_coordinates = []
for block in self.blocks:
i,j = block.gridpos()
while self.check_gridpos_empty(i,j,block_coordinates)==False:
i,j = block.gridpos(i,j+1)
block_coordinates.append([i,j])
#************************************************************************************
def xxcheck_gridpos_empty(self,coord1,coord2,block_coordinates):
i = coord1
j = coord2
return not([i,j] in block_coordinates or [i+1,j] in block_coordinates or [i-1,j] in block_coordinates)
#************************************************************************************
def rearr_grid (self,move_interval,b=0):
if 'semaphore_positioning_in_progress' in vars(self):
return()
for block in self.blocks:
block.newbbox = block.bbox[:]
sw = {}
for swimlane in self.swimlanes:
sw[ ("%09.4f" % swimlane.bbox[1]) + "-" + ("%09.4f" % swimlane.bbox[3]) ] = swimlane
swkeys = list(sw.keys())
swkeys.sort()
dy = 0 # shift to down
miny = 0 # limit in height for swimlane
for swkey in swkeys:
swimlane = sw[swkey]
dy = max(0,miny - swimlane.bbox[1])
swimlane.newbbox = [0,0,0,0,0]
swimlane.newbbox[1] = swimlane.bbox[1] + dy
swimlane.newbbox[2] = swimlane.bbox[2] - swimlane.bbox[0]
swimlane.newbbox[3] = swimlane.bbox[3] + dy
miny = swimlane.newbbox[3]
if hasattr(swimlane,'move_blocks'):
for block in swimlane.move_blocks:
block.newbbox[1] = block.newbbox[1] + dy
block.newbbox[3] = block.newbbox[3] + dy
# self.rearrange_blocks()
procpy.rearr_grid.Rearr_grid(self).newbends_for_arrows()
self.positioning(move_interval)
# self.fit_scrollbar()
#************************************************************************************
def xxrearr_grid_arrows_with_sugiyama (self,move_interval):
# for block in self.blocks:
# block.gridpos()
procpy.rearr_sugiyama.Rearr_sugiyama(self,0).arrows_sugiyama_fit()
self.positioning(move_interval)
#************************************************************************************
def xxrearr_sugiyama (self,move_interval):
procpy.rearr_sugiyama.Rearr_sugiyama(self,0).blocks_sugiyama_fit()
procpy.rearr_sugiyama.Rearr_sugiyama(self,0).arrows_sugiyama_fit()
self.positioning(move_interval)
#************************************************************************************
def xxrearr_circle (self,move_interval):
print("xxrearr_circle---nxs");
(maxw,maxh) = (0,0)
for block in self.blocks:
(maxw,maxh) = (max(maxw,block.bbox[2]-block.bbox[0]),
max(maxh,block.bbox[3]-block.bbox[1]))
anzahl = float(len(self.blocks))
radiusx = maxw * math.log(anzahl) * 1.5
radiusy = maxh * math.log(anzahl) * 1.5
zaehler = anzahl
self.blocks.sort(key=lambda block: block.nr)
for block in self.blocks:
block.newbbox = [0,0,0,0]
block.newbbox[0] = radiusx * (1.1+math.cos(math.pi*zaehler/anzahl))
block.newbbox[1] = radiusy * (1.1+math.sin(math.pi*zaehler/anzahl))
block.newbbox[2] = block.newbbox[0] + block.bbox[2] - block.bbox[0]
block.newbbox[3] = block.newbbox[1] + block.bbox[3] - block.bbox[1]
zaehler = zaehler + 2
for arrow in block.arrows_out:
arrow.newbends = []
arrow.anchorline = 0
self.positioning(move_interval)
#************************************************************************************
def xxrearr_swimlane (self,move_interval):
swimlanes = {} # Collecting and sorting the swimlanes
for swimlane in self.swimlanes:
swimlanes[ ("%09.4f" % swimlane.bbox[1]) + "-" + ("%09.4f" % swimlane.bbox[3]) ] = swimlane
swkeys = list(swimlanes.keys())
swkeys.sort()
dy = 0 # shift to down
miny = 0 # limit in height for swimlane
all_arrows = []
for block in self.blocks:
block.newbbox = block.bbox[:]
for arrow in block.arrows_in:
all_arrows.append(arrow)
arrow.newbends = []
for arrowline in arrow.arrowlines[:-1]:
coords = self.graphcanvas.coords(arrowline)
arrow.newbends.append([coords[2],coords[3]])
for swkey in swkeys:
swimlane = swimlanes[swkey]
dy = max(0,miny - swimlane.bbox[1])
swimlane.newbbox = [0,0,0,0,0]
swimlane.newbbox[1] = swimlane.bbox[1] + dy
swimlane.newbbox[2] = swimlane.bbox[2] - swimlane.bbox[0]
swimlane.newbbox[3] = swimlane.bbox[3] + dy
miny = swimlane.newbbox[3]
# (blocks,arrows,singlepoints) = swimlane.blocks_and_arrows_in_swimlane()
(blocks,arrows,singlepoints) = (swimlane.move_blocks,swimlane.move_arrows,swimlane.move_singlepoints)
for block in blocks:
block.newbbox[1] = block.bbox[1] + dy
block.newbbox[3] = block.bbox[3] + dy
for arrow in arrows:
all_arrows.remove(arrow)
zaehler = 0
for arrowline in arrow.arrowlines[:-1]:
arrow.newbends[zaehler][1] = arrow.newbends[zaehler][1] + dy
zaehler = zaehler + 1
for point in singlepoints:
if point[2] == 0 and point[1] > 0:
arrow = point[0]
arrow.newbends[point[1]-1][1] = arrow.newbends[point[1]-1][1] + dy
self.positioning(move_interval)
#************************************************************************************
def set_background_image(self, filename, fac=None):
try:
self.delete(self.bg)
self.bg = None
except Exception as e:
pass
try:
image_pil = Image.open(filename)
if fac:
w,h = image_pil.size
image_pil = image_pil.resize((int(w*fac), int(h*fac)),Image.ANTIALIAS)
self.im = ImageTk.PhotoImage(image_pil)
except Exception as e:
return()
self.bg = self.create_image(0,0, image=self.im, anchor="nw")
self.tag_lower(self.bg)
self.tag_bind(self.bg, "<Button-1>", self.unhighlight_block)
self.tag_bind(self.bg, "<ButtonRelease-1>", self.release_button_event)
self.tag_bind(self.bg, "<B1-Motion>", self.move_mouse_event)
#************************************************************************************
def create_arrow_line (self,*pars,**args):
args1 = args.copy()
args1['fill'] = "white"
args1['width'] = args['width'] + 10
# args1['state'] = "hidden"
bg_line = self.create_line(*pars,**args1) # background line for binding application
arrowline = self.create_line(*pars,**args)
self.tag_lower(bg_line)
return([arrowline,bg_line])
#************************************************************************************
def coords (self,*pars,**args):
if len(pars) > 0 and type(pars[0]) == type([]):
erg = []
for item in pars[0]:
erg.append(tkinter.Canvas.coords(self,item,*tuple(list(pars)[1:]),**args))
return(erg[0])
else:
return( tkinter.Canvas.coords(self,*pars,**args) )
#************************************************************************************
def itemconfig (self,*pars,**args):
if len(pars) > 0 and type(pars[0]) == type([]):
for item in pars[0]:
tkinter.Canvas.itemconfig(self,item,*tuple(list(pars)[1:]),**args)
args['fill'] = 'white'
else:
tkinter.Canvas.itemconfig(self,*pars,**args)
#************************************************************************************
def tag_bind (self,*pars,**args):
if len(pars) > 0 and type(pars[0]) == type([]):
for item in pars[0]:
tkinter.Canvas.tag_bind(self,item,*tuple(list(pars)[1:]),**args)
else:
tkinter.Canvas.tag_bind(self,*pars,**args)
#************************************************************************************
def tag_lower (self,*pars,**args):
for obj in pars:
tkinter.Canvas.tag_lower(self,obj)
if self.type(obj) == "image" or not str(self.itemcget(obj,'fill'))=='white': # white object should be lowest
try:
while self.itemcget(self.find_above(obj),"fill") == "white" :
self.tag_raise(obj,self.find_above(obj))
except: break
#************************************************************************************
def delete (self,*pars,**args):
if len(pars) > 0 and type(pars[0]) == type([]):
for item in pars[0]:
tkinter.Canvas.delete(self,item,*tuple(list(pars)[1:]),**args)
else:
tkinter.Canvas.delete(self,*pars,**args)
#************************************************************************************
def positioning (self,move_interval=10.0,max_rounds=100):
duetime = time.perf_counter() + move_interval
zaehler = 0
gesamt_time = 0
nr = max_rounds
if 'semaphore_positioning_in_progress' in vars(self):
if time.perf_counter() - self.semaphore_positioning_in_progress > 10 * move_interval:
print("WARNING","Semaphore could not be deleted")
del self.semaphore_positioning_in_progress
else:
return()
self.semaphore_positioning_in_progress = time.perf_counter()
# 1. Preparation: Absolute to relative values, extend arrows if necessary
maxshift = 0
for block in self.blocks + self.swimlanes: # shift the absolute coordinates to relative
if 'newbbox' in vars(block):
block.newbbox = [block.newbbox[0]-block.bbox[0],block.newbbox[1]-block.bbox[1],
block.newbbox[2]-block.bbox[2],block.newbbox[3]-block.bbox[3]]
else:
block.newbbox = [0,0,0,0]
maxshift = max(maxshift,abs(block.newbbox[0]),abs(block.newbbox[1]),
abs(block.newbbox[2]),abs(block.newbbox[3]))
for arrow in block.arrows_out:
if not 'newbends' in vars(arrow):
continue
bends = arrow.newbends
lines = arrow.arrowlines
print("----------bends:%s" % bends)
print("----------lines:%s" % lines)
zaehler = 1
for bend in bends:
if len(lines) == 1: # if no bend is in arrow
(x,y) = arrow.get_shapes_mid_point()
coords = self.coords(lines[0])
self.coords(lines[0],x,y,coords[2],coords[3])
lines.insert(-1,self.create_arrow_line(coords[0],coords[1],x,y,
fill='black',width=procpy.config.ARROWTHICKNESS))
while len(lines) < zaehler+1: # extend arrow bends to match the count of new bends
coords = self.coords(lines[-1])
lines.insert(-1,self.create_arrow_line(coords[0],coords[1],coords[0],coords[1],
fill='black',width=procpy.config.ARROWTHICKNESS))
coords = self.coords(lines[zaehler])
bend[0] = bend[0] - coords[0]
bend[1] = bend[1] - coords[1]
maxshift = max(maxshift,abs(bend[0]),abs(bend[1]))
zaehler = zaehler + 1
# self.gui.mark("B")
# 2. Morphing arrows in a loop step by step
while nr > 0:
time0 = time.perf_counter()
for block in self.blocks + self.swimlanes:
if 'newbbox'in vars(block):
(dx0,dy0,dx1,dy1) = ( block.newbbox[0]/nr, block.newbbox[1]/nr, block.newbbox[2]/nr, block.newbbox[3]/nr )
block.newbbox = [ block.newbbox[0] - dx0, block.newbbox[1] - dy0,
block.newbbox[2] - dx1, block.newbbox[3] - dy1 ]
block.bbox = [ block.bbox[0] + dx0, block.bbox[1] + dy0, block.bbox[2] + dx1, block.bbox[3] + dy1 ]
block.format_shape()
for block in self.blocks:
for arrow in block.arrows_out:
if not 'newbends' in vars(arrow):
continue
zaehler1 = 0
while (0 == 0):
px = None
try:
c_line1 = self.coords(arrow.arrowlines[zaehler1+1])
except:
break
c_line0 = self.coords(arrow.arrowlines[zaehler1])
try:
bend = arrow.newbends[zaehler1]
(dx,dy) = ( bend[0]/nr, bend[1]/nr )
bend[0] = bend[0] - dx
bend[1] = bend[1] - dy
(px,py) = ( c_line1[0], c_line1[1] )
except Exception as e: # if no new bend definition is available anymore
if not px:
(px,py) = arrow.get_shapes_mid_point()
(dx,dy) = ( (px-c_line0[2])/nr, (py-c_line0[3])/nr )
self.coords(arrow.arrowlines[zaehler1],
c_line0[0], c_line0[1], c_line0[2]+dx, c_line0[3]+dy)
self.coords(arrow.arrowlines[zaehler1+1],
c_line1[0]+dx, c_line1[1]+dy, c_line1[2], c_line1[3] )
zaehler1 = zaehler1 + 1
# bbox = self.get_bounding_box()
arrow.fit_block_connections()
arrow.fit_description() # self.griddata)
self.update()
# bbox = self.get_bounding_box()
xdim = self.winfo_width()
ydim = self.winfo_height()
# self.gui.mark(str(nr))
zaehler = zaehler + 1 # count runs
time0 = time.perf_counter() - time0 # time for this loop run
gesamt_time = gesamt_time + time0
rest_time = duetime - time.perf_counter() # Computing runs /waittime to match
avg_time = gesamt_time/zaehler # the interval for this action
if rest_time > 0 :
wait_time = rest_time/nr - avg_time
if wait_time > 0:
time.sleep(wait_time)
nr = nr-1
else:
nr = min( int(rest_time/avg_time), nr-1 )
nr = max(1,nr)
else:
nr = min(2,nr-1)
# self.gui.mark("C")
# bbox = self.get_bounding_box()
xdim = self.winfo_width()
ydim = self.winfo_height()
# self.config(scrollregion=(0,0,max(xdim,bbox[2]),max(ydim,bbox[3])))
# 3. Deleting superfluous bends in arrows at end of moving
for block in self.blocks:
for arrow in block.arrows_out:
if not 'newbends' in vars(arrow):
continue
lines = arrow.arrowlines
try:
soll_len = len(arrow.newbends) + 1
except:
continue
c_line0 = None
while soll_len < len(lines):
c_line0 = self.coords(lines[-2])
self.delete(lines.pop(-2))
if c_line0:
c_line1 = self.coords(lines[-1])
self.coords(lines[-1],c_line0[0],c_line0[1],c_line1[2],c_line1[3])
arrow.fit_description() # self.griddata)
del arrow.newbends
try:
del block.newbbox
except:
pass
# 4. now at last a re-fitting is necessary
for block in self.blocks:
for arrow in block.arrows_out:
arrow.fit_block_connections()
arrow.elem_bindings()
self.update()
del self.semaphore_positioning_in_progress
return(True)
#************************************************************************************
def reset_speed (self):
self.speedruler.set(950)
#************************************************************************************
def get_bounding_box (self):
bbox = []
for block in self.blocks:
block.bounding_box(bbox)
for jump in block.arrows_in:
jump.bounding_box(bbox)
return(bbox)
#************************************************************************************
def set_zoomfaktor (self,fac): # fac: factor to zoom, if = -1/ -2/ -3: fit to width, height resp. canvas
xdim0 = self.winfo_width()
ydim0 = self.winfo_height()
if fac < 0 and fac > -4: # fit to page width resp. height resp. canvas
self.graphcanvas.update()
bbox = self.get_bounding_box()
fakx = float(xdim) / float(bbox[2]) # - bbox[0])
faky = float(ydim) / float(bbox[3]) # - bbox[1])
if fac == -3 and fakx < faky:
fac = -1
elif fac == -3:
fac = -2
fac = 0.96 * [fakx,faky][-fac-1]
if self.hl_block[0] and not self.hl_block[0].shape == "a": # Textgroesse erhalten bei Highlighting
self.hl_block[0].fontsize = self.hl_block[0].fontsize / fac
self.zoom_factor = self.zoom_factor * fac
for block in self.blocks + self.swimlanes:
block.scale(fac)
bbox = self.get_bounding_box()
xdim = max(xdim0,bbox[2])
ydim = max(ydim0,bbox[3])
self.config(scrollregion=(0,0,xdim,ydim))
if self.hl_block[0] and not self.hl_block[0].shape == "a": # Textgroesse erhalten bei Highlighting
xdim0 = self.winfo_width()
ydim0 = self.winfo_height()
(x0,x1,y0,y1,x,y,w,h) = self.hl_block[0].box_coord()
self.xview_moveto(abs(float(x-xdim0/2)/float(xdim)))
self.yview_moveto(abs(float(y-ydim0/2)/float(ydim)))
# zoom background-image
self.set_background_image(procpy.config.FILENAME, self.zoom_factor)
#************************************************************************************
def sortcols (self,event):
canvas = event.widget
x = canvas.canvasx(event.x)
y = canvas.canvasy(event.y)
fieldnr = int(x)/160
field = self.actual_report_columns[fieldnr]
if self.sortfield == field:
self.sortupper = (self.sortupper + 1) % 4
else:
self.sortupper = 0
self.sortfield = field
self.draw_report_bars()
#**************************************************************************
def compute_report_data (self,entry):
try:
group0 = entry.SUMVALUES[self.groupby]
except:
pass #group0 =
try:
group0 = str(float(group))
except:
pass
for group in [group0,"__gesamt__"]:
try:
self.counts[group] += 1
except:
self.counts[group] = 1
self.sumvalues[group] = {}
if not group == "__gesamt__":
self.maxcount = max(self.counts[group],self.maxcount)
for field in self.report_fields:
if field == "COUNT":
continue
if field == "":
continue
try:
self.sumvalues[group]
except:
self.sumvalues[group] = {}
try:
self.sumvalues[group][field]
except:
self.sumvalues[group][field] = 0
try:
self.maxvalues[field]
except:
self.maxvalues[field] = 0
try:
val = entry.SUMVALUES[field]
except:
val = "0"
try:
val = float(val)
self.sumvalues[group][field] += val
if not group == "__gesamt__":
self.maxvalues[field] = max(self.maxvalues[field],val)
except:
self.sumvalues[group][field] = val
self.draw_data = []
for group in self.sumvalues:
data_row = {}
for field in self.report_fields:
if field == "COUNT":
data_row[field] = [self.counts[group],self.maxcount]
else:
val = self.sumvalues[group][field]
try:
val = float(val) / self.counts[group]
except Exception as e:
pass
data_row[field] = [val,self.maxvalues[field]]
if group == "__gesamt__":
self.draw_data_gesamt = data_row
else:
self.draw_data.append(data_row)
#****************************************************
def draw_report_headers (self,reason_for_call=1):
new_columns = []
for header_combobox in self.header_comboboxes:
header_text = header_combobox.get()
if not header_text == "":
new_columns.append(header_text)
new_columns.append("")
if not self.actual_report_columns == new_columns:
o1 = len(self.actual_report_columns)
o2 = len(new_columns)
if not o2 == o1:
if o2 < o1:
while o2 < len(self.header_comboboxes):
self.header_comboboxes[-1].destroy()
del self.header_comboboxes[-1]
else:
newcombo = tkinter.ttk.Combobox(self.reportcanvas,width=12,font=("Arial",8))
self.reportcanvas.create_window((o2-1)*160+20,5,anchor=tkinter.NW,window=newcombo)
if o1 == 0:
newcombo.insert(0,'PATH')
newcombo.config(state='readonly')
if o1 == 1:
newcombo.insert(0,'COUNT')
newcombo.config(state='readonly')
else:
newcombo.config(postcommand=self.draw_report_headers)
# newcombo.config(validatecommand=self.draw_report,validate='all')
self.header_comboboxes.append(newcombo)
self.reportcanvas.config(scrollregion=(0,0,len(self.header_comboboxes)*160,10))
self.actual_report_columns = new_columns
zaehler = 0
option_values = self.vars + [""]
for column_text in self.actual_report_columns:
self.header_comboboxes[zaehler].delete(0,9999)
self.header_comboboxes[zaehler].insert(0,column_text)
if column_text in ['PATH','COUNT']:
self.header_comboboxes[zaehler].config(values=[])
else:
self.header_comboboxes[zaehler].config(values=option_values)
zaehler = zaehler + 1
if 'draw_data' in vars(self):
self.draw_report_bars()
self.reportcanvas.config(scrollregion=(0,0,len(self.header_comboboxes)*160,10))
if len(self.actual_report_columns) < 3:
return(self.draw_report_headers())
#****************************************************
def draw_report_bars (self):
# nr = self.report_fields_nr[self.sortfield]
if self.sortfield == 'COUNT':
self.draw_data.sort(key=lambda x: x['COUNT']+x['PATH'], reverse=(self.sortupper%2==0))
else:
self.draw_data.sort(key=lambda x: x[self.sortfield], reverse=(self.sortupper%2==0))
self.draw_data1 = [self.draw_data_gesamt] + self.draw_data
self.reportcanvas.delete("reportbar")
row = 1
cellh = 12
cellw = 160
x0 = 0
y0 = 2*cellh
y0 = 3*cellh
gesamtzeile = True # first line is the total/average data line
for ergrow in self.draw_data1:
x0 = 0
y0 = y0 + cellh
for field in self.actual_report_columns[0:-1]:
if gesamtzeile and field == self.sortfield:
xpos = x0+2
ypos = y0-int(2.7*cellh)
color_sort = "yellow"
if self.sortupper%2 == 0: # compute and draw sort marker
ypos = ypos - 10
color_sort = "red"
self.reportcanvas.create_oval(xpos,ypos,xpos+4,ypos+4,fill=color_sort,tag='reportbar')
fillcolor = procpy.config.COLOR_REPORTBAR
val = ergrow[field][0]
gval = ergrow[field][1]
if gesamtzeile:
fillcolor = 'grey'
if field == 'PATH':
val = "TOTAL / AVERAGE"
try:
val1 = float(val)/float(gval)
if not (gesamtzeile and field == "COUNT"):
o = self.reportcanvas.create_rectangle(x0+5,
y0-12,
x0+5+val1*(cellw-40),
y0-2,
fill=fillcolor,tag='reportbar')
self.reportcanvas.tag_bind(o,'<ButtonPress-1>',lambda event: self.sortcols(event) )
val = int(val)
except:
pass
if field == 'COUNT' and self.sortupper > 1:
if gesamtzeile:
relative_val = val
else:
val = '%3.1f' % (100 * float(val) / float(relative_val) ) + '%'
o = self.reportcanvas.create_text(x0+6,y0,text=str(val),anchor='sw',font=("Arial",8),
tag=['reportbar',field])
self.reportcanvas.tag_bind(o,'<ButtonPress-1>',lambda event: self.sortcols(event) )
x0 = x0 + cellw
gesamtzeile = False
self.reportcanvas.config(scrollregion=(0,0,len(self.header_comboboxes)*160,y0+15))
#***************************************************************************************
def xxstart_process(self):
if self.saved_yet == 0:
self.save_graphics()
self.startbutton.config(state='disable')
self.hl_block = None
o = self.runcounter.get()
self.runcounter.delete(0,10)
if int(o) < 1:
self.runcounter.insert(0,"1")
self.startbutton.config(state='normal')
return(0)
self.runcounter.insert(0,str(int(o)-1))
o = self.resetbutton.config('text')[-1]
self.resetbutton.config(text=str(int(o)+1))
self.block_list = {}
self.hl_blocks = {}
self.steps = {}
for block in self.blocks:
self.graphcanvas.itemconfig(block.elems['SHAPE'],fill=self.color_blocks)
# if block.shape == 'a':# swimlanes are not counted in block_list
# pass
# else:
# self.block_list[block.fkt] = block
if not self.block_list: # if there are no blocks, stop process
self.stop_process()
return()
self.loopobj.after(0,self.proceed_process,self.__module__+".PROC")
#***************************************************************************************
def xxproceed_process (self,mode="START",pars=[]):
proc_instance = procpy.prcmanager.Prcmanager(self.db).run_process(mode,pars)
speedfactor = 5**(int(self.speedruler.get())/100-1)
if proc_instance:
self.entry = proc_instance
obj = proc_instance.OBJID
fkt = proc_instance.__func__
sleeptime = str(proc_instance.TIME)
if obj in self.hl_blocks:
id = self.hl_blocks[obj]
self.block_list[id].content.config(bg=self.color_blocks,highlightcolor=self.color_blocks)
self.block_list[id].contentframe.config(background=self.color_blocks,bg=self.color_blocks,
highlightcolor=self.color_blocks)
self.graphcanvas.itemconfig(self.block_list[id].elems['SHAPE'],fill=self.color_blocks) # <----
try:
fillcolor1 = "red"
self.block_list[fkt].content.config(bg=fillcolor1,highlightcolor=fillcolor1) # color the content
self.block_list[fkt].contentframe.config(background=fillcolor1,bg=fillcolor1,
highlightcolor=fillcolor1) # color the contentframe
self.graphcanvas.itemconfig(self.block_list[fkt].elems['SHAPE'],fill=fillcolor1) # color the outer rectangle
self.hl_blocks[obj] = fkt
except Exception as e:
pass
print(str(e))
if int(sleeptime) < 9999999900: # Prozess laeuft weiter
self.loopobj.after(max( 50,int(sleeptime)*1000/speedfactor),self.proceed_process,'___dryrun___')
return()
self.compute_report_data(self.entry) # Daten des beendeten Prozesses gehen
self.draw_report_headers() # in das Reporting ein
self.draw_report_bars()
# self.runobj = procpy.caller.Scripts()
self.loopobj.after(max(35,int(1000/speedfactor)),self.del_all_highlighting)
self.loopobj.after(max(70,int(2000/speedfactor)),self.start_process)
#****************************************************
def xxstop_process (self):
o = self.runcounter.get()
self.runcounter.delete(0,10)
self.runcounter.insert(0,"1")
self.del_all_highlighting()
self.startbutton.config(state='normal')
#****************************************************
def xxreset_process_data (self):
self.reset_drawdata()
self.reportcanvas.delete('reportbar')
#****************************************************
def reset_drawdata (self):
self.resetbutton.config(text='0')
self.report_fields = ['PATH','COUNT'] + self.vars
self.counts = {}
self.maxcount = 0
self.sumvalues = {}
self.maxvalues = {}
self.draw_report_headers()
# self.field_expression = {}
# for field in self.report_fields:
# if re.search(r"[^A-Za-z0-9\_]",field):
# self.field_expression[field] = re.sub(r"([A-Z][A-Za-z0-9\_]*)","float(entry.\\1)",field,99999999)
# else:
# self.field_expression[field] = "entry." +field
#
#****************************************************
def del_all_highlighting (self):
self.saved_yet = 0
fillcolor1 = self.color_blocks
for block in self.blocks:
block.content.config(bg=fillcolor1,highlightcolor=fillcolor1) # color the content
block.contentframe.config(background=fillcolor1,bg=fillcolor1,highlightcolor=fillcolor1) # color the contentframe
self.graphcanvas.itemconfig(block.elems['SHAPE'],fill=fillcolor1) # color the outer rectangle
#****************************************************
def show_menu(self, event,):
if self.allow_context_menu:
type = self.graphcanvas.type(event.widget.find_withtag("current"))
if self.click_target == None or type == None:
background_menu = tkinter.Menu(self.graphcanvas, tearoff=0)
background_menu.add_command(label="New block", command= lambda :self.create_block(event.x_root, event.y_root))
background_menu.post(event.x_root, event.y_root)
elif self.click_target.__class__ is procpy.block.Block:
block_menu = tkinter.Menu(self.graphcanvas, tearoff=0)
block_menu.add_command(label="New arrow", command=lambda : self.create_arrow(self.click_target))
block_menu.post(event.x_root, event.y_root)
#************************************************************************************
#************************************************************************************
def xxscale_texts (self,fac): # scale texts
for block in self.blocks:
block.scale_texts(fac)
for arrow in block.arrows_out:
arrow.scale_texts(fac)
self.current_zoom_factor = self.current_zoom_factor * fac
#************************************************************************************
def xxset_zoomfaktor (self,fac,draw_new=True):
xdim = self.graphcanvas.winfo_width()
ydim = self.graphcanvas.winfo_height()
if fac < 0 and fac > -4: # fit to page width resp. height resp. canvas
self.graphcanvas.update()
bbox = self.get_bounding_box()
fakx = xdim / (bbox[2] - bbox[0])
faky = ydim / (bbox[3] - bbox[1])
if fac == -1:
fak = fakx
elif fac == -2:
fak = faky
else:
fak = min(fakx,faky)
self.graphcanvas.scale("all",0,0,fak,fak)
"""for fkt in self.blocks[fkt]:
block = self.blocks[fkt]
old_size = self.graphcanvas.itemcget(block.text,'text')
new_size = self.graphcanvas.itemconfig(block.text,font=('Arial',old_size*fak)
for fkt in self.arrows:
for jump in self.arrows[fkt][jump]"""
bbox = self.get_bounding_box()
self.graphcanvas.config(scrollregion=(bbox[0],bbox[1],max(bbox[2],bbox[0]+xdim)+1,max(bbox[3],bbox[1]+ydim)+1))
# for fkt in self.blocks[fkt]:
# block = self.blocks[fkt]
# old_size = self.graphcanvas.itemcget(block.text,'text')
# new_size = self.graphcanvas.itemconfig(block.text,font=('Arial',old_size*fak)
# for fkt in self.arrows:
# for jump in self.arrows[fkt][jump]
# elif fac == -5:
# if self.fak == -1:
# fac = -7
# else:
# fac = -9
## if fac == -7: # toggle back to graph view
# self.fak = self.fit
#
# elif fac == -9: # presentation as a textfield for the pycode
# self.fak = -1
#
elif fac > 0:
bbox = self.get_bounding_box()
self.graphcanvas.scale("all",0,0,fac,fac)
bbox = self.get_bounding_box()
# bx = bbox[2] - bbox[0] + 20
# by = bbox[3] - bbox[1] + 20
# bbox = self.get_bounding_box()
# print (bbox[0],bbox[1],max(bbox[2],bbox[0]+xdim),max(bbox[3],bbox[1]+ydim))
self.graphcanvas.config(scrollregion=(bbox[0],bbox[1],max(bbox[2],bbox[0]+xdim)-1,max(bbox[3],bbox[1]+ydim)-1))
# self.graphcanvas.config(scrollregion=(0,0,bbox[2]+20,bbox[3]+15))
# faknew = self.fak * fac
# if True:
## if (faknew > fakx or faknew > faky) and faknew < 10*max(fakx,faky):
# self.fak = faknew
# self.fit = faknew
# else:
# return()
#
# try:
# if self.fak < self.fak0 * (1 + 0.00001) and self.fak > self.fak0 * (1 - 0.00001):
# return
# except:
# pass
# self.fak0 = self.fak
# self.draw_bpm()
#************************************************************************************
def xxdraw_miniview (self):
fakx = self.miniview_w / (self.pd.w())
faky = self.miniview_h / (self.pd.h())
self.draw_graphics(self.miniview,min(fakx,faky),self.moffset,False)
#************************************************************************************
def xxdraw_bpm (self):
if self.fak < 0:
pycode = self.pd.text
else:
self.graphcanvas_w = self.fak * (self.pd.w())
self.graphcanvas_h = self.fak * (self.pd.h())
print(self.graphcanvas_w)
print(self.graphcanvas_h)
try:
self.graphcanvas.destroy()
except:
pass
try:
self.xscroll.destroy()
except:
pass
try:
self.yscroll.destroy()
except:
pass
if self.fak < 0:
self.graphcanvas = tkinter.Frame(self.graphframe)
self.graphcanvas.pack(expand=tkinter.TRUE,fill=tkinter.BOTH)
self.graphtext = tkinter.Text(self.graphcanvas,wrap=tkinter.NONE,width=10,height=10)
self.graphtext.pack(expand=True,fill=tkinter.BOTH)
self.graphtext.insert(tkinter.END,pycode)
else:
self.graphcanvas = tkinter.Canvas(self.graphframe)
self.graphcanvas.config(scrollregion=(0,0,self.graphcanvas_w,self.graphcanvas_h))
self.xscroll = tkinter.Scrollbar(self.graphframe,orient=tkinter.HORIZONTAL)
self.yscroll = tkinter.Scrollbar(self.graphframe,orient=tkinter.VERTICAL)
self.xscroll.config(command=self.graphcanvas.xview,width=8)
self.yscroll.config(command=self.graphcanvas.yview,width=8)
self.graphcanvas.config(xscrollcommand=self.xscroll.set)
self.graphcanvas.config(yscrollcommand=self.yscroll.set)
self.xscroll.pack(side=tkinter.BOTTOM,fill=tkinter.X)
self.yscroll.pack(side=tkinter.RIGHT,fill=tkinter.Y)
self.graphcanvas.pack(side=tkinter.LEFT,expand=True,fill=tkinter.BOTH)
# create a menu
#self.initUI()
#Moving canvas with mouse not working at the moment with moving with items
#self.graphcanvas.bind("<ButtonPress-1>", self.move_start)
#self.graphcanvas.bind("<B1-Motion>", self.move_move)
#Add zoom function with mousewheel
# linux
self.graphcanvas.bind("<Button-4>", self.zoomerP)
self.graphcanvas.bind("<Button-5>", self.zoomerM)
# windows
self.graphcanvas.bind("<MouseWheel>", self.zoomer)
if self.fak > 0:
self.draw_graphics(self.graphcanvas,self.fak,self.offset,True)
#************************************************************************************
def xxdraw_graphics (self,graph_widget,fak,offset,with_text=False):
graph_widget.config(background='white')
self.sources = {} # The arrow lists of the blocks where the arrows are sources
self.targets = {} # The arrow lists of the blocks where the arrows are targets
for fkt in self.pd.funcs: # process all the blocks
self.sources[fkt] = []
self.targets[fkt] = []
x = fak * ( self.pd.x(fkt) - self.pd.x0() ) + offset
y = fak * ( self.pd.y(fkt) - self.pd.y0() ) + offset
w = fak * self.pd.w(fkt)
h = fak * self.pd.h(fkt)
# self.blocks[fkt] = graph_widget.create_rectangle(
# int(x-w/2),int(y-h/2),
# int(x+w/2),int(y+h/2),fill=self.color_blocks)
block_size = (int(x-w/2),int(y-h/2),int(x + w / 2),int(y+h/2))
self.blocks[fkt] = Box(graph_widget,fkt,self.color_blocks,block_size)
if with_text:
#o1 = self.graphcanvas.create_text(int(x-w/2),int(y-h/2),anchor=Tkinter.NW,
# text=fkt,font=("ARIAL",6))
#o2 = self.graphcanvas.create_text(int(x),int(y),anchor=Tkinter.CENTER,
# text=self.pd.prg(fkt),font=("ARIAL",7))
self.blocks[fkt].create_text((int(x-w/2),int(y-h/2)),tkinter.NW,fkt,6)
self.blocks[fkt].create_text((int(x),int(y)), tkinter.CENTER, self.pd.prg(fkt), 7)
# self.graphcanvas.tag_bind(o,'<ButtonPress-1>',self.make_text_fkt(node) )
self.colors[fkt] = self.color_blocks
for fkt in self.pd.funcs: # draw the arrows:
for ziel in self.pd.data[fkt]['JUMP']: # process all the edges
self.pd.data[fkt]['JUMP'][ziel][1:]
arrow = [self.pd.x(fkt),self.pd.y(fkt)] + self.pd.data[fkt]['JUMP'][ziel][1:] + [self.pd.x(ziel),self.pd.y(ziel)]
p0 = None
zaehler = 0
while (0 == 0):
try:
p = [ arrow[zaehler], arrow[zaehler+1] ]
except:
break
zaehler = zaehler + 2
x = fak * ( p[0] - self.pd.x0() ) + offset
y = fak * ( p[1] - self.pd.y0() ) + offset
if p0:
#o = graph_widget.create_line(int(p0[0]),int(p0[1]),int(x),int(y),fill='black')
arrow_size = (int(p0[0]),int(p0[1]),int(x),int(y))
self.blocks[fkt].create_arrow(arrow_size,"black",ziel)
self.blocks[ziel].set_arrow_from(fkt+":"+ziel)
#self.sources[fkt].append(o)
#self.targets[fkt].append(o)
p0 = [x,y]
#if with_text:
#graph_widget.create_oval(x-1.5,y-1.5,x+1.5,y+1.5,fill="black")