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 |
print "block types:" |
69 |
if not blocktypes: |
70 |
print "NONE FOUND" |
71 |
for t in blocktypes: |
72 |
|
73 |
b = BlockType(t,D) |
74 |
|
75 |
blocks += [b] |
76 |
|
77 |
# render icon table |
78 |
import threading |
79 |
import gtk |
80 |
import os, os.path, re |
81 |
|
82 |
import cairo |
83 |
|
84 |
#gtk.gdk.threads_init() |
85 |
|
86 |
class BlockIconView(gtk.IconView): |
87 |
""" |
88 |
IconView containing the palette of BlockTypes available for use in the |
89 |
canvas. The list of blocks is supplied currently as an initialisation |
90 |
parameter, but it is intended that this would be dynamic in a final system. |
91 |
|
92 |
It should be possible drag icons from the palette into the canvas, but |
93 |
that is not yet implemented. |
94 |
""" |
95 |
def __init__(self,blocks,app): |
96 |
# the mode containing the icons themselves... |
97 |
self.model = gtk.ListStore(str, gtk.gdk.Pixbuf) |
98 |
self.app = app |
99 |
self.otank = {} |
100 |
#thread = threading.RLock() |
101 |
n = 0 |
102 |
#with thread: |
103 |
for b in blocks: |
104 |
n += 1 |
105 |
pixbuf = b.get_icon(64,64) |
106 |
iter = self.model.append([b.type.getName(), pixbuf]) |
107 |
path = self.model.get_path(iter) |
108 |
self.otank[path] = b |
109 |
|
110 |
gtk.IconView.__init__(self) |
111 |
self.set_model(self.model) |
112 |
self.set_text_column(0) |
113 |
self.set_pixbuf_column(1) |
114 |
self.set_columns(-1) |
115 |
self.set_size_request(180,100) |
116 |
self.connect("item-activated", self.item_activated) |
117 |
self.connect("selection-changed", self.selection_changed) |
118 |
|
119 |
def selection_changed(self,iconview): |
120 |
s = self.get_selected_items() |
121 |
if len(s)==1: |
122 |
b = self.otank[s[0]] |
123 |
self.app.set_placement_tool(b) |
124 |
|
125 |
def item_activated(self,iconview, path): |
126 |
self.app.set_placement_tool(self.otank[path]) |
127 |
|
128 |
from gaphas import GtkView, View |
129 |
from gaphas.tool import HoverTool, PlacementTool, HandleTool, ToolChain |
130 |
from gaphas.tool import Tool, ItemTool, RubberbandTool |
131 |
from gaphas.item import Line |
132 |
from blockitem import * |
133 |
from contextmenutool import * |
134 |
from connectortool import * |
135 |
from portconnectinghandletool import * |
136 |
from blockcanvas import * |
137 |
from panzoom import * |
138 |
from blockinstance import * |
139 |
|
140 |
def BlockToolChain(): |
141 |
""" |
142 |
ToolChain for working with BlockCanvas, including several custom Tools. |
143 |
""" |
144 |
chain = ToolChain() |
145 |
chain.append(HoverTool()) |
146 |
chain.append(PortConnectingHandleTool()) |
147 |
chain.append(ConnectorTool()) |
148 |
chain.append(ContextMenuTool()) |
149 |
chain.append(ItemTool()) |
150 |
chain.append(ZoomTool()) |
151 |
chain.append(PanTool()) |
152 |
chain.append(RubberbandTool()) |
153 |
return chain |
154 |
|
155 |
class app(gtk.Window): |
156 |
def __init__(self): |
157 |
self.status = gtk.Statusbar() |
158 |
|
159 |
# the Gaphas canvas |
160 |
canvas = BlockCanvas() |
161 |
|
162 |
# the main window |
163 |
gtk.Window.__init__(self) |
164 |
self.set_title("ASCEND Blocks") |
165 |
self.set_default_size(400, 500) |
166 |
self.connect("destroy", gtk.main_quit) |
167 |
self.connect("key-press-event", self.key_press_event) |
168 |
|
169 |
windowicon = gtk.Image() |
170 |
windowicon.set_from_file(os.path.join("../glade/ascend.svg")) |
171 |
self.set_icon(windowicon.get_pixbuf()) |
172 |
|
173 |
# vbox containing the main view and the status bar at the bottom |
174 |
vbox = gtk.VBox() |
175 |
|
176 |
tb = gtk.Toolbar() |
177 |
debugbutton = gtk.ToolButton(gtk.STOCK_PROPERTIES) |
178 |
debugbutton.set_label("Debug") |
179 |
debugbutton.connect("clicked",self.debug_canvas) |
180 |
tb.insert(debugbutton,0) |
181 |
vbox.pack_start(tb, True, True) |
182 |
|
183 |
# hbox occupies top part of vbox, with icons on left & canvas on right. |
184 |
hbox = gtk.HBox() |
185 |
|
186 |
# the 'view' widget implemented by Gaphas |
187 |
self.view = GtkView() |
188 |
self.view.tool = BlockToolChain() |
189 |
|
190 |
# table containing scrollbars and main canvas |
191 |
t = gtk.Table(2,2) |
192 |
self.view.canvas = canvas |
193 |
self.view.zoom(1) |
194 |
self.view.set_size_request(600, 500) |
195 |
hs = gtk.HScrollbar(self.view.hadjustment) |
196 |
vs = gtk.VScrollbar(self.view.vadjustment) |
197 |
t.attach(self.view, 0, 1, 0, 1) |
198 |
t.attach(hs, 0, 1, 1, 2, xoptions=gtk.FILL, yoptions=gtk.FILL) |
199 |
t.attach(vs, 1, 2, 0, 1, xoptions=gtk.FILL, yoptions=gtk.FILL) |
200 |
|
201 |
# a scrolling window to contain the icon palette |
202 |
scroll = gtk.ScrolledWindow() |
203 |
scroll.set_border_width(2) |
204 |
scroll.set_shadow_type(gtk.SHADOW_ETCHED_IN) |
205 |
scroll.set_policy(gtk.POLICY_AUTOMATIC,gtk.POLICY_AUTOMATIC) |
206 |
|
207 |
# icon palette |
208 |
self.blockiconview = BlockIconView(blocks, self) |
209 |
scroll.add(self.blockiconview) |
210 |
|
211 |
hbox.pack_start(scroll, True, True) |
212 |
hbox.pack_start(t, True, True) |
213 |
vbox.pack_start(hbox, True, True) |
214 |
vbox.pack_start(self.status, False, False) |
215 |
self.add(vbox) |
216 |
self.show_all() |
217 |
|
218 |
# a message about the found blocks |
219 |
self.status.push(0, "Found %d block types." % (len(blocks))) |
220 |
|
221 |
def set_placement_tool(self,blocktype): |
222 |
# TODO: add undo handler |
223 |
label = blocktype.type.getName() |
224 |
def my_block_factory(): |
225 |
def wrapper(): |
226 |
b = BlockInstance(blocktype) |
227 |
bi = DefaultBlockItem(b) |
228 |
self.view.canvas.add(bi) |
229 |
return bi |
230 |
return wrapper |
231 |
self.view.tool.grab(PlacementTool(my_block_factory(), HandleTool(), 2)) |
232 |
self.status.push(0,"Selected '%s'..." % blocktype.type.getName()) |
233 |
|
234 |
def set_connector_tool(self): |
235 |
def my_line_factory(): |
236 |
def wrapper(): |
237 |
l = Line() |
238 |
self.view.canvas.add(l) |
239 |
return l |
240 |
return wrapper |
241 |
self.view.tool.grab(PlacementTool(my_line_factory(), HandleTool(), 1)) |
242 |
|
243 |
def key_press_event(self,widget,event): |
244 |
# TODO: add undo handler |
245 |
key = gtk.gdk.keyval_name(event.keyval) |
246 |
if key == 'Delete' and self.view.focused_item: |
247 |
self.view.canvas.remove(self.view.focused_item) |
248 |
self.status.push(0,"Item deleted.") |
249 |
elif key == 'l' or key == 'L': |
250 |
self.set_connector_tool() |
251 |
self.status.push(0,"Line draw mode...") |
252 |
elif key == 'S' or key == 's': |
253 |
import pickle as pickle |
254 |
import gaphas.picklers |
255 |
f = file("./test.a4b","w") |
256 |
try: |
257 |
pickle.dump(self.view.canvas,f) |
258 |
except Exception,e: |
259 |
import obrowser |
260 |
b = obrowser.Browser("canvas",self.view.canvas) |
261 |
d = gtk.Dialog("Error",self,gtk.DIALOG_DESTROY_WITH_PARENT, |
262 |
(gtk.STOCK_OK, gtk.RESPONSE_ACCEPT) |
263 |
) |
264 |
d.vbox.add(gtk.Label(str(e))) |
265 |
d.show_all() |
266 |
d.run() |
267 |
d.hide() |
268 |
finally: |
269 |
f.close() |
270 |
elif key == 'R' or key == 'r': |
271 |
import pickle as pickle |
272 |
import gaphas.picklers |
273 |
f = file("./test.a4b","r") |
274 |
try: |
275 |
self.view.canvas = pickle.load(f) |
276 |
print "canvas = ",self.view.canvas.__class__ |
277 |
print dir(self.view.canvas) |
278 |
self.view.canvas.reattach_ascend(L,D) |
279 |
self.view.canvas.update_now() |
280 |
finally: |
281 |
f.close() |
282 |
|
283 |
def debug_canvas(self,widget): |
284 |
import obrowser |
285 |
b = obrowser.Browser("canvas",self.view.canvas, False) |
286 |
|
287 |
a = app() |
288 |
gtk.main() |
289 |
|