Web · Wiki · Activities · Blog · Lists · Chat · Meeting · Bugs · Git · Translate · Archive · People · Donate

Commit b0c68db5e4adce027d9e83e054240c6a5a247f94

  • avatar
  • Raúl Gutiérrez S <rgs @paragu…duca.org>
  • Sat Dec 05 18:44:39 EST 2009
tawindow now has a class where all of its functionality is encapsulated. TODO: define how taproject and tawindow relate.
  
226226 FILE = open(dsobject.file_path, "r")
227227 self.tw.myblock = FILE.read()
228228 FILE.close()
229 tawindow.set_userdefined(self.tw)
229 self.tw.set_userdefined()
230230 # save reference to Pythin code in the project metadata
231231 self.metadata['python code'] = dsobject.object_id
232232 except:
244244 # Write the file to the instance directory of this activity's root.
245245 file_path = os.path.join(datapath, filename)
246246
247 # FIXME: this was like this before refactoring, the save_pict
248 # belongs to taproject (not tawindow)
247249 tawindow.save_pict(self.tw,file_path)
248250
249251 # Create a datastore object
280280 tafile = os.path.join(tmppath,"tmpfile.ta")
281281 print tafile
282282 try:
283 # FIXME: encapsulation?
283284 tawindow.save_data(self.tw,tafile)
284285 except:
285286 _logger.debug("couldn't save snapshot to journal")
306306 """ Show/hide palette """
307307 def _do_palette_cb(self, button):
308308 if self.tw.palette == True:
309 tawindow.hideshow_palette(self.tw,False)
309 self.tw.hideshow_palette(False)
310310 self.palette_button.set_icon("blockson")
311311 self.palette_button.set_tooltip(_('Show palette'))
312312 else:
313 tawindow.hideshow_palette(self.tw,True)
313 self.tw.hideshow_palette(True)
314314 self.palette_button.set_icon("blocksoff")
315315 self.palette_button.set_tooltip(_('Hide palette'))
316316
326326 self.palette_button.set_tooltip(_('Hide palette'))
327327
328328 def _do_hideshow_cb(self, button):
329 tawindow.hideshow_button(self.tw)
329 self.tw.hideshow_button()
330330 if self.tw.hide == True: # we just hid the blocks
331331 self.blocks_button.set_icon("hideshowon")
332332 self.blocks_button.set_tooltip(_('Show blocks'))
356356 def _do_eraser_cb(self, button):
357357 self.eraser_button.set_icon("eraseroff")
358358 self.recenter()
359 tawindow.eraser_button(self.tw)
359 self.tw.eraser_button()
360360 gobject.timeout_add(250,self.eraser_button.set_icon,"eraseron")
361361
362362 def _do_run_cb(self, button):
363363 self.run_button.set_icon("run-faston")
364364 self.stop_button.set_icon("stopiton")
365365 self.tw.lc.trace = 0
366 tawindow.run_button(self.tw, 0)
366 self.tw.run_button(0)
367367 gobject.timeout_add(1000,self.run_button.set_icon,"run-fastoff")
368368
369369 def _do_step_cb(self, button):
370370 self.step_button.set_icon("run-slowon")
371371 self.stop_button.set_icon("stopiton")
372372 self.tw.lc.trace = 0
373 tawindow.run_button(self.tw, 3)
373 self.tw.run_button(3)
374374 gobject.timeout_add(1000,self.step_button.set_icon,"run-slowoff")
375375
376376 def _do_debug_cb(self, button):
377377 self.debug_button.set_icon("debugon")
378378 self.stop_button.set_icon("stopiton")
379379 self.tw.lc.trace = 1
380 tawindow.run_button(self.tw, 6)
380 self.tw.run_button(6)
381381 gobject.timeout_add(1000,self.debug_button.set_icon,"debugoff")
382382
383383 def _do_stop_cb(self, button):
384384 self.stop_button.set_icon("stopitoff")
385 tawindow.stop_button(self.tw)
385 self.tw.stop_button()
386386 self.step_button.set_icon("run-slowoff")
387387 self.run_button.set_icon("run-fastoff")
388388
389389 """ Sample projects open dialog """
390390 def _do_samples_cb(self, button):
391 # FIXME: encapsulation!
391392 tawindow.load_file(self.tw, True)
392393 # run the activity
393394 self.stop_button.set_icon("stopiton")
394 tawindow.run_button(self.tw, 0)
395 self.tw.run_button(0)
395396
396397 """
397398 Recenter scrolled window around canvas
416416 """
417417 def _do_cartesian_cb(self, button):
418418 if self.tw.cartesian is True:
419 # FIXME: encapsulation
419420 tawindow.hide(self.tw.cartesian_coordinates_spr)
420421 self.tw.cartesian = False
421422 else:
423 # FIXME: encapsulation
422424 tawindow.setlayer(self.tw.cartesian_coordinates_spr,610)
423425 self.tw.cartesian = True
424426
425427 def _do_polar_cb(self, button):
426428 if self.tw.polar is True:
429 # FIXME: encapsulation
427430 tawindow.hide(self.tw.polar_coordinates_spr)
428431 self.tw.polar = False
429432 else:
433 # FIXME: encapsulation
430434 tawindow.setlayer(self.tw.polar_coordinates_spr,610)
431435 self.tw.polar = True
432436
442442 self.tw.coord_scale = self.tw.height/200
443443 self.rescale_button.set_icon("contract-coordinates")
444444 self.rescale_button.set_tooltip(_('Rescale coordinates down'))
445 tawindow.eraser_button(self.tw)
445 self.tw.eraser_button()
446446 else:
447447 self.tw.coord_scale = 1
448448 self.rescale_button.set_icon("expand-coordinates")
449449 self.rescale_button.set_tooltip(_('Rescale coordinates up'))
450 tawindow.eraser_button(self.tw)
450 self.tw.eraser_button()
451451
452452 """
453453 Either set up initial share...
548548 e,x,y,mask = re.split(":",text)
549549 # _logger.debug("receiving button press: "+x+" "+y+" "+mask)
550550 if mask == 'T':
551 tawindow.button_press(self.tw,True,int(x),int(y),False)
551 self.tw.button_press(True,int(x),int(y),False)
552552 else:
553 tawindow.button_press(self.tw,False,int(x),int(y),False)
553 self.tw.button_press(False,int(x),int(y),False)
554554 elif text[0] == 'r': # block release
555555 e,x,y = re.split(":",text)
556556 # _logger.debug("receiving button release: " + x + " " + y)
557 tawindow.button_release(self.tw,int(x),int(y),False)
557 self.tw.button_release(int(x),int(y),False)
558558 elif text[0] == 'm': # mouse move
559559 e,x,y = re.split(":",text)
560560 _logger.debug("receiving move: " + x + " " + y)
561 tawindow.mouse_move(self.tw,0,0,False,int(x),int(y))
561 self.tw.mouse_move(0,0,False,int(x),int(y))
562562 elif text[0] == 'k': # typing
563563 e,mask,keyname = re.split(":",text,3)
564564 # _logger.debug("recieving key press: " + mask + " " + keyname)
565565 if mask == 'T':
566 tawindow.key_press(self.tw,True,keyname,False)
566 self.tw.key_press(True,keyname,False)
567567 else:
568 tawindow.key_press(self.tw,False,keyname,False)
568 self.tw.key_press(False,keyname,False)
569569 elif text[0] == 'i': # request for current state
570570 # sharer should send current state to joiner
571571 if self.initiating is True:
572572 _logger.debug("serialize the project and send to joiner")
573573 text = tawindow.save_string(self.tw)
574574 self._send_event("I:" + text)
575 tawindow.show_palette(self.tw)
575 self.tw.show_palette()
576576 elif text[0] == 'I': # receiving current state
577577 if self.waiting_for_blocks:
578578 _logger.debug("receiving project from sharer")
878878 self.sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
879879 self.sw.show()
880880 canvas = gtk.DrawingArea()
881 canvas.set_size_request(gtk.gdk.screen_width()*2, \
882 gtk.gdk.screen_height()*2)
881 width = gtk.gdk.screen_width() * 2
882 height = gtk.gdk.screen_height() * 2
883 canvas.set_size_request(width, height)
883884 self.sw.add_with_viewport(canvas)
884885 canvas.show()
885886 return canvas
945945 """
946946 def _setup_canvas(self, canvas, lang):
947947 bundle_path = activity.get_bundle_path()
948 self.tw = tawindow.twNew(canvas, bundle_path, lang, self)
948 self.tw = tawindow.TurtleArtWindow(canvas, bundle_path, lang, self)
949949 self.tw.activity = self
950950 self.tw.window.grab_focus()
951951 path = os.path.join(os.environ['SUGAR_ACTIVITY_ROOT'], 'data')
10521052 # Use pre-0.86 toolbar design
10531053 self.projectToolbar.stop.set_icon("stopiton")
10541054
1055 tawindow.run_button(self.tw, 0)
1055 self.tw.run_button(0)
10561056 else:
10571057 _logger.debug("Deferring reading file %s" % file_path)
10581058
tawindow.py
(881 / 764)
  
