Läuft die Voice Acoustic VA-Remotecontrol (AllDSP AllControl) nativ unter Linux auf echtem wxGTK 3.0 — ohne Wine und ohne dekompilierten App-Code. Ausgeführt wird das unveränderte Python-2.7-Bytecode aus dem macOS-.app; C-Extensions (wxGTK/numpy/ scipy/PortAudio) kommen nativ aus Debian stretch. Enthält: va/ (Original-.pyc + pure-Python-Libs + Assets + launch.py mit den drei Linux-Fixes), Dockerfile/run.sh/entrypoint.sh, reference/ (dekompilierter Quellcode zum Debuggen) und README/STATUS. img.cache (378 MB, regenerierbar) ist per .gitignore ausgeschlossen. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1076 lines
30 KiB
Python
1076 lines
30 KiB
Python
# uncompyle6 version 3.9.3
|
|
# Python bytecode version base 2.6 (62161)
|
|
# Decompiled from: Python 3.9.25 (main, Oct 31 2025, 23:16:49)
|
|
# [GCC 14.2.0]
|
|
# Embedded file name: MyOGLlike.pyc
|
|
# Compiled at: 2023-05-16 13:01:50
|
|
import wx, pickle, os, sys, copy, mytime, one_unit, traceback, array
|
|
clipboard = []
|
|
|
|
def menuMaker(frame, menus):
|
|
menubar = wx.MenuBar()
|
|
for (m, n) in menus.items():
|
|
menu = wx.Menu()
|
|
menubar.Append(menu, m)
|
|
for x in n:
|
|
id = wx.NewId()
|
|
menu.Append(id, x[0], x[1])
|
|
wx.EVT_MENU(frame, id, x[2])
|
|
|
|
frame.SetMenuBar(menubar)
|
|
return
|
|
|
|
|
|
class Diagram():
|
|
|
|
def __init__(self):
|
|
self.shapes = []
|
|
return
|
|
|
|
def AddShape(self, shape, after=None):
|
|
if after:
|
|
self.shapes.insert(self.shapes.index(after), shape)
|
|
else:
|
|
self.shapes.insert(0, shape)
|
|
return
|
|
|
|
def AppendShape(self, shape):
|
|
self.shapes.append(shape)
|
|
return
|
|
|
|
def InsertShape(self, shape, index=0):
|
|
self.shapes.insert(index, shape)
|
|
return
|
|
|
|
def DeleteShape(self, shape):
|
|
self.shapes.remove(shape)
|
|
return
|
|
|
|
def PopShape(self, index=-1):
|
|
return self.shapes.pop(index)
|
|
|
|
def DeleteAllShapes(self):
|
|
del self.shapes[:]
|
|
return
|
|
|
|
def ChangeShapeOrder(self, shape, pos=0):
|
|
self.shapes.remove(shape)
|
|
self.shapes.insert(pos, shape)
|
|
return
|
|
|
|
def GetCount(self):
|
|
return len(self.shapes)
|
|
|
|
def GetShapeList(self):
|
|
return self.shapes
|
|
|
|
|
|
class ShapeEvtHandler():
|
|
|
|
def OnLeftUp(self, event):
|
|
return
|
|
|
|
def OnLeftDown(self, event):
|
|
return
|
|
|
|
def OnLeftDClick(self, event):
|
|
return
|
|
|
|
def OnRightUp(self, event):
|
|
return
|
|
|
|
def OnRightDown(self, event):
|
|
return
|
|
|
|
def OnRightDClick(self, event):
|
|
return
|
|
|
|
def OnSelect(self, event):
|
|
return
|
|
|
|
def OnDeselect(self, event):
|
|
return
|
|
|
|
def OnMove(self, event):
|
|
return
|
|
|
|
def OnResize(self, event):
|
|
return
|
|
|
|
def OnConnect(self, event):
|
|
return
|
|
|
|
|
|
class Shape(ShapeEvtHandler):
|
|
|
|
def __init__(self, x=[], y=[]):
|
|
self.x = x
|
|
self.y = y
|
|
self.pen = ['BLACK', 1]
|
|
self.fill = ['WHITE']
|
|
self.name = None
|
|
self.visible = True
|
|
return
|
|
|
|
def draw(self, dc):
|
|
dc.SetPen(wx.Pen(self.pen[0], self.pen[1], wx.SOLID))
|
|
dc.SetBrush(wx.Brush(self.fill[0], len(self.fill) >= 2 and self.fill[1] or wx.SOLID))
|
|
return
|
|
|
|
def move(self, x, y):
|
|
self.x = map((lambda v: v + x), self.x)
|
|
self.y = map((lambda v: v + y), self.y)
|
|
return
|
|
|
|
def Copy(self):
|
|
return copy.deepcopy(self)
|
|
|
|
|
|
class LineShape(Shape):
|
|
|
|
def __init__(self, x1=20, y1=20, x2=50, y2=50):
|
|
Shape.__init__(self, [x1, x2], [y1, y2])
|
|
return
|
|
|
|
def draw(self, dc):
|
|
Shape.draw(self, dc)
|
|
dc.DrawLine(self.x[0], self.y[0], self.x[1], self.y[1])
|
|
return
|
|
|
|
def HitTest(self, x, y):
|
|
if x < min(self.x) - 3:
|
|
return False
|
|
if x > max(self.x) + 3:
|
|
return False
|
|
if y < min(self.y) - 3:
|
|
return False
|
|
if y > max(self.y) + 3:
|
|
return False
|
|
top = (x - self.x[0]) * (self.x[1] - self.x[0]) + (y - self.y[0]) * (self.y[1] - self.y[0])
|
|
distsqr = pow(self.x[0] - self.x[1], 2) + pow(self.y[0] - self.y[1], 2)
|
|
u = float(top) / float(distsqr)
|
|
newx = self.x[0] + u * (self.x[1] - self.x[0])
|
|
newy = self.y[0] + u * (self.y[1] - self.y[0])
|
|
dist = pow(pow(newx - x, 2) + pow(newy - y, 2), 0.5)
|
|
if dist > 7:
|
|
return False
|
|
return True
|
|
|
|
|
|
class RectangleShape(Shape):
|
|
|
|
def __init__(self, x=20, y=20, x2=90, y2=90):
|
|
Shape.__init__(self, [x, x2], [y, y2])
|
|
return
|
|
|
|
def draw(self, dc, num, pos, line1='', line2='', line3='', enabled=True):
|
|
Shape.draw(self, dc)
|
|
dc.SetBrush(self.brush)
|
|
dc.DrawRectangle(int(self.x[0]), int(self.y[0]), int(self.x[1] - self.x[0]), int(self.y[1] - self.y[0]))
|
|
(w, h) = dc.GetTextExtent(num)
|
|
mx = self.x[0] + pos[0]
|
|
my = self.y[0] + pos[1]
|
|
if line1 == '' and line2 == '' and line3 == '':
|
|
dc.SetTextForeground(self.pen[0])
|
|
dc.DrawText(num, mx, my)
|
|
else:
|
|
if enabled == True:
|
|
dc.SetTextForeground('white')
|
|
else:
|
|
dc.SetTextForeground('red')
|
|
font = one_unit.app.font
|
|
dc.SetFont(font)
|
|
if pos[1] >= 0:
|
|
dc.DrawText(line1, self.x[0] - len(line1) * 3, my + 2)
|
|
dc.DrawText(line2, self.x[0] - len(line2) * 3, my + 16)
|
|
dc.DrawText(line3, self.x[0] - len(line3) * 3, my + 30)
|
|
else:
|
|
dc.DrawText(line1, self.x[0] - len(line1) * 3, my - 2)
|
|
dc.DrawText(line2, self.x[0] - len(line2) * 3, my - 16)
|
|
dc.DrawText(line3, self.x[0] - len(line3) * 3, my - 30)
|
|
return
|
|
|
|
def HitTest(self, x, y):
|
|
"""Check if the point (x, y) is contained within the shape."""
|
|
if x < self.x[0]:
|
|
return False
|
|
if x > self.x[1]:
|
|
return False
|
|
if y < self.y[0]:
|
|
return False
|
|
if y > self.y[1]:
|
|
return False
|
|
return True
|
|
|
|
def contains(self, other):
|
|
return other.x[0] >= self.x[0] and other.x[1] <= self.x[1] and other.y[0] >= self.y[0] and other.y[1] <= self.y[1]
|
|
|
|
|
|
class TriangleRightShape(Shape):
|
|
|
|
def __init__(self, x=20, y=20, x2=90, y2=90):
|
|
Shape.__init__(self, [x, x2], [y, y2])
|
|
self.size = x2 - x
|
|
return
|
|
|
|
def draw(self, dc, num, pos, line1='', line2='', line3='', enabled=True):
|
|
Shape.draw(self, dc)
|
|
dc.SetBrush(self.brush)
|
|
dc.DrawPolygon([(self.x[0] + 5 + self.size, self.y[0]), (self.x[0] + 5, self.y[0]), (self.x[0] + 5, self.y[0] + self.size)])
|
|
(w, h) = dc.GetTextExtent(num)
|
|
mx = self.x[0] + pos[0]
|
|
my = self.y[0] + pos[1]
|
|
dc.SetTextForeground(self.pen[0])
|
|
dc.DrawText(num, mx, my)
|
|
return
|
|
|
|
def HitTest(self, x, y):
|
|
"""Check if the point (x, y) is contained within the shape."""
|
|
if x < self.x[0] + 5:
|
|
return False
|
|
if x > self.x[1] + 5:
|
|
return False
|
|
if y < self.y[0]:
|
|
return False
|
|
if y > self.y[1]:
|
|
return False
|
|
return True
|
|
|
|
def contains(self, other):
|
|
return other.x[0] >= self.x[0] and other.x[1] <= self.x[1] and other.y[0] >= self.y[0] and other.y[1] <= self.y[1]
|
|
|
|
|
|
class TriangleLeftShape(Shape):
|
|
|
|
def __init__(self, x=20, y=20, x2=90, y2=90):
|
|
Shape.__init__(self, [x, x2], [y, y2])
|
|
self.size = x2 - x
|
|
return
|
|
|
|
def draw(self, dc, num, pos, line1='', line2='', line3='', enabled=True):
|
|
Shape.draw(self, dc)
|
|
dc.SetBrush(self.brush)
|
|
dc.DrawPolygon([(self.x[0] - 5, self.y[0]), (self.x[0] + self.size - 5, self.y[0]), (self.x[0] + self.size - 5, self.y[0] + self.size)])
|
|
(w, h) = dc.GetTextExtent(num)
|
|
mx = self.x[0] + pos[0]
|
|
my = self.y[0] + pos[1]
|
|
dc.SetTextForeground(self.pen[0])
|
|
dc.DrawText(num, mx, my)
|
|
return
|
|
|
|
def HitTest(self, x, y):
|
|
"""Check if the point (x, y) is contained within the shape."""
|
|
if x < self.x[0] - 5:
|
|
return False
|
|
if x > self.x[1] - 5:
|
|
return False
|
|
if y < self.y[0]:
|
|
return False
|
|
if y > self.y[1]:
|
|
return False
|
|
return True
|
|
|
|
def contains(self, other):
|
|
return other.x[0] >= self.x[0] and other.x[1] <= self.x[1] and other.y[0] >= self.y[0] and other.y[1] <= self.y[1]
|
|
|
|
|
|
class PointShape(Shape):
|
|
|
|
def __init__(self, x=20, y=20, size=4, type='rect', num='', pos=(0, 0), line1='', line2='', line3='', enabled=True, readOnly=False):
|
|
Shape.__init__(self, [x], [y])
|
|
self.type = type
|
|
self.num = num
|
|
self.readOnly = readOnly
|
|
self.pos = pos
|
|
self.line1 = line1
|
|
self.line2 = line2
|
|
self.line3 = line3
|
|
self.enabled = enabled
|
|
self.size = size
|
|
if self.type == 'rect':
|
|
self.graphic = RectangleShape(x - size, y - size, x + size, y + size)
|
|
if self.type == 'triangle_right':
|
|
self.graphic = TriangleRightShape(x - size, y - size, x + size, y + size)
|
|
if self.type == 'triangle_left':
|
|
self.graphic = TriangleLeftShape(x - size, y - size, x + size, y + size)
|
|
self.graphic.pen = self.pen
|
|
self.graphic.fill = self.fill
|
|
return
|
|
|
|
def moveto(self, x, y, pos, line1='', line2='', line3='', enabled=True):
|
|
self.pos = pos
|
|
self.line1 = line1
|
|
self.line2 = line2
|
|
self.line3 = line3
|
|
self.enabled = enabled
|
|
self.x = [x]
|
|
self.y = [y]
|
|
size = self.size
|
|
self.graphic.x = [x - size, x + size]
|
|
self.graphic.y = [y - size, y + size]
|
|
return
|
|
|
|
def move(self, x, y):
|
|
self.x = [x]
|
|
self.y = [y]
|
|
size = self.size
|
|
self.graphic.x = [x - size, x + size]
|
|
self.graphic.y = [y - size, y + size]
|
|
return
|
|
|
|
def HitTest(self, x, y):
|
|
if self.readOnly:
|
|
return False
|
|
return self.graphic.HitTest(x, y)
|
|
|
|
def draw(self, dc):
|
|
self.graphic.pen = self.pen
|
|
self.graphic.brush = self.brush
|
|
self.graphic.fill = self.fill
|
|
self.graphic.draw(dc, self.num, self.pos, self.line1, self.line2, self.line3, self.enabled)
|
|
return
|
|
|
|
|
|
class ShapeCanvas(wx.ScrolledWindow):
|
|
|
|
def __init__(self, parent, id=-1, pos=(-1, -1), size=(-1, -1), style=0, name=''):
|
|
wx.ScrolledWindow.__init__(self, parent, id, pos, size, style, name)
|
|
self.diagram = None
|
|
self.nodes = []
|
|
self.currentPoint = [0, 0]
|
|
self.selectedShapes = []
|
|
self.scalex = 1.0
|
|
self.scaley = 1.0
|
|
self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
|
|
wx.EVT_PAINT(self, self.onPaintEvent)
|
|
wx.EVT_LEFT_DOWN(self, self.OnLeftDown)
|
|
wx.EVT_LEFT_UP(self, self.OnLeftUp)
|
|
wx.EVT_LEFT_DCLICK(self, self.OnLeftDClick)
|
|
wx.EVT_RIGHT_DOWN(self, self.OnRightDown)
|
|
wx.EVT_RIGHT_UP(self, self.OnRightUp)
|
|
wx.EVT_RIGHT_DCLICK(self, self.OnRightDClick)
|
|
wx.EVT_MOTION(self, self.OnMotion)
|
|
self.bg_drawn = False
|
|
wx.EVT_KEY_UP(self, self.OnKeyUp)
|
|
return
|
|
|
|
def OnKeyUp(self, event):
|
|
if event.GetKeyCode() == wx.WXK_SHIFT:
|
|
self.shift_down = False
|
|
elif event.GetKeyCode() == wx.WXK_CONTROL:
|
|
self.ctrl_down = False
|
|
elif event.GetKeyCode() == wx.WXK_ALT:
|
|
self.alt_down = False
|
|
return
|
|
|
|
def SaveFile(self, path='', filename=''):
|
|
if file is None:
|
|
return
|
|
else:
|
|
dcSource = wx.ClientDC(self)
|
|
size = dcSource.Size
|
|
bmp = wx.EmptyBitmap(size.width, size.height)
|
|
memDC = wx.MemoryDC()
|
|
memDC.SelectObject(bmp)
|
|
memDC.Blit(0, 0, size.width, size.height, dcSource, 0, 0)
|
|
memDC.SelectObject(wx.NullBitmap)
|
|
wildcard = 'PNG File (*.PNG)|*.PNG'
|
|
dlg = wx.FileDialog(self, message='Save as....', defaultDir=path, defaultFile=filename, wildcard=wildcard, style=wx.SAVE | wx.CHANGE_DIR)
|
|
if dlg.ShowModal() == wx.ID_OK:
|
|
path = dlg.GetPath()
|
|
if path:
|
|
img = bmp.ConvertToImage()
|
|
img.SaveFile(path, wx.BITMAP_TYPE_PNG)
|
|
print mytime.displayTime() + ' saved as', path
|
|
return
|
|
|
|
def AddShape(self, shape, after=None):
|
|
self.diagram.AddShape(shape, after)
|
|
return
|
|
|
|
def AppendShape(self, shape):
|
|
self.diagram.AppendShape(shape)
|
|
return
|
|
|
|
def InsertShape(self, shape, index=0):
|
|
self.diagram.InsertShape(shape, index)
|
|
return
|
|
|
|
def DeleteShape(self, shape):
|
|
self.diagram.DeleteShape(shape)
|
|
return
|
|
|
|
def RemoveShape(self, shape):
|
|
self.diagram.DeleteShape(shape)
|
|
return
|
|
|
|
def keyPress(self, event):
|
|
key = event.GetKeyCode()
|
|
return
|
|
|
|
def onPaintEvent(self, event):
|
|
dc = wx.PaintDC(self)
|
|
self.PrepareDC(dc)
|
|
if self.bg_drawn == False:
|
|
(w, h) = self.GetClientSizeTuple()
|
|
self.w = w
|
|
self.h = h
|
|
bmp = wx.EmptyBitmap(w, h)
|
|
mem_dc = wx.MemoryDC()
|
|
mem_dc.SelectObject(bmp)
|
|
gcdc = wx.GCDC(mem_dc)
|
|
gcdc.SetDeviceOrigin(0, 0)
|
|
gcdc.SetUserScale(self.scalex, self.scaley)
|
|
gcdc.BeginDrawing()
|
|
gcdc.SetBackground(wx.BLACK_BRUSH)
|
|
gcdc.Clear()
|
|
for item in self.diagram.shapes + self.nodes:
|
|
try:
|
|
if item.name != 'bg':
|
|
continue
|
|
except:
|
|
continue
|
|
|
|
item.draw(gcdc)
|
|
|
|
gcdc.EndDrawing()
|
|
rc = dc.Blit(0, 0, w, h, mem_dc, 0, 0)
|
|
self.bg_drawn = True
|
|
self.bg_buffer = bmp.ConvertToImage()
|
|
mem_dc.SelectObject(wx.NullBitmap)
|
|
bmp = wx.BitmapFromImage(self.bg_buffer)
|
|
mem_dc = wx.MemoryDC(bmp)
|
|
gcdc = wx.GCDC(mem_dc)
|
|
gcdc.SetDeviceOrigin(0, 0)
|
|
gcdc.SetUserScale(self.scalex, self.scaley)
|
|
gcdc.BeginDrawing()
|
|
gcdc.Clear()
|
|
for item in self.diagram.shapes + self.nodes:
|
|
if item.visible == False:
|
|
continue
|
|
try:
|
|
if item.name == 'bg':
|
|
continue
|
|
except:
|
|
pass
|
|
|
|
item.draw(gcdc)
|
|
|
|
gcdc.EndDrawing()
|
|
rc = dc.Blit(0, 0, self.w, self.h, mem_dc, 0, 0)
|
|
if (self.left_down == True or self.right_selected_node != None) and callable(self.change_handler):
|
|
self.change_handler(self)
|
|
return
|
|
|
|
def OnRightDown(self, event):
|
|
try:
|
|
self.getCurrentShape(event).OnRightDown(event)
|
|
except:
|
|
pass
|
|
|
|
return
|
|
|
|
def OnRightUp(self, event):
|
|
try:
|
|
self.getCurrentShape(event).OnRightUp(event)
|
|
except:
|
|
pass
|
|
|
|
return
|
|
|
|
def OnRightDClick(self, event):
|
|
try:
|
|
self.getCurrentShape(event).OnRightDClick(event)
|
|
except:
|
|
pass
|
|
|
|
return
|
|
|
|
def OnLeftDClick(self, event):
|
|
try:
|
|
self.getCurrentShape(event).OnLeftDClick(event)
|
|
except:
|
|
pass
|
|
|
|
return
|
|
|
|
def OnLeftDown(self, event):
|
|
item = self.getCurrentShape(event)
|
|
if item is None:
|
|
self.deselect()
|
|
return
|
|
else:
|
|
item.OnLeftDown(event)
|
|
if isinstance(item, Selectable):
|
|
if not event.ShiftDown():
|
|
self.deselect()
|
|
self.select(item)
|
|
self.Refresh()
|
|
return
|
|
|
|
def OnLeftUp(self, event):
|
|
try:
|
|
shape = self.getCurrentShape(event)
|
|
shape.OnLeftUp(event)
|
|
shape.leftUp(self.select())
|
|
except:
|
|
pass
|
|
|
|
self.Refresh()
|
|
return
|
|
|
|
def OnMotion(self, event):
|
|
if event.Dragging():
|
|
point = self.getEventCoordinates(event)
|
|
x = point[0] - self.currentPoint[0]
|
|
y = point[1] - self.currentPoint[1]
|
|
for i in self.getSelectedShapes():
|
|
i.move(x, y)
|
|
|
|
self.currentPoint = point
|
|
self.Refresh()
|
|
return
|
|
|
|
def OnDragCenterNode(self, point):
|
|
x = point[0]
|
|
y = point[1]
|
|
for i in self.getSelectedShapes():
|
|
i.move(x, y)
|
|
|
|
self.currentPoint = point
|
|
self.Refresh()
|
|
return
|
|
|
|
def SetDiagram(self, diagram):
|
|
self.diagram = diagram
|
|
return
|
|
|
|
def getCurrentShape(self, event):
|
|
point = self.getEventCoordinates(event)
|
|
self.currentPoint = point
|
|
for item in self.nodes + self.diagram.shapes:
|
|
if item.HitTest(point[0], point[1]):
|
|
return item
|
|
|
|
return
|
|
|
|
def getEventCoordinates(self, event):
|
|
(originX, originY) = self.GetViewStart()
|
|
(unitX, unitY) = self.GetScrollPixelsPerUnit()
|
|
return [(event.GetX() + originX * unitX) / self.scalex, (event.GetY() + originY * unitY) / self.scaley]
|
|
|
|
def getSelectedShapes(self):
|
|
return self.selectedShapes
|
|
|
|
def deselect(self, item=None):
|
|
if item is None:
|
|
for s in self.selectedShapes:
|
|
s.OnDeselect(None)
|
|
|
|
del self.selectedShapes[:]
|
|
del self.nodes[:]
|
|
else:
|
|
self.nodes = [_[1] for n in self.nodes if n.item != item]
|
|
self.selectedShapes = [_[2] for n in self.selectedShapes if n != item]
|
|
item.OnDeselect(None)
|
|
return
|
|
|
|
def select(self, item=None):
|
|
if item is None:
|
|
return self.selectedShapes
|
|
else:
|
|
if isinstance(item, Node):
|
|
del self.selectedShapes[:]
|
|
self.selectedShapes.append(item)
|
|
return
|
|
if item not in self.selectedShapes:
|
|
self.selectedShapes.append(item)
|
|
item.OnSelect(None)
|
|
if isinstance(item, Connectable):
|
|
self.nodes.extend([_[1] for n in range(item.input)])
|
|
self.nodes.extend([_[2] for n in range(item.output)])
|
|
if isinstance(item, Resizeable):
|
|
self.nodes.extend([_[3] for n in range(len(item.x))])
|
|
return
|
|
|
|
def showOutputs(self, item=None):
|
|
if item:
|
|
self.nodes.extend([_[1] for n in range(item.output)])
|
|
elif item is None:
|
|
for i in self.diagram.shapes:
|
|
if isinstance(i, Connectable):
|
|
self.nodes.extend([_[2] for n in range(i.output)])
|
|
|
|
return
|
|
|
|
def showInputs(self, item=None):
|
|
if isinstance(item, Block):
|
|
self.nodes.extend([_[1] for n in range(item.input)])
|
|
else:
|
|
for i in self.diagram.shapes:
|
|
if isinstance(i, Connectable):
|
|
self.nodes.extend([_[2] for n in range(i.input)])
|
|
|
|
return
|
|
|
|
|
|
class Selectable():
|
|
"""
|
|
Allows Shape to be selected
|
|
"""
|
|
|
|
def __init__(self):
|
|
self.saved_pen = None
|
|
return
|
|
|
|
|
|
class Resizeable():
|
|
"""
|
|
Creates resize Nodes that can be drug around the canvas
|
|
to alter the shape or size of the Shape
|
|
"""
|
|
|
|
def __init__(self):
|
|
return
|
|
|
|
|
|
class Connectable():
|
|
"""
|
|
Creates connection nodes or ports
|
|
"""
|
|
|
|
def __init__(self):
|
|
self.input = 1
|
|
self.output = 3
|
|
self.connections = []
|
|
return
|
|
|
|
def getPort(self, type, num):
|
|
if type == 'input':
|
|
div = float(self.input + 1.0)
|
|
x = self.x[0]
|
|
elif type == 'output':
|
|
div = float(self.output + 1.0)
|
|
x = self.x[1]
|
|
dy = float(self.y[1] - self.y[0]) / div
|
|
y = self.y[0] + dy * (num + 1)
|
|
return (x, y)
|
|
|
|
|
|
class Attributable():
|
|
"""
|
|
Allows AttributeEditor to edit specified properties
|
|
of the Shape
|
|
"""
|
|
|
|
def __init__(self):
|
|
self.attributes = []
|
|
return
|
|
|
|
def AddAttribute(self, name):
|
|
self.attributes.append(name)
|
|
return
|
|
|
|
def AddAttributes(self, atts):
|
|
self.attributes.extend(atts)
|
|
return
|
|
|
|
def RemoveAttribute(self, name):
|
|
self.attributes.remove(name)
|
|
return
|
|
|
|
|
|
class LinesShape(Shape, Resizeable):
|
|
|
|
def __init__(self, points):
|
|
Shape.__init__(self)
|
|
self.x = []
|
|
self.y = []
|
|
for p in points:
|
|
self.x.append(p[0])
|
|
self.y.append(p[1])
|
|
|
|
return
|
|
|
|
def draw(self, dc):
|
|
Shape.draw(self, dc)
|
|
ind = 0
|
|
try:
|
|
while 1:
|
|
dc.DrawLine(self.x[ind], self.y[ind], self.x[ind + 1], self.y[ind + 1])
|
|
ind = ind + 1
|
|
|
|
except:
|
|
pass
|
|
|
|
return
|
|
|
|
def HitTest(self, x, y):
|
|
if x < min(self.x) - 3:
|
|
return False
|
|
if x > max(self.x) + 3:
|
|
return False
|
|
if y < min(self.y) - 3:
|
|
return False
|
|
if y > max(self.y) + 3:
|
|
return False
|
|
ind = 0
|
|
try:
|
|
while 1:
|
|
x1 = self.x[ind]
|
|
y1 = self.y[ind]
|
|
x2 = self.x[ind + 1]
|
|
y2 = self.y[ind + 1]
|
|
top = (x - x1) * (x2 - x1) + (y - y1) * (y2 - y1)
|
|
distsqr = pow(x1 - x2, 2) + pow(y1 - y2, 2)
|
|
u = float(top) / float(distsqr)
|
|
newx = x1 + u * (x2 - x1)
|
|
newy = y1 + u * (y2 - y1)
|
|
dist = pow(pow(newx - x, 2) + pow(newy - y, 2), 0.5)
|
|
if dist < 7:
|
|
return True
|
|
ind = ind + 1
|
|
|
|
except IndexError:
|
|
pass
|
|
|
|
return False
|
|
|
|
|
|
class ConnectionShape(LineShape, Resizeable, Selectable, Attributable):
|
|
|
|
def __init__(self):
|
|
LineShape.__init__(self)
|
|
Resizeable.__init__(self)
|
|
Attributable.__init__(self)
|
|
self.AddAttributes(['pen'])
|
|
self.input = None
|
|
self.output = None
|
|
return
|
|
|
|
def setInput(self, item, index):
|
|
self.input = (item, index)
|
|
return
|
|
|
|
def setOutput(self, item, index):
|
|
self.output = (item, index)
|
|
return
|
|
|
|
def draw(self, dc):
|
|
if self.input:
|
|
(self.x[0], self.y[0]) = self.input[0].getPort('output', self.input[1])
|
|
if self.output:
|
|
(self.x[1], self.y[1]) = self.output[0].getPort('input', self.output[1])
|
|
LineShape.draw(self, dc)
|
|
return
|
|
|
|
def OnRightDown(self, event):
|
|
f = AttributeEditor(None, -1, 'props', self)
|
|
f.Show(True)
|
|
return
|
|
|
|
|
|
class Block(RectangleShape, Connectable, Resizeable, Selectable, Attributable):
|
|
|
|
def __init__(self):
|
|
RectangleShape.__init__(self)
|
|
Resizeable.__init__(self)
|
|
Connectable.__init__(self)
|
|
Attributable.__init__(self)
|
|
self.AddAttributes([1, 2, 3, 4, 5])
|
|
self.label = 'Block'
|
|
return
|
|
|
|
def draw(self, dc):
|
|
RectangleShape.draw(self, dc)
|
|
(w, h) = dc.GetTextExtent(self.label)
|
|
mx = self.x[0] + 1
|
|
my = self.y[0] + 1
|
|
dc.DrawText(self.label, mx, my)
|
|
return
|
|
|
|
def OnLeftDown(self, event):
|
|
if isinstance(self, Block) and event.ControlDown():
|
|
d = wx.TextEntryDialog(None, 'Block Label', defaultValue=self.label, style=wx.OK)
|
|
d.ShowModal()
|
|
self.label = d.GetValue()
|
|
return
|
|
|
|
def OnRightDown(self, event):
|
|
f = AttributeEditor(None, -1, 'props', self)
|
|
f.Show(True)
|
|
return
|
|
|
|
def OnSelect(self, event):
|
|
self.saved_pen = self.pen
|
|
self.pen = ['MAGENTA', 2]
|
|
return
|
|
|
|
def OnDeselect(self, event):
|
|
self.pen = self.saved_pen
|
|
return
|
|
|
|
|
|
class CodeBlock(Block):
|
|
|
|
def __init__(self):
|
|
Block.__init__(self)
|
|
self.AddAttribute('code')
|
|
self.code = ''
|
|
self.label = 'Code'
|
|
return
|
|
|
|
def OnLeftDClick(self, event):
|
|
return
|
|
|
|
|
|
class ContainerBlock(Block, Diagram):
|
|
|
|
def __init__(self):
|
|
Block.__init__(self)
|
|
Diagram.__init__(self)
|
|
self.label = 'Container'
|
|
self.pen = ['BLACK', 2]
|
|
self.fill = ['GREEN']
|
|
return
|
|
|
|
def OnLeftDClick(self, event):
|
|
return
|
|
|
|
|
|
class Node(PointShape):
|
|
|
|
def __init__(self, item, index, cf):
|
|
self.item = item
|
|
self.index = index
|
|
self.cf = cf
|
|
PointShape.__init__(self)
|
|
return
|
|
|
|
def showProperties(self):
|
|
self.item.showProperties()
|
|
return
|
|
|
|
|
|
class ConnectableNode(Node):
|
|
|
|
def __init__(self, item, index, cf):
|
|
Node.__init__(self, item, index, cf)
|
|
return
|
|
|
|
|
|
class INode(ConnectableNode):
|
|
|
|
def __init__(self, item, index, cf):
|
|
ConnectableNode.__init__(self, item, index, cf)
|
|
return
|
|
|
|
def leftUp(self, items):
|
|
if len(items) == 1 and isinstance(items[0], ConnectionShape):
|
|
if items[0].output is None:
|
|
items[0].setOutput(self.item, self.index)
|
|
return
|
|
|
|
def move(self, x, y):
|
|
self.cf.deselect()
|
|
ci = ConnectionShape()
|
|
self.cf.container.shapes.insert(0, ci)
|
|
ci.setOutput(self.item, self.index)
|
|
(ci.x[0], ci.y[0]) = self.item.getPort('input', self.index)
|
|
self.cf.showOutputs()
|
|
self.cf.select(ci)
|
|
return
|
|
|
|
def draw(self, dc):
|
|
(x, y) = self.item.getPort('input', self.index)
|
|
self.moveto(x, y)
|
|
PointShape.draw(self, dc)
|
|
return
|
|
|
|
|
|
class ONode(ConnectableNode):
|
|
|
|
def __init__(self, item, index, cf):
|
|
ConnectableNode.__init__(self, item, index, cf)
|
|
return
|
|
|
|
def move(self, x, y):
|
|
self.cf.deselect()
|
|
ci = ConnectionShape()
|
|
self.cf.diagram.shapes.insert(0, ci)
|
|
ci.setInput(self.item, self.index)
|
|
(ci.x[1], ci.y[1]) = self.item.getPort('output', self.index)
|
|
self.cf.showInputs()
|
|
self.cf.select(ci)
|
|
return
|
|
|
|
def leftUp(self, items):
|
|
if len(items) == 1 and isinstance(items[0], ConnectionShape):
|
|
if items[0].input is None:
|
|
items[0].setInput(self.item, self.index)
|
|
return
|
|
|
|
def draw(self, dc):
|
|
(x, y) = self.item.getPort('output', self.index)
|
|
self.moveto(x, y)
|
|
PointShape.draw(self, dc)
|
|
return
|
|
|
|
|
|
class ResizeableNode(Node):
|
|
|
|
def __init__(self, item, index, cf):
|
|
Node.__init__(self, item, index, cf)
|
|
self.fill = ['BLACK']
|
|
return
|
|
|
|
def draw(self, dc):
|
|
item = self.item
|
|
index = self.index
|
|
self.moveto(item.x[index], item.y[index])
|
|
PointShape.draw(self, dc)
|
|
return
|
|
|
|
def move(self, x, y):
|
|
self.item.x[self.index] += x
|
|
self.item.y[self.index] += y
|
|
return
|
|
|
|
|
|
class AttributeEditor(wx.Frame):
|
|
|
|
def __init__(self, parent, ID, title, item):
|
|
wx.Frame.__init__(self, parent, ID, title, wx.DefaultPosition, wx.Size(200, 450))
|
|
self.item = item
|
|
box = wx.BoxSizer(wx.VERTICAL)
|
|
self.SetSizer(box)
|
|
tID = wx.NewId()
|
|
self.list = wx.ListCtrl(self, tID, wx.DefaultPosition, wx.DefaultSize, wx.LC_REPORT)
|
|
self.SetSize(self.GetSize())
|
|
self.list.InsertColumn(0, 'Attribute')
|
|
self.list.InsertColumn(1, 'Value')
|
|
accept = wx.Button(self, wx.NewId(), 'Accept', size=(40, 20))
|
|
for c in range(len(item.attributes)):
|
|
self.list.InsertStringItem(c, '')
|
|
self.list.SetStringItem(c, 0, str(item.attributes[c]))
|
|
temp = str(eval('item.' + str(item.attributes[c])))
|
|
self.list.SetStringItem(c, 1, temp)
|
|
|
|
self.text = wx.TextCtrl(self, wx.NewId(), '', style=wx.TE_MULTILINE)
|
|
box.Add(self.list, 1, wx.EXPAND)
|
|
box.Add(accept, 0, wx.EXPAND)
|
|
box.Add(self.text, 1, wx.EXPAND)
|
|
wx.EVT_LIST_ITEM_SELECTED(self.list, tID, self.selectProp)
|
|
wx.EVT_BUTTON(accept, accept.GetId(), self.acceptProp)
|
|
return
|
|
|
|
def selectProp(self, event):
|
|
idx = self.list.GetFocusedItem()
|
|
prop = self.list.GetItem(idx, 0).GetText()
|
|
val = self.list.GetItem(idx, 1).GetText()
|
|
self.text.Clear()
|
|
self.text.WriteText(val)
|
|
return
|
|
|
|
def acceptProp(self, event):
|
|
idx = self.list.GetFocusedItem()
|
|
prop = self.list.GetItem(idx, 0).GetText()
|
|
lines = self.text.GetNumberOfLines()
|
|
if lines == 1:
|
|
exec 'self.item.' + prop + '=' + self.text.GetValue()
|
|
else:
|
|
p = setattr(self.item, prop, self.text.GetValue())
|
|
self.list.SetStringItem(idx, 1, str(getattr(self.item, prop)))
|
|
return
|
|
|
|
|
|
class CodeFrame(wx.Frame):
|
|
|
|
def __init__(self, diagram):
|
|
wx.Frame.__init__(self, None, -1, 'Untitled', size=(500, 300))
|
|
self.file = None
|
|
menus = {}
|
|
menus['&Add'] = [
|
|
(
|
|
'Code', 'Block that holds code', self.newCodeBlock),
|
|
(
|
|
'Container', 'Block that holds blocks', self.newContBlock),
|
|
(
|
|
'Point', 'Playing with points', self.newPointShape),
|
|
(
|
|
'Lines', 'Plotting', self.newLinesShape)]
|
|
menus['&Zoom'] = [
|
|
(
|
|
'Zoom In\tCtrl+o', 'zoom in', self.zoomin),
|
|
(
|
|
'Zoom Out\tCtrl+p', 'zoom out', self.zoomout)]
|
|
menuMaker(self, menus)
|
|
self.canvas = ShapeCanvas(self, -1)
|
|
self.canvas.SetDiagram(diagram)
|
|
self.canvas.SetBackgroundColour(wx.WHITE)
|
|
self.Show(True)
|
|
return
|
|
|
|
def zoomin(self, event):
|
|
self.canvas.scalex = max(self.canvas.scalex + 0.05, 0.3)
|
|
self.canvas.scaley = max(self.canvas.scaley + 0.05, 0.3)
|
|
self.canvas.Refresh()
|
|
return
|
|
|
|
def zoomout(self, event):
|
|
self.canvas.scalex = self.canvas.scalex - 0.05
|
|
self.canvas.scaley = self.canvas.scaley - 0.05
|
|
self.canvas.Refresh()
|
|
return
|
|
|
|
def newCodeBlock(self, event):
|
|
i = CodeBlock()
|
|
self.canvas.AddShape(i)
|
|
self.canvas.deselect()
|
|
self.canvas.Refresh()
|
|
return
|
|
|
|
def newContBlock(self, event):
|
|
i = ContainerBlock()
|
|
self.canvas.AddShape(i)
|
|
self.canvas.deselect()
|
|
self.canvas.Refresh()
|
|
return
|
|
|
|
def newPointShape(self, event):
|
|
i = PointShape(50, 50)
|
|
self.canvas.AddShape(i)
|
|
self.canvas.deselect()
|
|
self.canvas.Refresh()
|
|
return
|
|
|
|
def newLinesShape(self, event):
|
|
points = [
|
|
27, 28, 29, 30, 31,
|
|
32, 33, 34,
|
|
35, 36,
|
|
37, 38, 39, 40, 41,
|
|
42,
|
|
43, 44, 45, 46,
|
|
47, 48, 49, 50, 51]
|
|
i = LinesShape(points)
|
|
self.canvas.AddShape(i)
|
|
self.canvas.deselect()
|
|
self.canvas.Refresh()
|
|
return
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
class MyApp(wx.App):
|
|
|
|
def OnInit(self):
|
|
frame = CodeFrame(ContainerBlock())
|
|
return True
|
|
|
|
|
|
app = MyApp(0)
|
|
app.MainLoop()
|
|
|
|
# okay decompiling pycode/MyOGLlike.pyc
|