/[ascend]/trunk/pygtk/canvas/blocklist.py
ViewVC logotype

Contents of /trunk/pygtk/canvas/blocklist.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2005 - (show annotations) (download) (as text)
Mon Apr 20 08:39:46 2009 UTC (11 years, 6 months ago) by jpye
File MIME type: text/x-python
File size: 11792 byte(s)
Started work on exposing model parameters to canvas GUI.
Updated header/comment formatting in type_descio.h.
Fixed some warnings in error.c.
A bug still exists error_reporter_tree_start that is causing problems with the
canvas-based GUI.
Added Info class to canvas code, for output of debug information via GUI.
Added a few missing types of gtksourceview langdef.
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 os.environ['ASCENDSOLVERS'] = "../../solvers/qrslv"
9
10 if sys.platform.startswith("win"):
11 os.environ['PATH'] += ";..\.."
12 else:
13 os.environ['LD_LIBRARY_PATH'] = "../.."
14
15 sys.path.append("..")
16
17 #import gtkexcepthook
18
19 if sys.platform.startswith("win"):
20 # Fetchs gtk2 path from registry
21 import _winreg
22 import msvcrt
23 try:
24 k = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, "Software\\GTK\\2.0")
25 except EnvironmentError:
26 # use TkInter to report the error :-)
27 from TkInter import *
28 root = Tk()
29 w = Label(root,"You must install the Gtk+ 2.2 Runtime Environment to run this program")
30 w.pack()
31 root.mainloop()
32 sys.exit(1)
33 else:
34 gtkdir = _winreg.QueryValueEx(k, "Path")
35 import os
36 # we must make sure the gtk2 path is the first thing in the path
37 # otherwise, we can get errors if the system finds other libs with
38 # the same name in the path...
39 os.environ['PATH'] = "%s/lib;%s/bin;" % (gtkdir[0], gtkdir[0]) + os.environ['PATH']
40
41 import ascpy
42
43 L = ascpy.Library()
44
45 # FIXME need to add way to add/remove modules from the Library?
46 L.load('test/canvas/blocktypes.a4c')
47
48 D = L.getAnnotationDatabase()
49
50 M = L.getModules()
51
52 blocktypes = set()
53
54 for m in M:
55 T = L.getModuleTypes(m)
56 for t in T:
57 # 'block' types must not be parametric, because they must be able to
58 # exist even without being connected, and parametric models impose
59 # restrictions on the use of ARE_THE_SAME and similar.
60 if t.hasParameters():
61 continue
62 x = D.getNotes(t,ascpy.SymChar("block"),ascpy.SymChar("SELF"))
63 if x:
64 blocktypes.add(t)
65
66 blocks = []
67
68 from blocktype import *
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(48,48)
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 LineSegmentTool
132 from gaphas.tool import Tool, ItemTool, RubberbandTool
133 from gaphas.painter import ItemPainter
134 from blockconnecttool import BlockConnectTool
135 from blockline import *
136 from blockitem import *
137 from contextmenutool import *
138 from connectortool import *
139 from blockcanvas import *
140 #from panzoom import ZoomTool
141 #from panzoom import PanTool
142 from gaphas.tool import PanTool, ZoomTool
143 from blockinstance import *
144 import info
145
146 def BlockToolChain():
147 """
148 ToolChain for working with BlockCanvas, including several custom Tools.
149 """
150 chain = ToolChain()
151 chain.append(HoverTool())
152 chain.append(BlockConnectTool()) # for connect/disconnect of lines
153 chain.append(ConnectorTool()) # for creating new lines by drag from Port
154 chain.append(ContextMenuTool()) # right-click
155 chain.append(LineSegmentTool()) # for moving line 'elbows'
156 chain.append(ItemTool())
157 chain.append(PanTool())
158 chain.append(ZoomTool())
159 chain.append(RubberbandTool())
160 return chain
161
162 class app(gtk.Window):
163 def __init__(self):
164 """
165 Initialise the application -- create all the widgets, and populate
166 the icon palette.
167 TODO: separate the icon palette into a separate method.
168 """
169 self.status = gtk.Statusbar()
170
171 # the Gaphas canvas
172 canvas = BlockCanvas()
173
174 # the main window
175 gtk.Window.__init__(self)
176 self.set_title("ASCEND Blocks")
177 self.set_default_size(400, 500)
178 self.connect("destroy", gtk.main_quit)
179 self.connect("key-press-event", self.key_press_event)
180
181 windowicon = gtk.Image()
182 windowicon.set_from_file(os.path.join("../glade/ascend.svg"))
183 self.set_icon(windowicon.get_pixbuf())
184
185 # vbox containing the main view and the status bar at the bottom
186 vbox = gtk.VBox()
187
188 tb = gtk.Toolbar()
189 loadbutton = gtk.ToolButton(gtk.STOCK_OPEN)
190 loadbutton.connect("clicked",self.load_canvas)
191 tb.insert(loadbutton,0)
192 savebutton = gtk.ToolButton(gtk.STOCK_SAVE)
193 savebutton.connect("clicked",self.save_canvas)
194 tb.insert(savebutton,1)
195 debugbutton = gtk.ToolButton(gtk.STOCK_PROPERTIES)
196 debugbutton.set_label("Debug")
197 debugbutton.connect("clicked",self.debug_canvas)
198 tb.insert(debugbutton,2)
199 previewb = gtk.ToolButton(gtk.STOCK_PRINT_PREVIEW)
200 previewb.set_label("Preview")
201 previewb.connect("clicked",self.preview_canvas)
202 tb.insert(previewb,3)
203 exportbutton = gtk.ToolButton(gtk.STOCK_CONVERT)
204 exportbutton.set_label("Export SVG")
205 exportbutton.connect("clicked",self.export_svg)
206 tb.insert(exportbutton,2)
207 runb = gtk.ToolButton(gtk.STOCK_EXECUTE)
208 runb.set_label("Run")
209 runb.connect("clicked",self.run_canvas)
210 tb.insert(runb,4)
211
212 vbox.pack_start(tb, True, True)
213
214 # hbox occupies top part of vbox, with icons on left & canvas on right.
215 paned = gtk.HPaned()
216
217 # the 'view' widget implemented by Gaphas
218 import gaphas.view
219 #gaphas.view.DEBUG_DRAW_BOUNDING_BOX = True
220 self.view = GtkView()
221 self.view.tool = BlockToolChain()
222
223 # table containing scrollbars and main canvas
224 t = gtk.Table(2,2)
225 self.view.canvas = canvas
226 self.view.zoom(1)
227 self.view.set_size_request(600, 500)
228 hs = gtk.HScrollbar(self.view.hadjustment)
229 vs = gtk.VScrollbar(self.view.vadjustment)
230 t.attach(self.view, 0, 1, 0, 1)
231 t.attach(hs, 0, 1, 1, 2, xoptions=gtk.FILL, yoptions=gtk.FILL)
232 t.attach(vs, 1, 2, 0, 1, xoptions=gtk.FILL, yoptions=gtk.FILL)
233
234 # a scrolling window to contain the icon palette
235 scroll = gtk.ScrolledWindow()
236 scroll.set_border_width(2)
237 scroll.set_shadow_type(gtk.SHADOW_ETCHED_IN)
238
239 scroll.set_policy(gtk.POLICY_AUTOMATIC,gtk.POLICY_AUTOMATIC)
240 # icon palette
241 self.blockiconview = BlockIconView(blocks, self)
242 scroll.add(self.blockiconview)
243
244 paned.pack1(scroll, True, True)
245 paned.pack2(t, True, True)
246 vbox.pack_start(paned, True, True)
247 vbox.pack_start(self.status, False, False)
248 self.add(vbox)
249 self.show_all()
250
251 # a message about the found blocks
252 self.status.push(0, "Found %d block types." % (len(blocks)))
253
254 def set_placement_tool(self,blocktype):
255 """
256 Prepare the canvas for drawing a block of the type selected in the
257 icon palette.
258 """
259 # TODO: add undo handler
260 label = blocktype.type.getName()
261 def my_block_factory():
262 def wrapper():
263 b = BlockInstance(blocktype)
264 bi = DefaultBlockItem(b)
265 self.view.canvas.add(bi)
266 return bi
267 return wrapper
268 self.view.tool.grab(PlacementTool(my_block_factory(), HandleTool(), 2))
269 self.status.push(0,"Selected '%s'..." % blocktype.type.getName())
270
271 def set_connector_tool(self):
272 """
273 Prepare the canvas for drawing a connecting line (note that one can
274 alternatively just drag from a port to another port).
275 """
276 def my_line_factory():
277 def wrapper():
278 l = BlockLine()
279 self.view.canvas.add(l)
280 return l
281 return wrapper
282 self.view.tool.grab(PlacementTool(my_line_factory(), HandleTool(), 1))
283
284 def key_press_event(self,widget,event):
285 """
286 Handle various application-level keypresses. Fall through if keypress
287 is not handled here; it might be picked up elsewhere.
288 """
289 # TODO: add undo handler
290 key = gtk.gdk.keyval_name(event.keyval)
291 if key == 'Delete' and self.view.focused_item:
292 self.view.canvas.remove(self.view.focused_item)
293 self.status.push(0,"Item deleted.")
294 elif key == 'l' or key == 'L':
295 self.set_connector_tool()
296 self.status.push(0,"Line draw mode...")
297 elif key == 'S' or key == 's':
298 self.save_canvas(None)
299 elif key == 'R' or key == 'r':
300 self.load_canvas(None)
301 elif key == 'V' or key == 'v':
302 self.preview_canvas(None)
303 elif key == 'X' or key == 'x':
304 self.run_canvas(None)
305 elif key == 'G' or key == 'g':
306 self.export_svg(None)
307
308
309 def debug_canvas(self,widget):
310 """
311 Display an 'object browser' to allow inspection of the objects
312 in the canvas.
313 """
314 import obrowser
315 b = obrowser.Browser("canvas",self.view.canvas, False)
316
317
318 def save_canvas(self,widget):
319 """
320 Save the canvas in 'pickle' format. Currently saves to a single
321 predefined file named 'test.a4b'.
322 """
323 import pickle as pickle
324 import gaphas.picklers
325 f = file("./test.a4b","w")
326 try:
327 pickle.dump(self.view.canvas,f)
328 except Exception,e:
329 print "ERROR:",str(e)
330 import obrowser
331 b = obrowser.Browser("canvas",self.view.canvas)
332 d = gtk.Dialog("Error",self,gtk.DIALOG_DESTROY_WITH_PARENT,
333 (gtk.STOCK_OK, gtk.RESPONSE_ACCEPT)
334 )
335 d.vbox.add(gtk.Label(str(e)))
336 d.show_all()
337 d.run()
338 d.hide()
339 finally:
340 f.close()
341 self.status.push(0,"Canvas saved...")
342
343 def load_canvas(self,widget):
344 """
345 Restore a saved canvas in 'pickle' format. Currently always uses the
346 default 'test.a4b' filename.
347 """
348 import pickle as pickle
349 import gaphas.picklers
350 f = file("./test.a4b","r")
351 try:
352 self.view.canvas = pickle.load(f)
353 #print "canvas = ",self.view.canvas.__class__
354 #print dir(self.view.canvas)
355 self.view.canvas.reattach_ascend(L,D)
356 self.view.canvas.update_now()
357 finally:
358 f.close()
359
360 self.status.push(0,"Canvas loaded...")
361
362 def preview_canvas(self,widget):
363 """
364 Output an ASCEND representation of the canvas on the commandline.
365 Under development.
366 """
367
368 info.Info(self.view.get_parent_window(),str(self.view.canvas),"Canvas Preview").run()
369
370 def export_svg(self,widget):
371 svgview = View(self.view.canvas)
372 svgview.painter = ItemPainter()
373
374 # Update bounding boxes with a temporaly CairoContext
375 # (used for stuff like calculating font metrics)
376 tmpsurface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 0, 0)
377 tmpcr = cairo.Context(tmpsurface)
378 svgview.update_bounding_box(tmpcr)
379 tmpcr.show_page()
380 tmpsurface.flush()
381
382 fn = 'demo.svg'
383 w, h = svgview.bounding_box.width, svgview.bounding_box.height
384 surface = cairo.SVGSurface(fn , w, h)
385 cr = cairo.Context(surface)
386 svgview.matrix.translate(-svgview.bounding_box.x, -svgview.bounding_box.y)
387 svgview.paint(cr)
388 cr.show_page()
389 surface.flush()
390 surface.finish()
391
392 self.status.push(0,"Wrote SVG file '%s'." % fn)
393
394 def run_canvas(self,widget):
395 """
396 Export canvas to ASCEND solver and attempt to solve, or at least to
397 to instantiate the model.
398 """
399 model = str(self.view.canvas)
400 print model
401 print "RUN NOT IMPLEMENTED"
402 L.loadString(model,"canvasmodel")
403 print "STRING MODEL LOADED"
404 T = L.findType("canvasmodel")
405 M = T.getSimulation('canvassim')
406 M.setSolver(ascpy.Solver("QRSlv"))
407 M.solve(ascpy.Solver("QRSlv"),ascpy.SolverReporter())
408
409 a = app()
410 gtk.main()
411

Properties

Name Value
svn:executable *

john.pye@anu.edu.au
ViewVC Help
Powered by ViewVC 1.1.22