1 |
jpye |
1935 |
from __future__ import with_statement |
2 |
jpye |
1937 |
import os, sys |
3 |
jpye |
1929 |
|
4 |
jpye |
1937 |
os.chdir(os.path.dirname(sys.argv[0])) |
5 |
|
|
os.environ['ASCENDLIBRARY'] = "../../models" |
6 |
|
|
os.environ['LD_LIBRARY_PATH'] = "../.." |
7 |
|
|
sys.path.append("..") |
8 |
|
|
|
9 |
|
|
|
10 |
jpye |
1929 |
if sys.platform.startswith("win"): |
11 |
|
|
# Fetchs gtk2 path from registry |
12 |
|
|
import _winreg |
13 |
|
|
import msvcrt |
14 |
|
|
try: |
15 |
|
|
k = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, "Software\\GTK\\2.0") |
16 |
|
|
except EnvironmentError: |
17 |
|
|
# use TkInter to report the error :-) |
18 |
|
|
from TkInter import * |
19 |
|
|
root = Tk() |
20 |
|
|
w = Label(root,"You must install the Gtk+ 2.2 Runtime Environment to run this program") |
21 |
|
|
w.pack() |
22 |
|
|
root.mainloop() |
23 |
|
|
sys.exit(1) |
24 |
|
|
else: |
25 |
|
|
gtkdir = _winreg.QueryValueEx(k, "Path") |
26 |
|
|
import os |
27 |
|
|
# we must make sure the gtk2 path is the first thing in the path |
28 |
|
|
# otherwise, we can get errors if the system finds other libs with |
29 |
|
|
# the same name in the path... |
30 |
|
|
os.environ['PATH'] = "%s/lib;%s/bin;" % (gtkdir[0], gtkdir[0]) + os.environ['PATH'] |
31 |
|
|
|
32 |
jpye |
1801 |
import ascpy |
33 |
|
|
|
34 |
|
|
L = ascpy.Library() |
35 |
|
|
|
36 |
jpye |
1929 |
# FIXME need to add way to add/remove modules from the Library? |
37 |
|
|
L.load('test/canvas/blocktypes.a4c') |
38 |
jpye |
1801 |
|
39 |
|
|
D = L.getAnnotationDatabase() |
40 |
|
|
|
41 |
|
|
M = L.getModules() |
42 |
|
|
|
43 |
|
|
blocktypes = set() |
44 |
|
|
|
45 |
jpye |
1935 |
class Block: |
46 |
|
|
def __init__(self, typedesc, notesdb): |
47 |
|
|
self.type = typedesc |
48 |
|
|
self.notesdb = notesdb |
49 |
|
|
|
50 |
|
|
nn = notesdb.getTypeRefinedNotesLang(self.type,ascpy.SymChar("inline")) |
51 |
|
|
|
52 |
|
|
self.inputs = [] |
53 |
|
|
self.outputs = [] |
54 |
|
|
for n in nn: |
55 |
|
|
t = n.getText() |
56 |
|
|
if t[0:min(len(t),3)]=="in:": |
57 |
|
|
self.inputs += [n] |
58 |
|
|
elif t[0:min(len(t),4)]=="out:": |
59 |
|
|
self.outputs += [n] |
60 |
|
|
|
61 |
|
|
def get_icon(self, width, height): |
62 |
jpye |
1936 |
return gtk.gdk.pixbuf_new_from_file_at_size("defaultblock.svg",width,height) |
63 |
jpye |
1935 |
|
64 |
jpye |
1937 |
|
65 |
jpye |
1813 |
for m in M: |
66 |
|
|
T = L.getModuleTypes(m) |
67 |
|
|
for t in T: |
68 |
jpye |
1925 |
# 'block' types must not be parametric, because they must be able to |
69 |
|
|
# exist even without being connected, and parametric models impose |
70 |
|
|
# restrictions on the use of ARE_THE_SAME and similar. |
71 |
|
|
if t.hasParameters(): |
72 |
jpye |
1893 |
continue |
73 |
jpye |
1925 |
x = D.getNotes(t,ascpy.SymChar("block"),ascpy.SymChar("SELF")) |
74 |
|
|
if x: |
75 |
jpye |
1813 |
blocktypes.add(t) |
76 |
|
|
|
77 |
jpye |
1935 |
blocks = [] |
78 |
|
|
|
79 |
jpye |
1813 |
print "block types:" |
80 |
|
|
if not blocktypes: |
81 |
|
|
print "NONE FOUND" |
82 |
|
|
for t in blocktypes: |
83 |
|
|
|
84 |
jpye |
1935 |
b = Block(t,D) |
85 |
jpye |
1926 |
|
86 |
jpye |
1935 |
blocks += [b] |
87 |
jpye |
1925 |
|
88 |
jpye |
1935 |
print b.type.getName() |
89 |
|
|
|
90 |
|
|
print "\t\tinputs:",[n.getId() for n in b.inputs] |
91 |
|
|
for n in b.inputs: |
92 |
jpye |
1929 |
print "\t\t\t%s: %s (type = %s)" % (n.getId(),n.getText(),n.getType()) |
93 |
jpye |
1935 |
print "\t\toutputs:",[n.getId() for n in b.outputs] |
94 |
|
|
for n in b.outputs: |
95 |
jpye |
1929 |
print "\t\t\t%s: %s" % (n.getId(),n.getText()) |
96 |
jpye |
1926 |
|
97 |
jpye |
1935 |
|
98 |
|
|
# render icon table |
99 |
|
|
import threading |
100 |
|
|
import gtk |
101 |
|
|
import os, os.path, re |
102 |
jpye |
1936 |
|
103 |
|
|
import cairo |
104 |
|
|
from gaphas import GtkView, View |
105 |
|
|
from gaphas.tool import HoverTool, PlacementTool, HandleTool, ToolChain |
106 |
jpye |
1939 |
from gaphas.tool import Tool, ItemTool, RubberbandTool |
107 |
jpye |
1936 |
from port import * |
108 |
|
|
|
109 |
jpye |
1935 |
gtk.gdk.threads_init() |
110 |
|
|
|
111 |
jpye |
1937 |
class BlockIconView(gtk.IconView): |
112 |
|
|
def __init__(self,blocks,app): |
113 |
|
|
# the mode containing the icons themselves... |
114 |
|
|
self.model = gtk.ListStore(str, gtk.gdk.Pixbuf) |
115 |
|
|
self.app = app |
116 |
|
|
self.otank = {} |
117 |
|
|
thread = threading.RLock() |
118 |
|
|
n = 0 |
119 |
|
|
with thread: |
120 |
|
|
for b in blocks: |
121 |
|
|
n += 1 |
122 |
|
|
pixbuf = b.get_icon(64,64) |
123 |
|
|
iter = self.model.append([b.type.getName(), pixbuf]) |
124 |
|
|
path = self.model.get_path(iter) |
125 |
|
|
self.otank[path] = b |
126 |
|
|
|
127 |
|
|
gtk.IconView.__init__(self) |
128 |
|
|
self.set_model(self.model) |
129 |
|
|
self.set_text_column(0) |
130 |
|
|
self.set_pixbuf_column(1) |
131 |
|
|
self.set_columns(-1) |
132 |
|
|
self.set_size_request(180,100) |
133 |
|
|
self.connect("item-activated", self.item_activated) |
134 |
|
|
self.connect("selection-changed", self.selection_changed) |
135 |
|
|
def item_activated(self,iconview,path): |
136 |
|
|
b = self.otank[path] |
137 |
|
|
self.app.status.push(0, "Activated '%s'..." % b.type.getName()) |
138 |
|
|
#view.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.CROSSHAIR)) |
139 |
|
|
self.app.set_placement_tool(b) |
140 |
|
|
|
141 |
|
|
def selection_changed(self,iconview): |
142 |
|
|
s = self.get_selected_items() |
143 |
|
|
if len(s)==1: |
144 |
|
|
b = self.otank[s[0]] |
145 |
|
|
self.app.set_placement_tool(b) |
146 |
|
|
self.app.status.push(0,"Selected '%s'..." % b.type.getName()) |
147 |
|
|
|
148 |
jpye |
1939 |
class ContextMenuTool(Tool): |
149 |
|
|
""" |
150 |
|
|
Context menu for blocks and connectors on the canvas, intended to be |
151 |
|
|
the main mouse-based way by which interaction with blocks occurs (blocks |
152 |
|
|
renamed, parameters specified, values examined, etc). |
153 |
|
|
Code for performing these tasks should not be here; this should just |
154 |
|
|
hook into the appropriate code in the Application layer. |
155 |
|
|
""" |
156 |
|
|
def __init__(self): |
157 |
|
|
pass |
158 |
|
|
def on_button_press(self, context, event): |
159 |
|
|
if event.button != 3: |
160 |
|
|
return False |
161 |
|
|
if context.view.hovered_item: |
162 |
|
|
menu = gtk.Menu() |
163 |
|
|
menurename = gtk.MenuItem("Re_name",True); |
164 |
|
|
menurename.connect("activate",self.rename) |
165 |
|
|
menu.add(menurename) |
166 |
|
|
menu.show_all() |
167 |
|
|
menu.popup( None, None, None, event.button, event.time) |
168 |
|
|
|
169 |
|
|
def rename(self,widget): |
170 |
|
|
print "RENAMING OBJECT" |
171 |
|
|
|
172 |
|
|
def BlockToolChain(): |
173 |
|
|
""" |
174 |
|
|
The default tool chain build from HoverTool, ItemTool and HandleTool. |
175 |
|
|
""" |
176 |
|
|
chain = ToolChain() |
177 |
|
|
chain.append(HoverTool()) |
178 |
|
|
chain.append(PortConnectingHandleTool()) |
179 |
|
|
chain.append(ContextMenuTool()) |
180 |
|
|
chain.append(ItemTool()) |
181 |
|
|
chain.append(RubberbandTool()) |
182 |
|
|
return chain |
183 |
|
|
|
184 |
jpye |
1935 |
class app(gtk.Window): |
185 |
|
|
def __init__(self): |
186 |
jpye |
1937 |
self.status = gtk.Statusbar() |
187 |
jpye |
1936 |
|
188 |
jpye |
1937 |
# the Gaphas canvas |
189 |
jpye |
1936 |
canvas = BlockCanvas() |
190 |
|
|
|
191 |
jpye |
1937 |
# the main window |
192 |
jpye |
1935 |
gtk.Window.__init__(self) |
193 |
|
|
self.set_title("ASCEND Blocks") |
194 |
|
|
self.set_default_size(400, 500) |
195 |
|
|
self.connect("destroy", gtk.main_quit) |
196 |
jpye |
1938 |
self.connect("key-press-event", self.key_press_event) |
197 |
jpye |
1935 |
|
198 |
jpye |
1937 |
# vbox containing the main view and the status bar at the bottom |
199 |
jpye |
1935 |
vbox = gtk.VBox() |
200 |
|
|
|
201 |
jpye |
1937 |
# hbox occupies top part of vbox, with icons on left & canvas on right. |
202 |
jpye |
1936 |
hbox = gtk.HBox() |
203 |
|
|
|
204 |
jpye |
1937 |
# the 'view' widget implemented by Gaphas |
205 |
|
|
self.view = GtkView() |
206 |
jpye |
1939 |
self.view.tool = BlockToolChain() |
207 |
jpye |
1936 |
|
208 |
jpye |
1937 |
# table containing scrollbars and main canvas |
209 |
jpye |
1936 |
t = gtk.Table(2,2) |
210 |
jpye |
1937 |
self.view.canvas = canvas |
211 |
|
|
self.view.zoom(1) |
212 |
|
|
self.view.set_size_request(600, 500) |
213 |
|
|
hs = gtk.HScrollbar(self.view.hadjustment) |
214 |
|
|
vs = gtk.VScrollbar(self.view.vadjustment) |
215 |
|
|
t.attach(self.view, 0, 1, 0, 1) |
216 |
jpye |
1936 |
t.attach(hs, 0, 1, 1, 2, xoptions=gtk.FILL, yoptions=gtk.FILL) |
217 |
|
|
t.attach(vs, 1, 2, 0, 1, xoptions=gtk.FILL, yoptions=gtk.FILL) |
218 |
|
|
|
219 |
jpye |
1937 |
# a scrolling window to contain the icon palette |
220 |
|
|
scroll = gtk.ScrolledWindow() |
221 |
|
|
scroll.set_border_width(2) |
222 |
|
|
scroll.set_shadow_type(gtk.SHADOW_ETCHED_IN) |
223 |
|
|
scroll.set_policy(gtk.POLICY_AUTOMATIC,gtk.POLICY_AUTOMATIC) |
224 |
|
|
|
225 |
|
|
# icon palette |
226 |
|
|
self.blockiconview = BlockIconView(blocks, self) |
227 |
|
|
scroll.add(self.blockiconview) |
228 |
|
|
|
229 |
jpye |
1936 |
hbox.pack_start(scroll, True, True) |
230 |
|
|
hbox.pack_start(t, True, True) |
231 |
|
|
vbox.pack_start(hbox, True, True) |
232 |
jpye |
1937 |
vbox.pack_start(self.status, False, False) |
233 |
jpye |
1935 |
self.add(vbox) |
234 |
|
|
self.show_all() |
235 |
|
|
|
236 |
jpye |
1937 |
# a message about the found blocks |
237 |
|
|
self.status.push(0, "Found %d block types." % (len(blocks))) |
238 |
|
|
|
239 |
|
|
def set_placement_tool(self,block): |
240 |
jpye |
1938 |
# TODO: add undo handler |
241 |
jpye |
1937 |
label = block.type.getName() |
242 |
|
|
def my_block_factory(): |
243 |
|
|
def wrapper(): |
244 |
|
|
b = DefaultBlock(label,inputs=len(block.inputs),outputs=len(block.outputs)) |
245 |
|
|
self.view.canvas.add(b) |
246 |
|
|
return b |
247 |
|
|
return wrapper |
248 |
|
|
self.view.tool.grab(PlacementTool(my_block_factory(), HandleTool(), 2)) |
249 |
jpye |
1938 |
|
250 |
|
|
def key_press_event(self,widget,event): |
251 |
|
|
# TODO: add undo handler |
252 |
|
|
key = gtk.gdk.keyval_name(event.keyval) |
253 |
|
|
if key == 'Delete' and self.view.focused_item: |
254 |
|
|
self.view.canvas.remove(self.view.focused_item) |
255 |
|
|
self.status.push(0,"Item deleted.") |
256 |
jpye |
1935 |
|
257 |
|
|
a = app() |
258 |
|
|
gtk.main() |
259 |
|
|
|