1 |
jpye |
1945 |
#!/usr/bin/env python |
2 |
jpye |
1935 |
from __future__ import with_statement |
3 |
jpye |
1937 |
import os, sys |
4 |
jpye |
1929 |
|
5 |
jpye |
1940 |
os.chdir(os.path.abspath(os.path.dirname(sys.argv[0]))) |
6 |
jpye |
1937 |
os.environ['ASCENDLIBRARY'] = "../../models" |
7 |
|
|
os.environ['LD_LIBRARY_PATH'] = "../.." |
8 |
|
|
sys.path.append("..") |
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 |
1813 |
for m in M: |
46 |
|
|
T = L.getModuleTypes(m) |
47 |
|
|
for t in T: |
48 |
jpye |
1925 |
# 'block' types must not be parametric, because they must be able to |
49 |
|
|
# exist even without being connected, and parametric models impose |
50 |
|
|
# restrictions on the use of ARE_THE_SAME and similar. |
51 |
|
|
if t.hasParameters(): |
52 |
jpye |
1893 |
continue |
53 |
jpye |
1925 |
x = D.getNotes(t,ascpy.SymChar("block"),ascpy.SymChar("SELF")) |
54 |
|
|
if x: |
55 |
jpye |
1813 |
blocktypes.add(t) |
56 |
|
|
|
57 |
jpye |
1935 |
blocks = [] |
58 |
|
|
|
59 |
jpye |
1945 |
from blocktype import * |
60 |
|
|
|
61 |
jpye |
1813 |
print "block types:" |
62 |
|
|
if not blocktypes: |
63 |
|
|
print "NONE FOUND" |
64 |
|
|
for t in blocktypes: |
65 |
|
|
|
66 |
jpye |
1945 |
b = BlockType(t,D) |
67 |
jpye |
1926 |
|
68 |
jpye |
1935 |
blocks += [b] |
69 |
jpye |
1925 |
|
70 |
jpye |
1935 |
# render icon table |
71 |
|
|
import threading |
72 |
|
|
import gtk |
73 |
|
|
import os, os.path, re |
74 |
jpye |
1936 |
|
75 |
|
|
import cairo |
76 |
|
|
|
77 |
jpye |
1935 |
gtk.gdk.threads_init() |
78 |
|
|
|
79 |
jpye |
1937 |
class BlockIconView(gtk.IconView): |
80 |
jpye |
1940 |
""" |
81 |
jpye |
1945 |
IconView containing the palette of BlockTypes available for use in the |
82 |
jpye |
1940 |
canvas. The list of blocks is supplied currently as an initialisation |
83 |
|
|
parameter, but it is intended that this would be dynamic in a final system. |
84 |
|
|
|
85 |
|
|
It should be possible drag icons from the palette into the canvas, but |
86 |
|
|
that is not yet implemented. |
87 |
|
|
""" |
88 |
jpye |
1937 |
def __init__(self,blocks,app): |
89 |
|
|
# the mode containing the icons themselves... |
90 |
|
|
self.model = gtk.ListStore(str, gtk.gdk.Pixbuf) |
91 |
|
|
self.app = app |
92 |
|
|
self.otank = {} |
93 |
|
|
thread = threading.RLock() |
94 |
|
|
n = 0 |
95 |
|
|
with thread: |
96 |
|
|
for b in blocks: |
97 |
|
|
n += 1 |
98 |
|
|
pixbuf = b.get_icon(64,64) |
99 |
|
|
iter = self.model.append([b.type.getName(), pixbuf]) |
100 |
|
|
path = self.model.get_path(iter) |
101 |
|
|
self.otank[path] = b |
102 |
|
|
|
103 |
|
|
gtk.IconView.__init__(self) |
104 |
|
|
self.set_model(self.model) |
105 |
|
|
self.set_text_column(0) |
106 |
|
|
self.set_pixbuf_column(1) |
107 |
|
|
self.set_columns(-1) |
108 |
|
|
self.set_size_request(180,100) |
109 |
|
|
self.connect("item-activated", self.item_activated) |
110 |
|
|
self.connect("selection-changed", self.selection_changed) |
111 |
|
|
|
112 |
|
|
def selection_changed(self,iconview): |
113 |
|
|
s = self.get_selected_items() |
114 |
|
|
if len(s)==1: |
115 |
|
|
b = self.otank[s[0]] |
116 |
|
|
self.app.set_placement_tool(b) |
117 |
|
|
|
118 |
jpye |
1940 |
def item_activated(self,iconview, path): |
119 |
|
|
self.app.set_placement_tool(self.otank[path]) |
120 |
|
|
|
121 |
jpye |
1945 |
from gaphas import GtkView, View |
122 |
|
|
from gaphas.tool import HoverTool, PlacementTool, HandleTool, ToolChain |
123 |
|
|
from gaphas.tool import Tool, ItemTool, RubberbandTool |
124 |
|
|
from gaphas.item import Line |
125 |
|
|
from blockitem import * |
126 |
|
|
from contextmenutool import * |
127 |
jpye |
1943 |
from connectortool import * |
128 |
jpye |
1945 |
from portconnectinghandletool import * |
129 |
|
|
from blockcanvas import * |
130 |
|
|
from panzoom import * |
131 |
|
|
from blockinstance import * |
132 |
jpye |
1943 |
|
133 |
jpye |
1939 |
def BlockToolChain(): |
134 |
jpye |
1942 |
""" |
135 |
|
|
The default tool chain build from HoverTool, ItemTool and HandleTool. |
136 |
|
|
""" |
137 |
|
|
chain = ToolChain() |
138 |
|
|
chain.append(HoverTool()) |
139 |
|
|
chain.append(PortConnectingHandleTool()) |
140 |
jpye |
1943 |
chain.append(ConnectorTool()) |
141 |
jpye |
1942 |
chain.append(ContextMenuTool()) |
142 |
|
|
chain.append(ItemTool()) |
143 |
|
|
chain.append(ZoomTool()) |
144 |
|
|
chain.append(PanTool()) |
145 |
|
|
chain.append(RubberbandTool()) |
146 |
|
|
return chain |
147 |
jpye |
1939 |
|
148 |
jpye |
1935 |
class app(gtk.Window): |
149 |
|
|
def __init__(self): |
150 |
jpye |
1937 |
self.status = gtk.Statusbar() |
151 |
jpye |
1936 |
|
152 |
jpye |
1937 |
# the Gaphas canvas |
153 |
jpye |
1936 |
canvas = BlockCanvas() |
154 |
|
|
|
155 |
jpye |
1937 |
# the main window |
156 |
jpye |
1935 |
gtk.Window.__init__(self) |
157 |
|
|
self.set_title("ASCEND Blocks") |
158 |
|
|
self.set_default_size(400, 500) |
159 |
|
|
self.connect("destroy", gtk.main_quit) |
160 |
jpye |
1938 |
self.connect("key-press-event", self.key_press_event) |
161 |
jpye |
1935 |
|
162 |
jpye |
1943 |
windowicon = gtk.Image() |
163 |
|
|
windowicon.set_from_file(os.path.join("../glade/ascend.svg")) |
164 |
|
|
self.set_icon(windowicon.get_pixbuf()) |
165 |
|
|
|
166 |
jpye |
1937 |
# vbox containing the main view and the status bar at the bottom |
167 |
jpye |
1935 |
vbox = gtk.VBox() |
168 |
|
|
|
169 |
jpye |
1937 |
# hbox occupies top part of vbox, with icons on left & canvas on right. |
170 |
jpye |
1936 |
hbox = gtk.HBox() |
171 |
|
|
|
172 |
jpye |
1937 |
# the 'view' widget implemented by Gaphas |
173 |
|
|
self.view = GtkView() |
174 |
jpye |
1939 |
self.view.tool = BlockToolChain() |
175 |
jpye |
1936 |
|
176 |
jpye |
1937 |
# table containing scrollbars and main canvas |
177 |
jpye |
1936 |
t = gtk.Table(2,2) |
178 |
jpye |
1937 |
self.view.canvas = canvas |
179 |
|
|
self.view.zoom(1) |
180 |
|
|
self.view.set_size_request(600, 500) |
181 |
|
|
hs = gtk.HScrollbar(self.view.hadjustment) |
182 |
|
|
vs = gtk.VScrollbar(self.view.vadjustment) |
183 |
|
|
t.attach(self.view, 0, 1, 0, 1) |
184 |
jpye |
1936 |
t.attach(hs, 0, 1, 1, 2, xoptions=gtk.FILL, yoptions=gtk.FILL) |
185 |
|
|
t.attach(vs, 1, 2, 0, 1, xoptions=gtk.FILL, yoptions=gtk.FILL) |
186 |
|
|
|
187 |
jpye |
1937 |
# a scrolling window to contain the icon palette |
188 |
|
|
scroll = gtk.ScrolledWindow() |
189 |
|
|
scroll.set_border_width(2) |
190 |
|
|
scroll.set_shadow_type(gtk.SHADOW_ETCHED_IN) |
191 |
|
|
scroll.set_policy(gtk.POLICY_AUTOMATIC,gtk.POLICY_AUTOMATIC) |
192 |
|
|
|
193 |
|
|
# icon palette |
194 |
|
|
self.blockiconview = BlockIconView(blocks, self) |
195 |
|
|
scroll.add(self.blockiconview) |
196 |
|
|
|
197 |
jpye |
1936 |
hbox.pack_start(scroll, True, True) |
198 |
|
|
hbox.pack_start(t, True, True) |
199 |
|
|
vbox.pack_start(hbox, True, True) |
200 |
jpye |
1937 |
vbox.pack_start(self.status, False, False) |
201 |
jpye |
1935 |
self.add(vbox) |
202 |
|
|
self.show_all() |
203 |
|
|
|
204 |
jpye |
1937 |
# a message about the found blocks |
205 |
|
|
self.status.push(0, "Found %d block types." % (len(blocks))) |
206 |
|
|
|
207 |
jpye |
1945 |
def set_placement_tool(self,blocktype): |
208 |
jpye |
1938 |
# TODO: add undo handler |
209 |
jpye |
1945 |
label = blocktype.type.getName() |
210 |
jpye |
1937 |
def my_block_factory(): |
211 |
|
|
def wrapper(): |
212 |
jpye |
1945 |
b = BlockInstance(blocktype) |
213 |
|
|
bi = DefaultBlockItem(b) |
214 |
|
|
self.view.canvas.add(bi) |
215 |
|
|
return bi |
216 |
jpye |
1937 |
return wrapper |
217 |
|
|
self.view.tool.grab(PlacementTool(my_block_factory(), HandleTool(), 2)) |
218 |
jpye |
1945 |
self.status.push(0,"Selected '%s'..." % blocktype.type.getName()) |
219 |
jpye |
1938 |
|
220 |
jpye |
1940 |
def set_connector_tool(self): |
221 |
|
|
def my_line_factory(): |
222 |
|
|
def wrapper(): |
223 |
|
|
l = Line() |
224 |
|
|
self.view.canvas.add(l) |
225 |
|
|
return l |
226 |
|
|
return wrapper |
227 |
|
|
self.view.tool.grab(PlacementTool(my_line_factory(), HandleTool(), 1)) |
228 |
|
|
|
229 |
jpye |
1938 |
def key_press_event(self,widget,event): |
230 |
|
|
# TODO: add undo handler |
231 |
|
|
key = gtk.gdk.keyval_name(event.keyval) |
232 |
|
|
if key == 'Delete' and self.view.focused_item: |
233 |
|
|
self.view.canvas.remove(self.view.focused_item) |
234 |
|
|
self.status.push(0,"Item deleted.") |
235 |
jpye |
1940 |
elif key == 'l' or key == 'L': |
236 |
|
|
self.set_connector_tool() |
237 |
|
|
self.status.push(0,"Line draw mode...") |
238 |
jpye |
1935 |
|
239 |
|
|
a = app() |
240 |
|
|
gtk.main() |
241 |
|
|
|