2121#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2222#THE SOFTWARE.
2323
24
25# TODO:
26# - we need a method to know if we are running inside Sugar (vs. stand-alone)
27# - we need helper methods to discriminate what XO version we are using (if any)
28# - verbose flag should be in the scope of the object instance
29# - better comments!
30#
31
32
2433import pygtk
2534pygtk.require('2.0')
2635import gtk
4242# Import from Journal for these blocks
4343importblocks = ['audiooff', 'descriptionoff','journal']
4444
45class taWindow: pass
4645
4746from math import atan2, pi
4847DEGTOR = 2*pi/360
7575timeout_tag = [0]
7676
7777
78#
79# Setup
80#
8178
82def twNew(win, path, lang, parent=None):
83 tw = taWindow()
84 tw.window = win
85 tw.path = os.path.join(path,'images')
86 tw.path_lang = os.path.join(path,'images',lang)
87 tw.path_en = os.path.join(path,'images/en') # en as fallback
88 tw.load_save_folder = os.path.join(path,'samples')
89 tw.save_folder = None
90 tw.save_file_name = None
91 win.set_flags(gtk.CAN_FOCUS)
92 tw.width = gtk.gdk.screen_width()
93 tw.height = gtk.gdk.screen_height()
94 # starting from command line
95 if parent is None:
96 win.show_all()
97 # starting from Sugar
98 else:
99 parent.show_all()
100 win.add_events(gtk.gdk.BUTTON_PRESS_MASK)
101 win.add_events(gtk.gdk.BUTTON_RELEASE_MASK)
102 win.add_events(gtk.gdk.POINTER_MOTION_MASK)
103 win.add_events(gtk.gdk.KEY_PRESS_MASK)
104 win.connect("expose-event", expose_cb, tw)
105 win.connect("button-press-event", buttonpress_cb, tw)
106 win.connect("button-release-event", buttonrelease_cb, tw)
107 win.connect("motion-notify-event", move_cb, tw)
108 win.connect("key_press_event", keypress_cb, tw)
109 tw.keypress = ""
110 tw.keyvalue = 0
111 tw.dead_key = ""
112 tw.area = win.window
113 tw.gc = tw.area.new_gc()
114 # on an OLPC-XO-1, there is a scaling factor
115 if os.path.exists('/etc/olpc-release') or \
116 os.path.exists('/sys/power/olpc-pm'):
117 tw.lead = 1.6
118 tw.scale = 1.0
119 else:
120 tw.lead = 1.0
121 tw.scale = 1.6
122 tw.cm = tw.gc.get_colormap()
123 tw.rgb = [255,0,0]
124 tw.bgcolor = tw.cm.alloc_color('#fff8de')
125 tw.msgcolor = tw.cm.alloc_color('black')
126 tw.fgcolor = tw.cm.alloc_color('red')
127 tw.textcolor = tw.cm.alloc_color('blue')
128 tw.textsize = 32
129 tw.sprites = []
130 tw.selected_block = None
131 tw.draggroup = None
132 prep_selectors(tw)
133 tw.myblock = None
134 tw.nop = 'nop'
135 tw.loaded = 0
136 for s in selectors:
137 setup_selectors(tw,s)
138 setup_misc(tw)
139 tw.step_time = 0
140 tw.hide = False
141 tw.palette = True
142 select_category(tw, tw.selbuttons[0])
143 tw.coord_scale = 1
144 tw.turtle = tNew(tw,tw.width,tw.height)
145 tw.lc = lcNew(tw)
146 tw.buddies = []
147 tw.dx = 0
148 tw.dy = 0
149 tw.cartesian = False
150 tw.polar = False
151 tw.spr = None # "currently selected spr"
152 return tw
79"""
80TurtleArt Window class abstraction
81"""
82class TurtleArtWindow():
15383
154#
155# Button Press
156#
84 def __init__(self, win, path, lang, parent=None):
85 self.window = win
86 self.path = os.path.join(path,'images')
87 self.path_lang = os.path.join(path,'images',lang)
88 self.path_en = os.path.join(path,'images/en') # en as fallback
89 self.load_save_folder = os.path.join(path,'samples')
90 self.save_folder = None
91 self.save_file_name = None
92 win.set_flags(gtk.CAN_FOCUS)
93 self.width = gtk.gdk.screen_width()
94 self.height = gtk.gdk.screen_height()
15795
158def buttonpress_cb(win, event, tw):
159 win.grab_focus()
160 x, y = xy(event)
161 button_press(tw, event.get_state()&gtk.gdk.CONTROL_MASK, x, y)
162 # if sharing, send button press
163 if hasattr(tw, 'activity') and \
164 hasattr(tw.activity, 'chattube') and tw.activity.chattube is not None:
165 # print "sending button pressed"
166 if event.get_state()&gtk.gdk.CONTROL_MASK is True:
167 tw.activity._send_event("p:"+str(x)+":"+str(y)+":"+'T')
96 # starting from command line
97 if parent is None:
98 win.show_all()
99 # starting from Sugar
168100 else:
169 tw.activity._send_event("p:"+str(x)+":"+str(y)+":"+'F')
170 return True
101 parent.show_all()
171102
172def button_press(tw, mask, x, y, verbose=False):
173 if verbose:
174 print "processing remote button press: " + str(x) + " " + str(y)
175 tw.block_operation = 'click'
176 if tw.selected_block!=None:
177 unselect(tw)
178 else:
179 setlayer(tw.status_spr,400)
180 spr = findsprite(tw,(x,y))
181 tw.x, tw.y = x,y
182 tw.dx = 0
183 tw.dy = 0
184 if spr is None:
185 return True
186 if spr.type == "canvas":
187 return True
188 elif spr.type == 'selbutton':
189 select_category(tw,spr)
190 elif spr.type == 'category':
191 block_selector_pressed(tw,x,y)
192 elif spr.type == 'block':
193 block_pressed(tw,mask,x,y,spr)
194 elif spr.type == 'turtle':
195 turtle_pressed(tw,x,y)
196 tw.spr = spr
103 self._setup_events()
197104
198def block_selector_pressed(tw,x,y):
199 proto = get_proto_from_category(tw,x,y)
200 if proto==None:
105 self.keypress = ""
106 self.keyvalue = 0
107 self.dead_key = ""
108 self.area = self.window.window
109 self.gc = self.area.new_gc()
110 # on an OLPC-XO-1, there is a scaling factor
111 if os.path.exists('/etc/olpc-release') or \
112 os.path.exists('/sys/power/olpc-pm'):
113 self.lead = 1.6
114 self.scale = 1.0
115 else:
116 self.lead = 1.0
117 self.scale = 1.6
118 self.cm = self.gc.get_colormap()
119 self.rgb = [255,0,0]
120 self.bgcolor = self.cm.alloc_color('#fff8de')
121 self.msgcolor = self.cm.alloc_color('black')
122 self.fgcolor = self.cm.alloc_color('red')
123 self.textcolor = self.cm.alloc_color('blue')
124 self.textsize = 32
125 self.sprites = []
126 self.selected_block = None
127 self.draggroup = None
128 prep_selectors(self)
129 self.myblock = None
130 self.nop = 'nop'
131 self.loaded = 0
132 for s in selectors:
133 setup_selectors(self,s)
134 setup_misc(self)
135 self.step_time = 0
136 self.hide = False
137 self.palette = True
138 self._select_category(self.selbuttons[0])
139 self.coord_scale = 1
140 self.turtle = tNew(self,self.width,self.height)
141 self.lc = lcNew(self)
142 self.buddies = []
143 self.dx = 0
144 self.dy = 0
145 self.cartesian = False
146 self.polar = False
147 self.spr = None # "currently selected spr"
148
149
150 """
151 DEPRECATED
152 """
153 def runtool(self, spr, cmd, *args):
154 cmd(*(args))
155
156 """
157 eraser_button: hide status block
158 """
159 def eraser_button(self):
160 setlayer(self.status_spr,400)
161 clear(self.lc)
162 display_coordinates(self)
163
164 """
165 stop button
166 """
167 def stop_button(self):
168 stop_logo(self)
169
170
171 """
172 change the icon for user-defined blocks after Python code is loaded
173 """
174 def set_userdefined(self):
175 list = self.sprites[:]
176 for spr in list:
177 if hasattr(spr,'proto') and spr.proto.name == 'nop':
178 setimage(spr,self.media_shapes['pythonloaded'])
179 self.nop = 'pythonloaded'
180
181
182 """
183 hideshow button
184 """
185 def hideshow_button(self):
186 if self.hide is False:
187 for b in self._blocks(): setlayer(b,100)
188 self._hide_palette()
189 hide(self.select_mask)
190 hide(self.select_mask_string)
191 self.hide = True
192 else:
193 for b in self._blocks(): setlayer(b,650)
194 self.show_palette()
195 self.hide = False
196 inval(self.turtle.canvas)
197
198
199 """
200 run turtle!
201 """
202 def run_button(self, time):
203 print "you better run, turtle, run!!"
204 # look for the start block
205 for b in self._blocks():
206 if self._find_start_stack(b):
207 self.step_time = time
208 if hasattr(self, 'activity'):
209 self.activity.recenter()
210 self._run_stack(b)
211 return
212 # no start block, so run a stack that isn't a hat
213 for b in self._blocks():
214 if self._find_block_to_run(b):
215 print "running " + b.proto.name
216 self.step_time = time
217 self._run_stack(b)
201218 return
202 if proto is not 'hide':
203 new_block_from_category(tw,proto,x,y)
204 else:
205 hideshow_palette(tw,False)
206219
207def hideshow_palette(tw,state):
208 if state is False:
209 tw.palette == False
210 if hasattr(tw,'activity'):
211 # Use new toolbar design
212 tw.activity.do_hidepalette()
213 hide_palette(tw)
214 else:
215 tw.palette == True
216 if hasattr(tw,'activity'):
217 # Use new toolbar design
218 tw.activity.do_showpalette()
219 show_palette(tw)
220 """
221 button_press
222 """
223 def button_press(self, mask, x, y, verbose=False):
224 if verbose:
225 print "processing remote button press: " + str(x) + " " + str(y)
226 self.block_operation = 'click'
227 if self.selected_block != None:
228 self._unselect()
229 else:
230 setlayer(self.status_spr,400)
231 spr = findsprite(self,(x,y))
232 self.x, self.y = x,y
233 self.dx = 0
234 self.dy = 0
235 if spr is None:
236 return True
237 if spr.type == "canvas":
238 return True
239 elif spr.type == 'selbutton':
240 self._select_category(spr)
241 elif spr.type == 'category':
242 self._block_selector_pressed(x,y)
243 elif spr.type == 'block':
244 self._block_pressed(mask,x,y,spr)
245 elif spr.type == 'turtle':
246 self._turtle_pressed(x,y)
247 self.spr = spr
220248
221def show_palette(tw):
222 for i in tw.selbuttons: setlayer(i,800)
223 select_category(tw,tw.selbuttons[0])
224 tw.palette = True
225249
226def hide_palette(tw):
227 for i in tw.selbuttons: hide(i)
228 setshape(tw.category_spr, tw.hidden_palette_icon)
229 tw.palette = False
250 """
251 hideshow_palette
252 """
253 def hideshow_palette(self, state):
254 if state is False:
255 self.palette == False
256 if hasattr(self, 'activity'):
257 # Use new toolbar design
258 self.activity.do_hidepalette()
259 self._hide_palette()
260 else:
261 self.palette == True
262 if hasattr(self, 'activity'):
263 # Use new toolbar design
264 self.activity.do_showpalette()
265 self.show_palette()
230266
231def get_proto_from_category(tw,x,y):
232 dx,dy = x-tw.category_spr.x, y-tw.category_spr.y,
233 pixel = getpixel(tw.current_category.mask,dx,dy)
234 index = ((pixel%256)>>3)-1
235 if index==0:
236 return 'hide'
237 index-=1
238 if index>len(tw.current_category.blockprotos):
239 return None
240 return tw.current_category.blockprotos[index]
267 """
268 show palette
269 """
270 def show_palette(self):
271 for i in self.selbuttons: setlayer(i,800)
272 self._select_category(self.selbuttons[0])
273 self.palette = True
241274
242def select_category(tw, spr):
243 if hasattr(tw, 'current_category'):
244 setshape(tw.current_category, tw.current_category.offshape)
245 setshape(spr, spr.onshape)
246 tw.current_category = spr
247 setshape(tw.category_spr,spr.group)
248275
249def new_block_from_category(tw,proto,x,y):
250 if proto is None:
251 return True
252 # load alternative image of nop block if python code is loaded
253 if proto.name == 'nop' and tw.nop == 'pythonloaded':
254 newspr = sprNew(tw,x-20,y-20,tw.media_shapes['pythonloaded'])
255 else:
256 newspr = sprNew(tw,x-20,y-20,proto.image)
257 setlayer(newspr,2000)
258 tw.dragpos = 20,20
259 newspr.type = 'block'
260 newspr.proto = proto
261 if tw.defdict.has_key(newspr.proto.name):
262 newspr.label=tw.defdict[newspr.proto.name]
263 newspr.connections = [None]*len(proto.docks)
264 for i in range(len(proto.defaults)):
265 dock = proto.docks[i+1]
266 argproto = tw.protodict[tw.valdict[dock[0]]]
267 argdock = argproto.docks[0]
268 nx,ny = newspr.x+dock[2]-argdock[2],newspr.y+dock[3]-argdock[3]
269 argspr = sprNew(tw,nx,ny,argproto.image)
270 argspr.type = 'block'
271 argspr.proto = argproto
272 argspr.label = str(proto.defaults[i])
273 setlayer(argspr,2000)
274 argspr.connections = [newspr,None]
275 newspr.connections[i+1] = argspr
276 tw.draggroup = findgroup(newspr)
277 tw.block_operation = 'new'
276 """
277 unselect
278 """
279 def _unselect(self):
280 if self.selected_block.label in ['-', '.', '-.']:
281 setlabel(self.selected_block,'0')
278282
279def block_pressed(tw,mask,x,y,spr):
280 if spr is not None:
281 tw.draggroup = findgroup(spr)
282 for b in tw.draggroup: setlayer(b,2000)
283 if spr.connections[0] != None and spr.proto.name == 'lock':
284 b = find_top_block(spr)
285 tw.dragpos = x-b.x,y-b.y
283 # put an upper and lower bound on numbers to prevent OverflowError
284 if self.selected_block.proto.name == 'number' and \
285 self.selected_block.label is not None:
286 try:
287 i = float(self.selected_block.label)
288 if i > 1000000:
289 setlabel(self.selected_block,'1')
290 showlabel(self.lc,"#overflowerror")
291 elif i < -1000000:
292 setlabel(self.selected_block,'-1')
293 showlabel(self.lc,"#overflowerror")
294 except ValueError:
295 pass
296
297 hide(self.select_mask)
298 hide(self.select_mask_string)
299 self.selected_block = None
300
301
302 """
303 select category
304 """
305 def _select_category(self, spr):
306 if hasattr(self, 'current_category'):
307 setshape(self.current_category, self.current_category.offshape)
308 setshape(spr, spr.onshape)
309 self.current_category = spr
310 setshape(self.category_spr,spr.group)
311
312 """
313 hide palette
314 """
315 def _hide_palette(self):
316 for i in self.selbuttons: hide(i)
317 setshape(self.category_spr, self.hidden_palette_icon)
318 self.palette = False
319
320
321 """
322 register the events we listen to
323 """
324 def _setup_events(self):
325 self.window.add_events(gtk.gdk.BUTTON_PRESS_MASK)
326 self.window.add_events(gtk.gdk.BUTTON_RELEASE_MASK)
327 self.window.add_events(gtk.gdk.POINTER_MOTION_MASK)
328 self.window.add_events(gtk.gdk.KEY_PRESS_MASK)
329 self.window.connect("expose-event", self._expose_cb)
330 self.window.connect("button-press-event", self._buttonpress_cb)
331 self.window.connect("button-release-event", self._buttonrelease_cb)
332 self.window.connect("motion-notify-event", self._move_cb)
333 self.window.connect("key_press_event", self._keypress_cb)
334
335 def xy(self, event):
336 return map(int, event.get_coords())
337
338
339 """
340 find a stack to run (any stack without a hat)
341 """
342 def _find_block_to_run(self, spr):
343 top = self._find_top_block(spr)
344 if spr == top and spr.proto.name[0:3] != 'hat':
345 return True
286346 else:
287 tw.dragpos = x-spr.x,y-spr.y
288 disconnect(spr)
347 return False
289348
290def turtle_pressed(tw,x,y):
291 dx,dy = x-tw.turtle.spr.x-30,y-tw.turtle.spr.y-30
292 if dx*dx+dy*dy > 200:
293 tw.dragpos = ('turn', \
294 tw.turtle.heading-atan2(dy,dx)/DEGTOR,0)
295 else:
296 tw.dragpos = ('move', x-tw.turtle.spr.x,y-tw.turtle.spr.y)
297 tw.draggroup = [tw.turtle.spr]
349 """
350 find top block
351 """
352 def _find_top_block(self, spr):
353 b = spr
354 while b.connections[0]!=None:
355 b=b.connections[0]
356 return b
298357
299#
300# Mouse move
301#
358 """
359 find start stack
360 """
361 def _find_start_stack(self, spr):
362 top = self._find_top_block(spr)
363 if spr.proto.name == 'start':
364 return True
365 else:
366 return False
302367
303def move_cb(win, event, tw):
304 x,y = xy(event)
305 mouse_move(tw, x, y)
306 return True
368 """
369 tube available?
370 """
371 def _sharing(self):
372 ret = False
373 if hasattr(self, 'activity') and hasattr(self.activity, 'chattube'):
374 if self.activity.chattube is not None:
375 ret = True
376 return ret
307377
308def mouse_move(tw, x, y, verbose=False, mdx=0, mdy=0):
309 if verbose:
310 print "processing remote mouse move: " + str(x) + " " + str(y)
311 if tw.draggroup is None:
312 # popup help from RGS
313 spr = findsprite(tw,(x,y))
378
379 """
380 Mouse move
381 """
382 def _move_cb(self, win, event):
383 x,y = self.xy(event)
384 self._mouse_move(x, y)
385 return True
386
387 def _mouse_move(self, x, y, verbose=False, mdx=0, mdy=0):
388 if verbose:
389 print "processing remote mouse move: " + str(x) + " " + str(y)
390 if self.draggroup is None:
391 self._show_popup(x, y)
392 return
393
394 self.block_operation = 'move'
395 spr = self.draggroup[0]
396 if spr.type == 'block':
397 self.spr = spr
398 dragx, dragy = self.dragpos
399 if mdx != 0 or mdy != 0:
400 dx,dy = mdx,mdy
401 else:
402 dx,dy = x-dragx-spr.x,y-dragy-spr.y
403 # skip if there was a move of 0,0
404 if dx == 0 and dy == 0:
405 return
406 # drag entire stack if moving lock block
407 if spr.proto.name == 'lock':
408 self.draggroup = findgroup(find_top_block(spr))
409 else:
410 self.draggroup = findgroup(spr)
411 # check to see if any block ends up with a negative x
412 for b in self.draggroup:
413 if b.x+dx < 0:
414 dx += -(b.x+dx)
415 # move the stack
416 for b in self.draggroup:
417 move(b,(b.x+dx, b.y+dy))
418 elif spr.type=='turtle':
419 type,dragx,dragy = self.dragpos
420 if type == 'move':
421 if mdx != 0 or mdy != 0:
422 dx,dy = mdx,mdy
423 else:
424 dx,dy = x-dragx-spr.x,y-dragy-spr.y
425 move(spr, (spr.x+dx, spr.y+dy))
426 else:
427 if mdx != 0 or mdy != 0:
428 dx,dy = mdx,mdy
429 else:
430 dx,dy = x-spr.x-30,y-spr.y-30
431 seth(self.turtle, int(dragx+atan2(dy,dx)/DEGTOR+5)/10*10)
432 if mdx != 0 or mdy != 0:
433 dx,dy = 0,0
434 else:
435 self.dx += dx
436 self.dy += dy
437
438 """
439 get_proto_from_category
440 """
441 def _get_proto_from_category(self, x, y):
442 dx, dy = x-self.category_spr.x, y-self.category_spr.y,
443 pixel = getpixel(self.current_category.mask,dx,dy)
444 index = ((pixel%256)>>3)-1
445 if index==0:
446 return 'hide'
447 index-=1
448 if index>len(self.current_category.blockprotos):
449 return None
450 return self.current_category.blockprotos[index]
451
452 """
453 lets help our our user by displaying a little help
454 """
455 def _show_popup(self, x, y):
456 spr = findsprite(self, (x,y))
314457 if spr and spr.type == 'category':
315 proto = get_proto_from_category(tw,x,y)
458 proto = self._get_proto_from_category(x, y)
316459 if proto and proto!='hide':
317460 if timeout_tag[0] == 0:
318 timeout_tag[0] = showPopup(proto.name,tw)
319 tw.spr = spr
461 timeout_tag[0] = self._do_show_popup(proto.name)
462 self.spr = spr
320463 return
321464 else:
322465 if timeout_tag[0] > 0:
470470 timeout_tag[0] = 0
471471 elif spr and spr.type == 'selbutton':
472472 if timeout_tag[0] == 0:
473 timeout_tag[0] = showPopup(spr.name,tw)
474 tw.spr = spr
473 timeout_tag[0] = self._do_show_popup(spr.name)
474 self.spr = spr
475475 else:
476476 if timeout_tag[0] > 0:
477477 try:
481481 timeout_tag[0] = 0
482482 elif spr and spr.type == 'block':
483483 if timeout_tag[0] == 0:
484 timeout_tag[0] = showPopup(spr.proto.name,tw)
485 tw.spr = spr
484 timeout_tag[0] = self._do_show_popup(spr.proto.name)
485 self.spr = spr
486486 else:
487487 if timeout_tag[0] > 0:
488488 try:
497497 timeout_tag[0] = 0
498498 except:
499499 timeout_tag[0] = 0
500 return
501 tw.block_operation = 'move'
502 spr = tw.draggroup[0]
503 if spr.type == 'block':
504 tw.spr = spr
505 dragx, dragy = tw.dragpos
506 if mdx != 0 or mdy != 0:
507 dx,dy = mdx,mdy
500
501 """
502 fetch the help text and display it
503 """
504 def _do_show_popup(self, block_name):
505 if blocks_dict.has_key(block_name):
506 block_name_s = _(blocks_dict[block_name])
508507 else:
509 dx,dy = x-dragx-spr.x,y-dragy-spr.y
510 # skip if there was a move of 0,0
511 if dx == 0 and dy == 0:
512 return
513 # drag entire stack if moving lock block
514 if spr.proto.name == 'lock':
515 tw.draggroup = findgroup(find_top_block(spr))
508 block_name_s = _(block_name)
509 if hover_dict.has_key(block_name):
510 label = block_name_s + ": " + hover_dict[block_name]
516511 else:
517 tw.draggroup = findgroup(spr)
518 # check to see if any block ends up with a negative x
519 for b in tw.draggroup:
520 if b.x+dx < 0:
521 dx += -(b.x+dx)
522 # move the stack
523 for b in tw.draggroup:
524 move(b,(b.x+dx, b.y+dy))
525 elif spr.type=='turtle':
526 type,dragx,dragy = tw.dragpos
527 if type == 'move':
528 if mdx != 0 or mdy != 0:
529 dx,dy = mdx,mdy
530 else:
531 dx,dy = x-dragx-spr.x,y-dragy-spr.y
532 move(spr, (spr.x+dx, spr.y+dy))
533 else:
534 if mdx != 0 or mdy != 0:
535 dx,dy = mdx,mdy
536 else:
537 dx,dy = x-spr.x-30,y-spr.y-30
538 seth(tw.turtle, int(dragx+atan2(dy,dx)/DEGTOR+5)/10*10)
539 if mdx != 0 or mdy != 0:
540 dx,dy = 0,0
541 else:
542 tw.dx += dx
543 tw.dy += dy
512 label = block_name_s
513 if hasattr(self, "activity"):
514 self.activity.hover_help_label.set_text(label)
515 self.activity.hover_help_label.show()
516 elif hasattr(self, "win"):
517 self.win.set_title(_("Turtle Art") + " — " + label)
518 return 0
544519
545#
546# Button release
547#
548520
549def buttonrelease_cb(win, event, tw):
550 x,y = xy(event)
551 button_release(tw, x, y)
552 if hasattr(tw, 'activity') and \
553 hasattr(tw.activity, 'chattube') and tw.activity.chattube is not None:
554 # print "sending release button"
555 tw.activity._send_event("r:"+str(x)+":"+str(y))
556 return True
521 """
522 Keyboard
523 """
524 def _keypress_cb(self, area, event):
525 keyname = gtk.gdk.keyval_name(event.keyval)
526 keyunicode = gtk.gdk.keyval_to_unicode(event.keyval)
557527
558def button_release(tw, x, y, verbose=False):
559 if tw.dx != 0 or tw.dy != 0:
560 if hasattr(tw, 'activity') and \
561 hasattr(tw.activity, 'chattube') and \
562 tw.activity.chattube is not None:
563 if verbose:
564 print "processing move: " + str(tw.dx) + " " + str(tw.dy)
565 tw.activity._send_event("m:"+str(tw.dx)+":"+str(tw.dy))
566 tw.dx = 0
567 tw.dy = 0
568 if verbose:
569 print "processing remote button release: " + str(x) + " " + str(y)
570 if tw.draggroup == None:
571 return
572 spr = tw.draggroup[0]
573 if spr.type == 'turtle':
574 tw.turtle.xcor = tw.turtle.spr.x-tw.turtle.canvas.x- \
575 tw.turtle.canvas.width/2+30
576 tw.turtle.ycor = tw.turtle.canvas.height/2-tw.turtle.spr.y+ \
577 tw.turtle.canvas.y-30
578 move_turtle(tw.turtle)
579 display_coordinates(tw)
580 tw.draggroup = None
581 return
582 if tw.block_operation=='move' and hit(tw.category_spr, (x,y)):
583 for b in tw.draggroup: hide(b)
584 tw.draggroup = None
585 return
586 if tw.block_operation=='new':
587 for b in tw.draggroup:
588 move(b, (b.x+200, b.y))
589 snap_to_dock(tw)
590 for b in tw.draggroup: setlayer(b,650)
591 tw.draggroup = None
592 if tw.block_operation=='click':
593 if tw.spr.proto.name=='number':
594 tw.selected_block = spr
595 move(tw.select_mask, (spr.x-5,spr.y-5))
596 setlayer(tw.select_mask, 660)
597 tw.firstkey = True
598 elif tw.defdict.has_key(spr.proto.name):
599 tw.selected_block = spr
600 if tw.spr.proto.name=='string':
601 move(tw.select_mask_string, (spr.x-5,spr.y-5))
602 setlayer(tw.select_mask_string, 660)
603 tw.firstkey = True
604 elif tw.spr.proto.name in importblocks:
605 import_from_journal(tw, spr)
606 elif tw.spr.proto.name=='nop' and tw.myblock==None:
607 tw.activity.import_py()
608 else: run_stack(tw, spr)
609
610def import_from_journal(tw, spr):
611 if hasattr(tw,"activity"):
612 chooser = ObjectChooser('Choose image', None,\
613 gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT)
614 try:
615 result = chooser.run()
616 if result == gtk.RESPONSE_ACCEPT:
617 dsobject = chooser.get_selected_object()
618 # change block graphic to indicate that object is "loaded"
619 if spr.proto.name == 'journal':
620 load_image(tw, dsobject, spr)
621 elif spr.proto.name == 'audiooff':
622 setimage(spr,tw.media_shapes['audioon'])
623 else:
624 setimage(spr, tw.media_shapes['decson'])
625 spr.ds_id = dsobject.object_id
626 dsobject.destroy()
627 finally:
628 chooser.destroy()
629 del chooser
630 else:
631 print "Journal Object Chooser unavailable from outside of Sugar"
632
633# Replace Journal block graphic with preview image
634def load_image(tw, picture, spr):
635 from talogo import get_pixbuf_from_journal
636 pixbuf = get_pixbuf_from_journal(picture,spr.width,spr.height)
637 if pixbuf is not None:
638 setimage(spr, pixbuf)
639 else:
640 setimage(spr, tw.media_shapes['texton'])
641
642# change the icon for user-defined blocks after Python code is loaded
643def set_userdefined(tw):
644 list = tw.sprites[:]
645 for spr in list:
646 if hasattr(spr,'proto') and spr.proto.name == 'nop':
647 setimage(spr,tw.media_shapes['pythonloaded'])
648 tw.nop = 'pythonloaded'
649
650def snap_to_dock(tw):
651 d=200
652 me = tw.draggroup[0]
653 for mydockn in range(len(me.proto.docks)):
654 for you in blocks(tw):
655 if you in tw.draggroup:
656 continue
657 for yourdockn in range(len(you.proto.docks)):
658 thisxy = dock_dx_dy(you,yourdockn,me,mydockn)
659 if magnitude(thisxy)>d:
660 continue
661 d=magnitude(thisxy)
662 bestxy=thisxy
663 bestyou=you
664 bestyourdockn=yourdockn
665 bestmydockn=mydockn
666 if d<200:
667 for b in tw.draggroup:
668 move(b,(b.x+bestxy[0],b.y+bestxy[1]))
669 blockindock=bestyou.connections[bestyourdockn]
670 if blockindock!=None:
671 for b in findgroup(blockindock):
672 hide(b)
673 bestyou.connections[bestyourdockn]=me
674 me.connections[bestmydockn]=bestyou
675
676def dock_dx_dy(block1,dock1n,block2,dock2n):
677 dock1 = block1.proto.docks[dock1n]
678 dock2 = block2.proto.docks[dock2n]
679 d1type,d1dir,d1x,d1y=dock1[0:4]
680 d2type,d2dir,d2x,d2y=dock2[0:4]
681 if (d2type!='num') or (dock2n!=0):
682 if block1.connections[dock1n] != None:
683 return (100,100)
684 if block2.connections[dock2n] != None:
685 return (100,100)
686 if block1==block2: return (100,100)
687 if d1type!=d2type:
688 # some blocks can take strings or nums
689 if block1.proto.name in ('write', 'plus2', 'equal', 'less', 'greater', \
690 'template1', 'template2', 'template3', \
691 'template4', 'template6', 'template7', 'nop', \
692 'print', 'stack'):
693 if block1.proto.name == 'write' and d1type == 'string':
694 if d2type == 'num' or d2type == 'string':
695 pass
696 else:
697 if d2type == 'num' or d2type == 'string':
698 pass
699 # some blocks can take strings, nums, or Journal
700 elif block1.proto.name in ('show', 'push', 'storein', 'storeinbox1', \
701 'storeinbox2'):
702 if d2type == 'num' or d2type == 'string' or d2type == 'journal':
703 pass
704 # some blocks can take media, audio, movies, of descriptions
705 elif block1.proto.name in ('containter'):
706 if d1type == 'audiooff' or d1type == 'journal':
707 pass
528 if event.get_state()&gtk.gdk.MOD1_MASK:
529 alt_mask = True
708530 else:
709 return (100,100)
710 if d1dir==d2dir:
711 return (100,100)
712 return (block1.x+d1x)-(block2.x+d2x),(block1.y+d1y)-(block2.y+d2y)
531 alt_mask = False
532 results = self._key_press(alt_mask, keyname, keyunicode)
533 if keyname is not None and self._sharing():
534 if alt_mask:
535 self.activity._send_event("k:"+'T'+":"+keyname+":"+str(keyunicode))
536 else:
537 self.activity._send_event("k:"+'F'+":"+keyname+":"+str(keyunicode))
538 return keyname
713539
714def magnitude(pos):
715 x,y = pos
716 return x*x+y*y
717540
718#
719# Repaint
720#
721
722def expose_cb(win, event, tw):
723 redrawsprites(tw)
724 return True
725
726#
727# Keyboard
728#
729
730def keypress_cb(area, event, tw):
731 keyname = gtk.gdk.keyval_name(event.keyval)
732# keyunicode = unichr(gtk.gdk.keyval_to_unicode(event.keyval)).replace("\x00","")
733 keyunicode = gtk.gdk.keyval_to_unicode(event.keyval)
734# print keyname
735# if keyunicode > 0:
736# print unichr(keyunicode)
737
738 if event.get_state()&gtk.gdk.MOD1_MASK:
739 alt_mask = True
740 else:
741 alt_mask = False
742 results = key_press(tw, alt_mask, keyname, keyunicode)
743 if keyname is not None and hasattr(tw,"activity") and \
744 hasattr(tw.activity, 'chattube') and tw.activity.chattube is not None:
745 # print "key press"
746 if alt_mask:
747 tw.activity._send_event("k:"+'T'+":"+keyname+":"+str(keyunicode))
748 else:
749 tw.activity._send_event("k:"+'F'+":"+keyname+":"+str(keyunicode))
750 return keyname
751'''
752 if len(keyname)>1:
753 # print "(" + keyunicode.encode("utf-8") + ")"
754 return keyname
755 else:
756 # print "[" + keyunicode.encode("utf-8") + "]"
757 return keyunicode.encode("utf-8")
758'''
759def key_press(tw, alt_mask, keyname, keyunicode, verbose=False):
760 if keyname is None:
761 return False
762 if verbose:
763 print "processing remote key press: " + keyname
764 tw.keypress = keyname
765 if alt_mask is True and tw.selected_block==None:
766 if keyname=="i" and hasattr(tw, 'activity'):
767 tw.activity.waiting_for_blocks = True
768 tw.activity._send_event("i") # request sync for sharing
769 elif keyname=="p":
770 hideshow_button(tw)
771 elif keyname=='q':
772 exit()
773 return True
774 if tw.selected_block is not None and \
775 tw.selected_block.proto.name == 'number':
776 if keyname in ['minus', 'period']:
777 keyname = {'minus': '-', 'period': '.'}[keyname]
778 oldnum = tw.selected_block.label
779 selblock=tw.selected_block.proto
541 def _key_press(self, alt_mask, keyname, keyunicode, verbose=False):
542 if keyname is None:
543 return False
544 if verbose:
545 print "processing remote key press: " + keyname
546 self.keypress = keyname
547 if alt_mask is True and self.selected_block==None:
548 if keyname=="i" and hasattr(self, 'activity'):
549 self.activity.waiting_for_blocks = True
550 self.activity._send_event("i") # request sync for sharing
551 elif keyname=="p":
552 self.hideshow_button()
553 elif keyname=='q':
554 exit()
555 return True
556 if self.selected_block is not None and \
557 self.selected_block.proto.name == 'number':
558 if keyname in ['minus', 'period']:
559 keyname = {'minus': '-', 'period': '.'}[keyname]
560 oldnum = self.selected_block.label
561 selblock=self.selected_block.proto
562 if keyname == 'BackSpace':
563 if len(oldnum) > 1:
564 newnum = oldnum[:len(oldnum)-1]
565 else:
566 newnum = ''
567 setlabel(self.selected_block, selblock.check(newnum,oldnum))
568 if len(newnum) > 0:
569 self.firstkey = False
570 else:
571 self.firstkey = True
572 if len(keyname)>1:
573 return True
574 else: # gtk.keysyms.Left ...
575 if keyname in ['Escape', 'Return', 'j', 'k', 'h', 'l', 'KP_Page_Up',
576 'Up', 'Down', 'Left', 'Right', 'KP_Home', 'KP_End',
577 'KP_Up', 'KP_Down', 'KP_Left', 'KP_Right',
578 'KP_Page_Down']:
579 # move blocks (except number and text blocks only with arrows)
580 # or click with Return
581 if keyname == 'KP_End':
582 self.run_button(0)
583 elif self.spr is not None:
584 if self.spr.type == 'turtle': # jog turtle with arrow keys
585 if keyname == 'KP_Up' or keyname == 'j' or keyname == 'Up':
586 self._jog_turtle(0,10)
587 elif keyname == 'KP_Down' or keyname == 'k' or \
588 keyname == 'Down':
589 self._jog_turtle(0,-10)
590 elif keyname == 'KP_Left' or keyname == 'h' or \
591 keyname == 'Left':
592 self._jog_turtle(-10,0)
593 elif keyname == 'KP_Right' or keyname == 'l' or \
594 keyname == 'Right':
595 self._jog_turtle(10,0)
596 elif keyname == 'KP_Home':
597 self._jog_turtle(-1,-1)
598 elif self.spr.type == 'block':
599 if keyname == 'Return' or keyname == 'KP_Page_Up':
600 self._click_block()
601 elif keyname == 'KP_Up' or keyname == 'j' or \
602 keyname == 'Up':
603 self._jog_block(0,10)
604 elif keyname == 'KP_Down' or keyname == 'k' or \
605 keyname == 'Down':
606 self._jog_block(0,-10)
607 elif keyname == 'KP_Left' or keyname == 'h' or \
608 keyname == 'Left':
609 self._jog_block(-10,0)
610 elif keyname == 'KP_Right' or keyname == 'l' or \
611 keyname == 'Right':
612 self._jog_block(10,0)
613 elif keyname == 'KP_Page_Down':
614 if self.draggroup == None:
615 self.draggroup = findgroup(self.spr)
616 for b in self.draggroup: hide(b)
617 self.draggroup = None
618 elif self.spr.type == 'selbutton':
619 if keyname == 'Return' or keyname == 'KP_Page_Up':
620 self._select_category(self.spr)
621 elif self.spr.type == 'category':
622 if keyname == 'Return' or keyname == 'KP_Page_Up':
623 (x,y) = self.window.get_pointer()
624 self._block_selector_pressed(x, y)
625 for b in self.draggroup:
626 move(b, (b.x+200, b.y))
627 self.draggroup = None
628 return True
629 if self.selected_block is None:
630 return False
631 if keyname in ['Shift_L', 'Shift_R', 'Control_L', 'Caps_Lock', \
632 'Alt_L', 'Alt_R', 'KP_Enter', 'ISO_Level3_Shift']:
633 keyname = ''
634 keyunicode = 0
635 # Hack until I sort out input and unicode + dead keys
636 if keyname[0:5] == 'dead_':
637 self.dead_key = keyname
638 keyname = ''
639 keyunicode = 0
640 if keyname == 'Tab':
641 keyunicode = 32 # substitute a space for a tab
642 oldnum = self.selected_block.label
643 selblock=self.selected_block.proto
780644 if keyname == 'BackSpace':
781645 if len(oldnum) > 1:
782646 newnum = oldnum[:len(oldnum)-1]
783647 else:
784648 newnum = ''
785 setlabel(tw.selected_block, selblock.check(newnum,oldnum))
649 setlabel(self.selected_block, selblock.check(newnum,oldnum))
786650 if len(newnum) > 0:
787 tw.firstkey = False
651 self.firstkey = False
788652 else:
789 tw.firstkey = True
790 if len(keyname)>1:
791 return True
792 else: # gtk.keysyms.Left ...
793 if keyname in ['Escape', 'Return', 'j', 'k', 'h', 'l', 'KP_Page_Up',
794 'Up', 'Down', 'Left', 'Right', 'KP_Home', 'KP_End',
795 'KP_Up', 'KP_Down', 'KP_Left', 'KP_Right',
796 'KP_Page_Down']:
797 # move blocks (except number and text blocks only with arrows)
798 # or click with Return
799 if keyname == 'KP_End':
800 run_button(tw, 0)
801 elif tw.spr is not None:
802 if tw.spr.type == 'turtle': # jog turtle with arrow keys
803 if keyname == 'KP_Up' or keyname == 'j' or keyname == 'Up':
804 jog_turtle(tw,0,10)
805 elif keyname == 'KP_Down' or keyname == 'k' or \
806 keyname == 'Down':
807 jog_turtle(tw,0,-10)
808 elif keyname == 'KP_Left' or keyname == 'h' or \
809 keyname == 'Left':
810 jog_turtle(tw,-10,0)
811 elif keyname == 'KP_Right' or keyname == 'l' or \
812 keyname == 'Right':
813 jog_turtle(tw,10,0)
814 elif keyname == 'KP_Home':
815 jog_turtle(tw,-1,-1)
816 elif tw.spr.type == 'block':
817 if keyname == 'Return' or keyname == 'KP_Page_Up':
818 click_block(tw)
819 elif keyname == 'KP_Up' or keyname == 'j' or \
820 keyname == 'Up':
821 jog_block(tw,0,10)
822 elif keyname == 'KP_Down' or keyname == 'k' or \
823 keyname == 'Down':
824 jog_block(tw,0,-10)
825 elif keyname == 'KP_Left' or keyname == 'h' or \
826 keyname == 'Left':
827 jog_block(tw,-10,0)
828 elif keyname == 'KP_Right' or keyname == 'l' or \
829 keyname == 'Right':
830 jog_block(tw,10,0)
831 elif keyname == 'KP_Page_Down':
832 if tw.draggroup == None:
833 tw.draggroup = findgroup(tw.spr)
834 for b in tw.draggroup: hide(b)
835 tw.draggroup = None
836 elif tw.spr.type == 'selbutton':
837 if keyname == 'Return' or keyname == 'KP_Page_Up':
838 select_category(tw,tw.spr)
839 elif tw.spr.type == 'category':
840 if keyname == 'Return' or keyname == 'KP_Page_Up':
841 (x,y) = tw.window.get_pointer()
842 block_selector_pressed(tw,x,y)
843 for b in tw.draggroup:
844 move(b, (b.x+200, b.y))
845 tw.draggroup = None
846 return True
847 if tw.selected_block is None:
848 return False
849 if keyname in ['Shift_L', 'Shift_R', 'Control_L', 'Caps_Lock', \
850 'Alt_L', 'Alt_R', 'KP_Enter', 'ISO_Level3_Shift']:
851 keyname = ''
852 keyunicode = 0
853 # Hack until I sort out input and unicode + dead keys
854 if keyname[0:5] == 'dead_':
855 tw.dead_key = keyname
856 keyname = ''
857 keyunicode = 0
858 if keyname == 'Tab':
859 keyunicode = 32 # substitute a space for a tab
860 oldnum = tw.selected_block.label
861 selblock=tw.selected_block.proto
862 if keyname == 'BackSpace':
863 if len(oldnum) > 1:
864 newnum = oldnum[:len(oldnum)-1]
865 else:
866 newnum = ''
867 setlabel(tw.selected_block, selblock.check(newnum,oldnum))
868 if len(newnum) > 0:
869 tw.firstkey = False
870 else:
871 tw.firstkey = True
872 elif keyname is not '':
873 # Hack until I sort out input and unicode + dead keys
874 if tw.dead_key == 'dead_grave':
875 keyunicode = dead_grave[keyname]
876 elif tw.dead_key == 'dead_acute':
877 keyunicode = dead_acute[keyname]
878 elif tw.dead_key == 'dead_circumflex':
879 keyunicode = dead_circumflex[keyname]
880 elif tw.dead_key == 'dead_tilde':
881 keyunicode = dead_tilde[keyname]
882 elif tw.dead_key == 'dead_diaeresis':
883 keyunicode = dead_diaeresis[keyname]
884 elif tw.dead_key == 'dead_abovering':
885 keyunicode = dead_abovering[keyname]
886 tw.dead_key = ""
887 if tw.firstkey:
888 newnum = selblock.check(unichr(keyunicode), \
889 tw.defdict[selblock.name])
890 elif keyunicode > 0:
891 if unichr(keyunicode) is not '\x00':
892 newnum = oldnum+unichr(keyunicode)
653 self.firstkey = True
654 elif keyname is not '':
655 # Hack until I sort out input and unicode + dead keys
656 if self.dead_key == 'dead_grave':
657 keyunicode = dead_grave[keyname]
658 elif self.dead_key == 'dead_acute':
659 keyunicode = dead_acute[keyname]
660 elif self.dead_key == 'dead_circumflex':
661 keyunicode = dead_circumflex[keyname]
662 elif self.dead_key == 'dead_tilde':
663 keyunicode = dead_tilde[keyname]
664 elif self.dead_key == 'dead_diaeresis':
665 keyunicode = dead_diaeresis[keyname]
666 elif self.dead_key == 'dead_abovering':
667 keyunicode = dead_abovering[keyname]
668 self.dead_key = ""
669 if self.firstkey:
670 newnum = selblock.check(unichr(keyunicode), \
671 self.defdict[selblock.name])
672 elif keyunicode > 0:
673 if unichr(keyunicode) is not '\x00':
674 newnum = oldnum+unichr(keyunicode)
675 else:
676 newnum = oldnum
893677 else:
894 newnum = oldnum
895 else:
896 newnum = ""
897 setlabel(tw.selected_block, selblock.check(newnum,oldnum))
898 tw.firstkey = False
899 return True
678 newnum = ""
679 setlabel(self.selected_block, selblock.check(newnum,oldnum))
680 self.firstkey = False
681 return True
900682
901def unselect(tw):
902 if tw.selected_block.label in ['-', '.', '-.']:
903 setlabel(tw.selected_block,'0')
904683
905 # put an upper and lower bound on numbers to prevent OverflowError
906 if tw.selected_block.proto.name == 'number' and \
907 tw.selected_block.label is not None:
908 try:
909 i = float(tw.selected_block.label)
910 if i > 1000000:
911 setlabel(tw.selected_block,'1')
912 showlabel(tw.lc,"#overflowerror")
913 elif i < -1000000:
914 setlabel(tw.selected_block,'-1')
915 showlabel(tw.lc,"#overflowerror")
916 except ValueError:
917 pass
918684
919 hide(tw.select_mask)
920 hide(tw.select_mask_string)
921 tw.selected_block = None
922685
923def jog_turtle(tw,dx,dy):
924 if dx == -1 and dy == -1:
925 tw.turtle.xcor = 0
926 tw.turtle.ycor = 0
927 else:
928 tw.turtle.xcor += dx
929 tw.turtle.ycor += dy
930 move_turtle(tw.turtle)
931 display_coordinates(tw)
932 tw.draggroup = None
686 """
687 Button release
688 """
689 def _buttonrelease_cb(self, win, event):
690 x,y = self.xy(event)
691 self.button_release(x, y)
692 if self._sharing():
693 # print "sending release button"
694 self.activity._send_event("r:"+str(x)+":"+str(y))
695 return True
933696
934def jog_block(tw,dx,dy):
935 # drag entire stack if moving lock block
936 if tw.spr.proto.name == 'lock':
937 tw.draggroup = findgroup(find_top_block(tw.spr))
938 else:
939 tw.draggroup = findgroup(tw.spr)
940 # check to see if any block ends up with a negative x
941 for b in tw.draggroup:
942 if b.x+dx < 0:
943 dx += -(b.x+dx)
944 # move the stack
945 for b in tw.draggroup:
946 move(b,(b.x+dx, b.y-dy))
947 snap_to_dock(tw)
948 tw.draggroup = None
697 def button_release(self, x, y, verbose=False):
698 if self.dx != 0 or self.dy != 0:
699 if self._sharing():
700 if verbose:
701 print "processing move: " + str(self.dx) + " " + str(self.dy)
702 self.activity._send_event("m:"+str(self.dx)+":"+str(self.dy))
703 self.dx = 0
704 self.dy = 0
949705
950def click_block(tw):
951 if tw.spr.proto.name=='number':
952 tw.selected_block = tw.spr
953 move(tw.select_mask, (tw.spr.x-5,tw.spr.y-5))
954 setlayer(tw.select_mask, 660)
955 tw.firstkey = True
956 elif tw.defdict.has_key(tw.spr.proto.name):
957 tw.selected_block = tw.spr
958 if tw.spr.proto.name=='string':
959 move(tw.select_mask_string, (tw.spr.x-5,tw.spr.y-5))
960 setlayer(tw.select_mask_string, 660)
961 tw.firstkey = True
962 elif tw.spr.proto.name in importblocks:
963 import_from_journal(tw, tw.spr)
964 elif tw.spr.proto.name=='nop' and tw.myblock==None:
965 tw.activity.import_py()
966 else: run_stack(tw, tw.spr)
706 if verbose:
707 print "processing remote button release: " + str(x) + " " + str(y)
708 if self.draggroup == None:
709 return
710 spr = self.draggroup[0]
711 if spr.type == 'turtle':
712 self.turtle.xcor = self.turtle.spr.x-self.turtle.canvas.x- \
713 self.turtle.canvas.width/2+30
714 self.turtle.ycor = self.turtle.canvas.height/2-self.turtle.spr.y+ \
715 self.turtle.canvas.y-30
716 move_turtle(self.turtle)
717 display_coordinates(self)
718 self.draggroup = None
719 return
720 if self.block_operation=='move' and hit(self.category_spr, (x,y)):
721 for b in self.draggroup: hide(b)
722 self.draggroup = None
723 return
724 if self.block_operation=='new':
725 for b in self.draggroup:
726 move(b, (b.x+200, b.y))
727 self._snap_to_dock()
728 for b in self.draggroup: setlayer(b,650)
729 self.draggroup = None
730 if self.block_operation=='click':
731 if self.spr.proto.name=='number':
732 self.selected_block = spr
733 move(self.select_mask, (spr.x-5,spr.y-5))
734 setlayer(self.select_mask, 660)
735 self.firstkey = True
736 elif self.defdict.has_key(spr.proto.name):
737 self.selected_block = spr
738 if self.spr.proto.name=='string':
739 move(self.select_mask_string, (spr.x-5,spr.y-5))
740 setlayer(self.select_mask_string, 660)
741 self.firstkey = True
742 elif self.spr.proto.name in importblocks:
743 self._import_from_journal(spr)
744 elif self.spr.proto.name=='nop' and self.myblock==None:
745 self.activity.import_py()
746 else: self._run_stack(spr)
967747
968#
969# Block utilities
970#
748 """
749 click block
750 """
751 def _click_block(self):
752 if self.spr.proto.name=='number':
753 self.selected_block = self.spr
754 move(self.select_mask, (self.spr.x-5,self.spr.y-5))
755 setlayer(self.select_mask, 660)
756 self.firstkey = True
757 elif self.defdict.has_key(self.spr.proto.name):
758 self.selected_block = self.spr
759 if self.spr.proto.name=='string':
760 move(self.select_mask_string, (self.spr.x-5,self.spr.y-5))
761 setlayer(self.select_mask_string, 660)
762 self.firstkey = True
763 elif self.spr.proto.name in importblocks:
764 self._import_from_journal(self.spr)
765 elif self.spr.proto.name=='nop' and self.myblock==None:
766 self.activity.import_py()
767 else: self._run_stack(self.spr)
971768
972def disconnect(b):
973 if b.connections[0]==None:
974 return
975 b2=b.connections[0]
976 b2.connections[b2.connections.index(b)] = None
977 b.connections[0] = None
769 """
770 Repaint
771 """
772 def _expose_cb(self, win, event):
773 # FIXME
774 redrawsprites(self)
775 return True
978776
979def run_stack(tw,spr):
980 tw.lc.ag = None
981 top = find_top_block(spr)
982 run_blocks(tw.lc, top, blocks(tw), True)
983 gobject.idle_add(doevalstep, tw.lc)
777 """
778 Button Press
779 """
780 def _buttonpress_cb(self, win, event):
781 self.window.grab_focus()
782 x, y = self.xy(event)
783 self.button_press(event.get_state()&gtk.gdk.CONTROL_MASK, x, y)
784
785 # if sharing, send button press
786 if self._sharing():
787 # print "sending button pressed"
788 if event.get_state()&gtk.gdk.CONTROL_MASK is True:
789 self.activity._send_event("p:"+str(x)+":"+str(y)+":"+'T')
790 else:
791 self.activity._send_event("p:"+str(x)+":"+str(y)+":"+'F')
792 return True
984793
985def findgroup(b):
986 group=[b]
987 for b2 in b.connections[1:]:
988 if b2!=None: group.extend(findgroup(b2))
989 return group
990794
991def find_top_block(spr):
992 b = spr
993 while b.connections[0]!=None:
994 b=b.connections[0]
995 return b
795 """
796 snap_to_dock
797 """
798 def _snap_to_dock(self):
799 d=200
800 me = self.draggroup[0]
801 for mydockn in range(len(me.proto.docks)):
802 for you in self._blocks():
803 if you in self.draggroup:
804 continue
805 for yourdockn in range(len(you.proto.docks)):
806 thisxy = self._dock_dx_dy(you,yourdockn,me,mydockn)
807 if self._magnitude(thisxy) > d:
808 continue
809 d = self._magnitude(thisxy)
810 bestxy=thisxy
811 bestyou=you
812 bestyourdockn=yourdockn
813 bestmydockn=mydockn
814 if d<200:
815 for b in self.draggroup:
816 move(b,(b.x+bestxy[0],b.y+bestxy[1]))
817 blockindock=bestyou.connections[bestyourdockn]
818 if blockindock!=None:
819 for b in findgroup(blockindock):
820 hide(b)
821 bestyou.connections[bestyourdockn]=me
822 me.connections[bestmydockn]=bestyou
996823
997def runtool(tw, spr, cmd, *args):
998 cmd(*(args))
999824
1000def eraser_button(tw):
1001 # hide status block
1002 setlayer(tw.status_spr,400)
1003 clear(tw.lc)
1004 display_coordinates(tw)
825 """
826 import from Journal
827 """
828 def _import_from_journal(self, spr):
829 if hasattr(self, "activity"): # this should be a method: _inside_sugar()
830 chooser = ObjectChooser('Choose image', None,\
831 gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT)
832 try:
833 result = chooser.run()
834 if result == gtk.RESPONSE_ACCEPT:
835 dsobject = chooser.get_selected_object()
836 # change block graphic to indicate that object is "loaded"
837 if spr.proto.name == 'journal':
838 self._load_image(dsobject, spr)
839 elif spr.proto.name == 'audiooff':
840 setimage(spr,self.media_shapes['audioon'])
841 else:
842 setimage(spr, self.media_shapes['decson'])
843 spr.ds_id = dsobject.object_id
844 dsobject.destroy()
845 finally:
846 chooser.destroy()
847 del chooser
848 else:
849 print "Journal Object Chooser unavailable from outside of Sugar"
1005850
1006def stop_button(tw):
1007 stop_logo(tw)
851 """
852 run stack
853 """
854 def _run_stack(self, spr):
855 self.lc.ag = None
856 top = self._find_top_block(spr)
857 run_blocks(self.lc, top, self._blocks(), True)
858 gobject.idle_add(doevalstep, self.lc)
1008859
1009def run_button(tw, time):
1010 print "you better run, turtle, run!!"
1011 # look for the start block
1012 for b in blocks(tw):
1013 if find_start_stack(tw, b):
1014 tw.step_time = time
1015 if hasattr(tw,'activity'):
1016 tw.activity.recenter()
1017 run_stack(tw, b)
860 """
861 filter out blocks
862 """
863 def _blocks(self):
864 return [spr for spr in self.sprites if spr.type == 'block']
865
866 """
867 block selector pressed
868 """
869 def _block_selector_pressed(self, x, y):
870 proto = self._get_proto_from_category(x, y)
871 if proto==None:
1018872 return
1019 # no start block, so run a stack that isn't a hat
1020 for b in blocks(tw):
1021 if find_block_to_run(tw, b):
1022 print "running " + b.proto.name
1023 tw.step_time = time
1024 run_stack(tw, b)
1025 return
873 if proto is not 'hide':
874 self._new_block_from_category(proto, x, y)
875 else:
876 self.hideshow_palette(False)
1026877
1027def hideshow_button(tw):
1028 if tw.hide is False:
1029 for b in blocks(tw): setlayer(b,100)
1030 hide_palette(tw)
1031 hide(tw.select_mask)
1032 hide(tw.select_mask_string)
1033 tw.hide = True
1034 else:
1035 for b in blocks(tw): setlayer(b,650)
1036 show_palette(tw)
1037 tw.hide = False
1038 inval(tw.turtle.canvas)
1039878
1040# find start stack
1041def find_start_stack(tw, spr):
1042 top = find_top_block(spr)
1043 if spr.proto.name == 'start':
1044 return True
1045 else:
1046 return False
879 """
880 new block from category
881 """
882 def _new_block_from_category(self, proto, x, y):
883 if proto is None:
884 return True
885 # load alternative image of nop block if python code is loaded
886 if proto.name == 'nop' and self.nop == 'pythonloaded':
887 newspr = sprNew(self,x-20,y-20,self.media_shapes['pythonloaded'])
888 else:
889 newspr = sprNew(self,x-20,y-20,proto.image)
890 setlayer(newspr,2000)
891 self.dragpos = 20,20
892 newspr.type = 'block'
893 newspr.proto = proto
894 if self.defdict.has_key(newspr.proto.name):
895 newspr.label=self.defdict[newspr.proto.name]
896 newspr.connections = [None]*len(proto.docks)
897 for i in range(len(proto.defaults)):
898 dock = proto.docks[i+1]
899 argproto = self.protodict[self.valdict[dock[0]]]
900 argdock = argproto.docks[0]
901 nx,ny = newspr.x+dock[2]-argdock[2],newspr.y+dock[3]-argdock[3]
902 argspr = sprNew(self,nx,ny,argproto.image)
903 argspr.type = 'block'
904 argspr.proto = argproto
905 argspr.label = str(proto.defaults[i])
906 setlayer(argspr,2000)
907 argspr.connections = [newspr,None]
908 newspr.connections[i+1] = argspr
909 self.draggroup = findgroup(newspr)
910 self.block_operation = 'new'
1047911
1048# find a stack to run (any stack without a hat)
1049def find_block_to_run(tw, spr):
1050 top = find_top_block(spr)
1051 if spr == top and spr.proto.name[0:3] != 'hat':
1052 return True
1053 else:
1054 return False
1055912
1056def blocks(tw):
1057 return [spr for spr in tw.sprites if spr.type == 'block']
913 """
914 block pressed
915 """
916 def _block_pressed(self, mask, x, y, spr):
917 if spr is not None:
918 self.draggroup = findgroup(spr)
919 for b in self.draggroup: setlayer(b,2000)
920 if spr.connections[0] != None and spr.proto.name == 'lock':
921 b = self._find_top_block(spr)
922 self.dragpos = x-b.x,y-b.y
923 else:
924 self.dragpos = x-spr.x,y-spr.y
925 self._disconnect(spr)
1058926
1059def xy(event):
1060 return map(int, event.get_coords())
1061927
1062def showPopup(block_name,tw):
1063 if blocks_dict.has_key(block_name):
1064 block_name_s = _(blocks_dict[block_name])
1065 else:
1066 block_name_s = _(block_name)
1067 if hover_dict.has_key(block_name):
1068 label = block_name_s + ": " + hover_dict[block_name]
1069 else:
1070 label = block_name_s
1071 if hasattr(tw, "activity"):
1072 tw.activity.hover_help_label.set_text(label)
1073 tw.activity.hover_help_label.show()
1074 elif hasattr(tw, "win"):
1075 tw.win.set_title(_("Turtle Art") + " — " + label)
1076 return 0
928 """
929 disconnect block
930 """
931 def _disconnect(self, b):
932 if b.connections[0]==None:
933 return
934 b2=b.connections[0]
935 b2.connections[b2.connections.index(b)] = None
936 b.connections[0] = None
937
938 """
939 turtle pressed
940 """
941 def _turtle_pressed(self, x, y):
942 dx,dy = x-self.turtle.spr.x-30,y-self.turtle.spr.y-30
943 if dx*dx+dy*dy > 200:
944 self.dragpos = ('turn', \
945 self.turtle.heading-atan2(dy,dx)/DEGTOR,0)
946 else:
947 self.dragpos = ('move', x-self.turtle.spr.x,y-self.turtle.spr.y)
948 self.draggroup = [self.turtle.spr]
949
950
951 """
952 Replace Journal block graphic with preview image
953 """
954 def _load_image(self, picture, spr):
955 from talogo import get_pixbuf_from_journal
956 pixbuf = get_pixbuf_from_journal(picture,spr.width,spr.height)
957 if pixbuf is not None:
958 setimage(spr, pixbuf)
959 else:
960 setimage(spr, self.media_shapes['texton'])
961
962
963 """
964 dock_dx_dy
965 """
966 def _dock_dx_dy(self, block1, dock1n, block2, dock2n):
967 dock1 = block1.proto.docks[dock1n]
968 dock2 = block2.proto.docks[dock2n]
969 d1type,d1dir,d1x,d1y=dock1[0:4]
970 d2type,d2dir,d2x,d2y=dock2[0:4]
971 if (d2type!='num') or (dock2n!=0):
972 if block1.connections[dock1n] != None:
973 return (100,100)
974 if block2.connections[dock2n] != None:
975 return (100,100)
976 if block1==block2: return (100,100)
977 if d1type!=d2type:
978 # some blocks can take strings or nums
979 if block1.proto.name in ('write', 'plus2', 'equal', 'less', 'greater', \
980 'template1', 'template2', 'template3', \
981 'template4', 'template6', 'template7', 'nop', \
982 'print', 'stack'):
983 if block1.proto.name == 'write' and d1type == 'string':
984 if d2type == 'num' or d2type == 'string':
985 pass
986 else:
987 if d2type == 'num' or d2type == 'string':
988 pass
989 # some blocks can take strings, nums, or Journal
990 elif block1.proto.name in ('show', 'push', 'storein', 'storeinbox1', \
991 'storeinbox2'):
992 if d2type == 'num' or d2type == 'string' or d2type == 'journal':
993 pass
994 # some blocks can take media, audio, movies, of descriptions
995 elif block1.proto.name in ('containter'):
996 if d1type == 'audiooff' or d1type == 'journal':
997 pass
998 else:
999 return (100,100)
1000 if d1dir==d2dir:
1001 return (100,100)
1002 return (block1.x+d1x)-(block2.x+d2x),(block1.y+d1y)-(block2.y+d2y)
1003
1004 """
1005 magnitude
1006 """
1007 def _magnitude(self, pos):
1008 x,y = pos
1009 return x*x+y*y
1010
1011 """
1012 jog turtle
1013 """
1014 def _jog_turtle(self, dx, dy):
1015 if dx == -1 and dy == -1:
1016 self.turtle.xcor = 0
1017 self.turtle.ycor = 0
1018 else:
1019 self.turtle.xcor += dx
1020 self.turtle.ycor += dy
1021 move_turtle(self.turtle)
1022 display_coordinates(self)
1023 self.draggroup = None
1024
1025 """
1026 jog block
1027 """
1028 def _jog_block(self,dx,dy):
1029 # drag entire stack if moving lock block
1030 if self.spr.proto.name == 'lock':
1031 self.draggroup = findgroup(self._find_top_block(self.spr))
1032 else:
1033 self.draggroup = findgroup(self.spr)
1034 # check to see if any block ends up with a negative x
1035 for b in self.draggroup:
1036 if b.x+dx < 0:
1037 dx += -(b.x+dx)
1038 # move the stack
1039 for b in self.draggroup:
1040 move(b,(b.x+dx, b.y-dy))
1041 self._snap_to_dock()
1042 self.draggroup = None
  
