1 |
#!/usr/bin/env python |
2 |
from __future__ import with_statement |
3 |
import os, sys |
4 |
|
5 |
os.chdir(os.path.abspath(os.path.dirname(sys.argv[0]))) |
6 |
|
7 |
os.environ['ASCENDLIBRARY'] = "../../models" |
8 |
|
9 |
if sys.platform.startswith("win"): |
10 |
os.environ['PATH'] += ";..\.." |
11 |
else: |
12 |
os.environ['LD_LIBRARY_PATH'] = "../.." |
13 |
|
14 |
sys.path.append("..") |
15 |
|
16 |
import gtkexcepthook |
17 |
|
18 |
if sys.platform.startswith("win"): |
19 |
# Fetchs gtk2 path from registry |
20 |
import _winreg |
21 |
import msvcrt |
22 |
try: |
23 |
k = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, "Software\\GTK\\2.0") |
24 |
except EnvironmentError: |
25 |
# use TkInter to report the error :-) |
26 |
from TkInter import * |
27 |
root = Tk() |
28 |
w = Label(root,"You must install the Gtk+ 2.2 Runtime Environment to run this program") |
29 |
w.pack() |
30 |
root.mainloop() |
31 |
sys.exit(1) |
32 |
else: |
33 |
gtkdir = _winreg.QueryValueEx(k, "Path") |
34 |
import os |
35 |
# we must make sure the gtk2 path is the first thing in the path |
36 |
# otherwise, we can get errors if the system finds other libs with |
37 |
# the same name in the path... |
38 |
os.environ['PATH'] = "%s/lib;%s/bin;" % (gtkdir[0], gtkdir[0]) + os.environ['PATH'] |
39 |
|
40 |
import ascpy |
41 |
|
42 |
L = ascpy.Library() |
43 |
|
44 |
# FIXME need to add way to add/remove modules from the Library? |
45 |
L.load('test/canvas/blocktypes.a4c') |
46 |
|
47 |
D = L.getAnnotationDatabase() |
48 |
|
49 |
M = L.getModules() |
50 |
|
51 |
blocktypes = set() |
52 |
|
53 |
for m in M: |
54 |
T = L.getModuleTypes(m) |
55 |
for t in T: |
56 |
# 'block' types must not be parametric, because they must be able to |
57 |
# exist even without being connected, and parametric models impose |
58 |
# restrictions on the use of ARE_THE_SAME and similar. |
59 |
if t.hasParameters(): |
60 |
continue |
61 |
x = D.getNotes(t,ascpy.SymChar("block"),ascpy.SymChar("SELF")) |
62 |
if x: |
63 |
blocktypes.add(t) |
64 |
|
65 |
blocks = [] |
66 |
|
67 |
from blocktype import * |
68 |
|
69 |
print "block types:" |
70 |
if not blocktypes: |
71 |
print "NONE FOUND" |
72 |
for t in blocktypes: |
73 |
|
74 |
b = BlockType(t,D) |
75 |
|
76 |
blocks += [b] |
77 |
|
78 |
# render icon table |
79 |
import threading |
80 |
import gtk |
81 |
import os, os.path, re |
82 |
|
83 |
import cairo |
84 |
|
85 |
#gtk.gdk.threads_init() |
86 |
|
87 |
class BlockIconView(gtk.IconView): |
88 |
""" |
89 |
IconView containing the palette of BlockTypes available for use in the |
90 |
canvas. The list of blocks is supplied currently as an initialisation |
91 |
parameter, but it is intended that this would be dynamic in a final system. |
92 |
|
93 |
It should be possible drag icons from the palette into the canvas, but |
94 |
that is not yet implemented. |
95 |
""" |
96 |
def __init__(self,blocks,app): |
97 |
# the mode containing the icons themselves... |
98 |
self.model = gtk.ListStore(str, gtk.gdk.Pixbuf) |
99 |
self.app = app |
100 |
self.otank = {} |
101 |
#thread = threading.RLock() |
102 |
n = 0 |
103 |
#with thread: |
104 |
for b in blocks: |
105 |
n += 1 |
106 |
pixbuf = b.get_icon(64,64) |
107 |
iter = self.model.append([b.type.getName(), pixbuf]) |
108 |
path = self.model.get_path(iter) |
109 |
self.otank[path] = b |
110 |
|
111 |
gtk.IconView.__init__(self) |
112 |
self.set_model(self.model) |
113 |
self.set_text_column(0) |
114 |
self.set_pixbuf_column(1) |
115 |
self.set_columns(-1) |
116 |
self.set_size_request(180,100) |
117 |
self.connect("item-activated", self.item_activated) |
118 |
self.connect("selection-changed", self.selection_changed) |
119 |
|
120 |
def selection_changed(self,iconview): |
121 |
s = self.get_selected_items() |
122 |
if len(s)==1: |
123 |
b = self.otank[s[0]] |
124 |
self.app.set_placement_tool(b) |
125 |
|
126 |
def item_activated(self,iconview, path): |
127 |
self.app.set_placement_tool(self.otank[path]) |
128 |
|
129 |
from gaphas import GtkView, View |
130 |
from gaphas.tool import HoverTool, PlacementTool, HandleTool, ToolChain |
131 |
from gaphas.tool import Tool, ItemTool, RubberbandTool |
132 |
from gaphas.item import Line |
133 |
from blockitem import * |
134 |
from contextmenutool import * |
135 |
from connectortool import * |
136 |
from portconnectinghandletool import * |
137 |
from blockcanvas import * |
138 |
from panzoom import * |
139 |
from blockinstance import * |
140 |
|
141 |
def BlockToolChain(): |
142 |
""" |
143 |
ToolChain for working with BlockCanvas, including several custom Tools. |
144 |
""" |
145 |
chain = ToolChain() |
146 |
chain.append(HoverTool()) |
147 |
chain.append(PortConnectingHandleTool()) |
148 |
chain.append(ConnectorTool()) |
149 |
chain.append(ContextMenuTool()) |
150 |
chain.append(ItemTool()) |
151 |
chain.append(ZoomTool()) |
152 |
chain.append(PanTool()) |
153 |
chain.append(RubberbandTool()) |
154 |
return chain |
155 |
|
156 |
class app(gtk.Window): |
157 |
def __init__(self): |
158 |
self.status = gtk.Statusbar() |
159 |
|
160 |
# the Gaphas canvas |
161 |
canvas = BlockCanvas() |
162 |
|
163 |
# the main window |
164 |
gtk.Window.__init__(self) |
165 |
self.set_title("ASCEND Blocks") |
166 |
self.set_default_size(400, 500) |
167 |
self.connect("destroy", gtk.main_quit) |
168 |
self.connect("key-press-event", self.key_press_event) |
169 |
|
170 |
windowicon = gtk.Image() |
171 |
windowicon.set_from_file(os.path.join("../glade/ascend.svg")) |
172 |
self.set_icon(windowicon.get_pixbuf()) |
173 |
|
174 |
# vbox containing the main view and the status bar at the bottom |
175 |
vbox = gtk.VBox() |
176 |
|
177 |
# hbox occupies top part of vbox, with icons on left & canvas on right. |
178 |
hbox = gtk.HBox() |
179 |
|
180 |
# the 'view' widget implemented by Gaphas |
181 |
self.view = GtkView() |
182 |
self.view.tool = BlockToolChain() |
183 |
|
184 |
# table containing scrollbars and main canvas |
185 |
t = gtk.Table(2,2) |
186 |
self.view.canvas = canvas |
187 |
self.view.zoom(1) |
188 |
self.view.set_size_request(600, 500) |
189 |
hs = gtk.HScrollbar(self.view.hadjustment) |
190 |
vs = gtk.VScrollbar(self.view.vadjustment) |
191 |
t.attach(self.view, 0, 1, 0, 1) |
192 |
t.attach(hs, 0, 1, 1, 2, xoptions=gtk.FILL, yoptions=gtk.FILL) |
193 |
t.attach(vs, 1, 2, 0, 1, xoptions=gtk.FILL, yoptions=gtk.FILL) |
194 |
|
195 |
# a scrolling window to contain the icon palette |
196 |
scroll = gtk.ScrolledWindow() |
197 |
scroll.set_border_width(2) |
198 |
scroll.set_shadow_type(gtk.SHADOW_ETCHED_IN) |
199 |
scroll.set_policy(gtk.POLICY_AUTOMATIC,gtk.POLICY_AUTOMATIC) |
200 |
|
201 |
# icon palette |
202 |
self.blockiconview = BlockIconView(blocks, self) |
203 |
scroll.add(self.blockiconview) |
204 |
|
205 |
hbox.pack_start(scroll, True, True) |
206 |
hbox.pack_start(t, True, True) |
207 |
vbox.pack_start(hbox, True, True) |
208 |
vbox.pack_start(self.status, False, False) |
209 |
self.add(vbox) |
210 |
self.show_all() |
211 |
|
212 |
# a message about the found blocks |
213 |
self.status.push(0, "Found %d block types." % (len(blocks))) |
214 |
|
215 |
def set_placement_tool(self,blocktype): |
216 |
# TODO: add undo handler |
217 |
label = blocktype.type.getName() |
218 |
def my_block_factory(): |
219 |
def wrapper(): |
220 |
b = BlockInstance(blocktype) |
221 |
bi = DefaultBlockItem(b) |
222 |
self.view.canvas.add(bi) |
223 |
return bi |
224 |
return wrapper |
225 |
self.view.tool.grab(PlacementTool(my_block_factory(), HandleTool(), 2)) |
226 |
self.status.push(0,"Selected '%s'..." % blocktype.type.getName()) |
227 |
|
228 |
def set_connector_tool(self): |
229 |
def my_line_factory(): |
230 |
def wrapper(): |
231 |
l = Line() |
232 |
self.view.canvas.add(l) |
233 |
return l |
234 |
return wrapper |
235 |
self.view.tool.grab(PlacementTool(my_line_factory(), HandleTool(), 1)) |
236 |
|
237 |
def key_press_event(self,widget,event): |
238 |
# TODO: add undo handler |
239 |
key = gtk.gdk.keyval_name(event.keyval) |
240 |
if key == 'Delete' and self.view.focused_item: |
241 |
self.view.canvas.remove(self.view.focused_item) |
242 |
self.status.push(0,"Item deleted.") |
243 |
elif key == 'l' or key == 'L': |
244 |
self.set_connector_tool() |
245 |
self.status.push(0,"Line draw mode...") |
246 |
elif key == 'S' or key == 's': |
247 |
import cPickle as pickle |
248 |
f = file("./test.a4b","w") |
249 |
try: |
250 |
pickle.dump(self.view.canvas,f) |
251 |
except Exception,e: |
252 |
d = gtk.Dialog("Error",self,gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, |
253 |
(gtk.STOCK_OK, gtk.RESPONSE_ACCEPT) |
254 |
) |
255 |
d.vbox.add(gtk.Label(str(e))) |
256 |
d.show_all() |
257 |
d.run() |
258 |
d.hide() |
259 |
finally: |
260 |
f.close() |
261 |
elif key == 'R' or key == 'r': |
262 |
import cPickle as pickle |
263 |
f = file("./test.a4b","r") |
264 |
try: |
265 |
self.view.canvas = pickle.load(f) |
266 |
self.view.canvas.update_now() |
267 |
finally: |
268 |
f.close() |
269 |
|
270 |
a = app() |
271 |
gtk.main() |
272 |
|