1 |
from __future__ import with_statement |
2 |
import os, sys |
3 |
|
4 |
os.chdir(os.path.abspath(os.path.dirname(sys.argv[0]))) |
5 |
os.environ['ASCENDLIBRARY'] = "../../models" |
6 |
os.environ['LD_LIBRARY_PATH'] = "../.." |
7 |
sys.path.append("..") |
8 |
|
9 |
|
10 |
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 |
import ascpy |
33 |
|
34 |
L = ascpy.Library() |
35 |
|
36 |
# FIXME need to add way to add/remove modules from the Library? |
37 |
L.load('test/canvas/blocktypes.a4c') |
38 |
|
39 |
D = L.getAnnotationDatabase() |
40 |
|
41 |
M = L.getModules() |
42 |
|
43 |
blocktypes = set() |
44 |
|
45 |
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 |
return gtk.gdk.pixbuf_new_from_file_at_size("defaultblock.svg",width,height) |
63 |
|
64 |
|
65 |
for m in M: |
66 |
T = L.getModuleTypes(m) |
67 |
for t in T: |
68 |
# '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 |
continue |
73 |
x = D.getNotes(t,ascpy.SymChar("block"),ascpy.SymChar("SELF")) |
74 |
if x: |
75 |
blocktypes.add(t) |
76 |
|
77 |
blocks = [] |
78 |
|
79 |
print "block types:" |
80 |
if not blocktypes: |
81 |
print "NONE FOUND" |
82 |
for t in blocktypes: |
83 |
|
84 |
b = Block(t,D) |
85 |
|
86 |
blocks += [b] |
87 |
|
88 |
# render icon table |
89 |
import threading |
90 |
import gtk |
91 |
import os, os.path, re |
92 |
|
93 |
import cairo |
94 |
from gaphas import GtkView, View |
95 |
from gaphas.tool import HoverTool, PlacementTool, HandleTool, ToolChain |
96 |
from gaphas.tool import Tool, ItemTool, RubberbandTool |
97 |
from port import * |
98 |
|
99 |
gtk.gdk.threads_init() |
100 |
|
101 |
class BlockIconView(gtk.IconView): |
102 |
""" |
103 |
IconView containing the palette of Block available for use in the |
104 |
canvas. The list of blocks is supplied currently as an initialisation |
105 |
parameter, but it is intended that this would be dynamic in a final system. |
106 |
|
107 |
It should be possible drag icons from the palette into the canvas, but |
108 |
that is not yet implemented. |
109 |
""" |
110 |
def __init__(self,blocks,app): |
111 |
# the mode containing the icons themselves... |
112 |
self.model = gtk.ListStore(str, gtk.gdk.Pixbuf) |
113 |
self.app = app |
114 |
self.otank = {} |
115 |
thread = threading.RLock() |
116 |
n = 0 |
117 |
with thread: |
118 |
for b in blocks: |
119 |
n += 1 |
120 |
pixbuf = b.get_icon(64,64) |
121 |
iter = self.model.append([b.type.getName(), pixbuf]) |
122 |
path = self.model.get_path(iter) |
123 |
self.otank[path] = b |
124 |
|
125 |
gtk.IconView.__init__(self) |
126 |
self.set_model(self.model) |
127 |
self.set_text_column(0) |
128 |
self.set_pixbuf_column(1) |
129 |
self.set_columns(-1) |
130 |
self.set_size_request(180,100) |
131 |
self.connect("item-activated", self.item_activated) |
132 |
self.connect("selection-changed", self.selection_changed) |
133 |
|
134 |
def selection_changed(self,iconview): |
135 |
s = self.get_selected_items() |
136 |
if len(s)==1: |
137 |
b = self.otank[s[0]] |
138 |
self.app.set_placement_tool(b) |
139 |
|
140 |
def item_activated(self,iconview, path): |
141 |
self.app.set_placement_tool(self.otank[path]) |
142 |
|
143 |
class ContextMenuTool(Tool): |
144 |
""" |
145 |
Context menu for blocks and connectors on the canvas, intended to be |
146 |
the main mouse-based way by which interaction with blocks occurs (blocks |
147 |
renamed, parameters specified, values examined, etc). |
148 |
Code for performing these tasks should not be here; this should just |
149 |
hook into the appropriate code in the Application layer. |
150 |
""" |
151 |
def __init__(self): |
152 |
pass |
153 |
def on_button_press(self, context, event): |
154 |
if event.button != 3: |
155 |
return False |
156 |
if context.view.hovered_item: |
157 |
menu = gtk.Menu() |
158 |
menurename = gtk.MenuItem("Re_name",True); |
159 |
menurename.connect("activate",self.rename) |
160 |
menu.add(menurename) |
161 |
menu.show_all() |
162 |
menu.popup( None, None, None, event.button, event.time) |
163 |
|
164 |
def rename(self,widget): |
165 |
print "RENAMING OBJECT" |
166 |
|
167 |
|
168 |
|
169 |
def BlockToolChain(): |
170 |
""" |
171 |
The default tool chain build from HoverTool, ItemTool and HandleTool. |
172 |
""" |
173 |
chain = ToolChain() |
174 |
chain.append(HoverTool()) |
175 |
chain.append(PortConnectingHandleTool()) |
176 |
chain.append(ContextMenuTool()) |
177 |
chain.append(ItemTool()) |
178 |
chain.append(RubberbandTool()) |
179 |
return chain |
180 |
|
181 |
class app(gtk.Window): |
182 |
def __init__(self): |
183 |
self.status = gtk.Statusbar() |
184 |
|
185 |
# the Gaphas canvas |
186 |
canvas = BlockCanvas() |
187 |
|
188 |
# the main window |
189 |
gtk.Window.__init__(self) |
190 |
self.set_title("ASCEND Blocks") |
191 |
self.set_default_size(400, 500) |
192 |
self.connect("destroy", gtk.main_quit) |
193 |
self.connect("key-press-event", self.key_press_event) |
194 |
|
195 |
# vbox containing the main view and the status bar at the bottom |
196 |
vbox = gtk.VBox() |
197 |
|
198 |
# hbox occupies top part of vbox, with icons on left & canvas on right. |
199 |
hbox = gtk.HBox() |
200 |
|
201 |
# the 'view' widget implemented by Gaphas |
202 |
self.view = GtkView() |
203 |
self.view.tool = BlockToolChain() |
204 |
|
205 |
# table containing scrollbars and main canvas |
206 |
t = gtk.Table(2,2) |
207 |
self.view.canvas = canvas |
208 |
self.view.zoom(1) |
209 |
self.view.set_size_request(600, 500) |
210 |
hs = gtk.HScrollbar(self.view.hadjustment) |
211 |
vs = gtk.VScrollbar(self.view.vadjustment) |
212 |
t.attach(self.view, 0, 1, 0, 1) |
213 |
t.attach(hs, 0, 1, 1, 2, xoptions=gtk.FILL, yoptions=gtk.FILL) |
214 |
t.attach(vs, 1, 2, 0, 1, xoptions=gtk.FILL, yoptions=gtk.FILL) |
215 |
|
216 |
# a scrolling window to contain the icon palette |
217 |
scroll = gtk.ScrolledWindow() |
218 |
scroll.set_border_width(2) |
219 |
scroll.set_shadow_type(gtk.SHADOW_ETCHED_IN) |
220 |
scroll.set_policy(gtk.POLICY_AUTOMATIC,gtk.POLICY_AUTOMATIC) |
221 |
|
222 |
# icon palette |
223 |
self.blockiconview = BlockIconView(blocks, self) |
224 |
scroll.add(self.blockiconview) |
225 |
|
226 |
hbox.pack_start(scroll, True, True) |
227 |
hbox.pack_start(t, True, True) |
228 |
vbox.pack_start(hbox, True, True) |
229 |
vbox.pack_start(self.status, False, False) |
230 |
self.add(vbox) |
231 |
self.show_all() |
232 |
|
233 |
# a message about the found blocks |
234 |
self.status.push(0, "Found %d block types." % (len(blocks))) |
235 |
|
236 |
def set_placement_tool(self,block): |
237 |
# TODO: add undo handler |
238 |
label = block.type.getName() |
239 |
def my_block_factory(): |
240 |
def wrapper(): |
241 |
b = DefaultBlock(label,inputs=len(block.inputs),outputs=len(block.outputs)) |
242 |
self.view.canvas.add(b) |
243 |
return b |
244 |
return wrapper |
245 |
self.view.tool.grab(PlacementTool(my_block_factory(), HandleTool(), 2)) |
246 |
self.status.push(0,"Selected '%s'..." % block.type.getName()) |
247 |
|
248 |
def set_connector_tool(self): |
249 |
def my_line_factory(): |
250 |
def wrapper(): |
251 |
l = Line() |
252 |
self.view.canvas.add(l) |
253 |
return l |
254 |
return wrapper |
255 |
self.view.tool.grab(PlacementTool(my_line_factory(), HandleTool(), 1)) |
256 |
|
257 |
def key_press_event(self,widget,event): |
258 |
# TODO: add undo handler |
259 |
key = gtk.gdk.keyval_name(event.keyval) |
260 |
if key == 'Delete' and self.view.focused_item: |
261 |
self.view.canvas.remove(self.view.focused_item) |
262 |
self.status.push(0,"Item deleted.") |
263 |
elif key == 'l' or key == 'L': |
264 |
self.set_connector_tool() |
265 |
self.status.push(0,"Line draw mode...") |
266 |
|
267 |
a = app() |
268 |
gtk.main() |
269 |
|