135135 menu_bar.append(project_menu)
136136
137137 win.show_all()
138 self.tw = twNew(canvas, os.path.abspath('.'), lang)
138 self.tw = TurtleArtWindow(canvas, os.path.abspath('.'), lang)
139139 self.tw.win = win
140140
141141 def _do_open_cb(self, widget):
146146
147147 def _do_palette_cb(self, widget):
148148 if self.tw.palette == True:
149 hideshow_palette(self.tw,False)
149 self.tw.hideshow_palette(False)
150150 else:
151 hideshow_palette(self.tw,True)
151 self.tw.hideshow_palette(True)
152152
153153 def _do_hideshow_cb(self, widget):
154 hideshow_button(self.tw)
154 self.tw.hideshow_button()
155155
156156 def _do_eraser_cb(self, widget):
157 eraser_button(self.tw)
157 self.tw.eraser_button()
158158 return
159159
160160 def _do_run_cb(self, widget):
161161 self.tw.lc.trace = 0
162 runbutton(self.tw, 0)
162 self.tw.runbutton(0)
163163 return
164164
165165 def _do_step_cb(self, widget):
166166 self.tw.lc.trace = 0
167 runbutton(self.tw, 3)
167 self.tw.runbutton(3)
168168 return
169169
170170 def _do_stop_cb(self, widget):