Revisión | 4a966ff0d08f9003f54fa8bcf85bd7f2f54ebf03 (tree) |
---|---|
Tiempo | 2013-03-03 19:25:24 |
Autor | bijoux |
Commiter | bijoux |
change behavior of getports
@@ -1,4 +1,5 @@ | ||
1 | 1 | from ingredient import * |
2 | 2 | from chef import Recipe |
3 | 3 | import chef |
4 | +import data | |
4 | 5 | import vtkext |
@@ -4,6 +4,7 @@ | ||
4 | 4 | import time |
5 | 5 | import threading |
6 | 6 | import inspect |
7 | +import types | |
7 | 8 | import imp |
8 | 9 | import uuid |
9 | 10 | import random |
@@ -13,8 +14,24 @@ | ||
13 | 14 | import Tkinter |
14 | 15 | import ttk |
15 | 16 | import ingredient as laf |
17 | +import data | |
16 | 18 | from ingredient import rule,event,Logic,Port |
17 | 19 | |
20 | +def editable(logic): | |
21 | + ''' | |
22 | + コントロールパネルで自動生成可能なポートを返す | |
23 | + ''' | |
24 | + MYTYPES = (types.IntType,types.FloatType,types.StringType, | |
25 | + numpy.float64,numpy.int64,data.SpecificData) | |
26 | + members = {} | |
27 | + for k,v in laf.getproxports(logic).iteritems(): | |
28 | + value = v.actualport(logic).container.value | |
29 | + for t in MYTYPES: | |
30 | + if isinstance(value,t): | |
31 | + members[k] = v | |
32 | + break | |
33 | + return members | |
34 | + | |
18 | 35 | def getClass(domelement): |
19 | 36 | module_name = domelement.getAttribute('module') |
20 | 37 | cls_name = domelement.getAttribute('cls') |
@@ -214,6 +231,7 @@ | ||
214 | 231 | self.generate_myports() |
215 | 232 | self.bind('<Button1-Motion>',self.leftdrag) |
216 | 233 | self.bind('<Button1-ButtonRelease>',self.leftrelease) |
234 | + self.bind('<Double-Button-1>',self.popup_equipment) | |
217 | 235 | self.bind('<Button-2>',lambda e:self.canvas.rmenu.queue((self.Menu,self,e))) |
218 | 236 | self.event.bind('<<CheckModel>>',self.check_model) |
219 | 237 | @property |
@@ -270,7 +288,7 @@ | ||
270 | 288 | x,y = self.loc |
271 | 289 | lports,rports = {},{} |
272 | 290 | #FIXME: current status |
273 | - for name,port in laf.getports(self.logic).iteritems(): | |
291 | + for name,port in laf.getproxports(self.logic).iteritems(): | |
274 | 292 | # 右に表示するか左に表示するか振り分け |
275 | 293 | if isinstance(port,laf.Rule): |
276 | 294 | rports[name] = port |
@@ -278,7 +296,128 @@ | ||
278 | 296 | lports[name] = port |
279 | 297 | generate(lports,-50,direction=Tkinter.LEFT) |
280 | 298 | generate(rports,50,direction=Tkinter.RIGHT) |
299 | + def popup_equipment(self,e): # for Tk Event | |
300 | + logic = self.logic | |
301 | + module = inspect.getmodule(logic) | |
302 | +# recipes = [] | |
303 | +# for k,v in sys.modules[module.__name__].__dict__.iteritems(): | |
304 | +# if inspect.isclass(v): | |
305 | +# for cls in inspect.getmro(v): | |
306 | +# if cls == Recipe: | |
307 | +# if not v.RECIPIENT == None: | |
308 | +# if isinstance(self.logic,v.RECIPIENT): | |
309 | +# recipes.append(v) | |
310 | +# break | |
311 | +# chef = self.canvas.chef | |
312 | +# if recipes: | |
313 | +# recipe = recipes[0]() | |
314 | +# w = chef.cook(recipe,Tkinter.Toplevel(chef)) | |
315 | +# w.connect(self.logic) | |
316 | +# w.pack() | |
317 | +# else: | |
318 | +# if editable(self.logic): | |
319 | +# ControlPanel(Tkinter.Toplevel(chef),logic=self.logic).pack() | |
320 | + if editable(logic): | |
321 | + ControlPanel(Tkinter.Toplevel(self.canvas),logic=logic).pack() | |
281 | 322 | |
323 | +class ControlPanel(Tkinter.Frame,object): | |
324 | + def __init__(self,*args,**kw): | |
325 | + if kw.has_key('logic'): | |
326 | + logic = kw['logic'] | |
327 | + del kw['logic'] | |
328 | + Tkinter.Frame.__init__(self,*args,**kw) | |
329 | + members = editable(logic) | |
330 | + keys = members.keys() | |
331 | + keys.sort() | |
332 | + i = 0 | |
333 | + for k in keys: | |
334 | + v = members[k] | |
335 | + value = getattr(logic,k) | |
336 | + if isinstance(value,data.SpecificData): | |
337 | + #TODO: より汎用性のある方式へ変更しなければいけない | |
338 | + o = SmartPanel(self,logic,k); o.grid(column=0,row=i,columnspan=2) | |
339 | + p = ControlPanel(o,logic=value); p.pack() | |
340 | + laf.link(laf.port(value,'data'),laf.port(o,'receiver')) | |
341 | + else: | |
342 | + l = Tkinter.Label(self,text=k); l.grid(column=0,row=i) | |
343 | + e = Entry(self); e.grid(column=1,row=i) | |
344 | + setattr(e,'value',value) | |
345 | + laf.link(laf.port(logic,k),laf.port(e,'value')) | |
346 | + i += 1 | |
347 | + | |
348 | +#TODO: 結構トリッキーなのでドキュメントにしておくこと | |
349 | +#FIXME: 縁ありフレームにする | |
350 | +class SmartPanel(Tkinter.LabelFrame,object): | |
351 | + # データクラスの変更を補足してデータ更新を促すクラス | |
352 | + @event | |
353 | + def receiver(self): | |
354 | + setattr(self.logic,self.portid,getattr(self.logic,self.portid)) | |
355 | + def __init__(self,master=None,logic=None,portid=None,*args,**kw): | |
356 | + Tkinter.LabelFrame.__init__(self,master,text=portid,*args,**kw) | |
357 | + self._logic = weakref.ref(logic) | |
358 | + self.portid = portid | |
359 | + @property | |
360 | + def logic(self): | |
361 | + return self._logic() | |
362 | +##FIXME: 適切な名前へ! | |
363 | +#class SmartControlPanel(Tkinter.Frame,object): | |
364 | +# # データクラスの変更を捕捉する機能を有するパネル | |
365 | +# @event | |
366 | +# def receiver(self): | |
367 | +# self.updated() | |
368 | +# def updated(self): | |
369 | +# setattr(self.logic,self.name,getattr(self.logic,self.name)) | |
370 | +# def __init__(self,*args,**kw): | |
371 | +# if kw.has_key('logic'): | |
372 | +# logic = kw['logic'] | |
373 | +# del kw['logic'] | |
374 | +# Tkinter.Frame.__init__(self,*args,**kw) | |
375 | +# self.logic = weakref.ref(logic) | |
376 | +# self.name | |
377 | +# members = editable(logic) | |
378 | +# i = 0 | |
379 | +# for k,v in members.iteritems(): | |
380 | +# value = getattr(logic,k) | |
381 | +# if isinstance(value,data.SpecificData): | |
382 | +# #TODO: より汎用性のある方式へ変更しなければいけない | |
383 | +# p = SmartControlPanel(self,logic=value); p.grid(column=0,row=i,columnspan=2) | |
384 | +# else: | |
385 | +# l = Tkinter.Label(self,text=k); l.grid(column=0,row=i) | |
386 | +# e = Entry(self); e.grid(column=1,row=i) | |
387 | +# setattr(e,'value',value) | |
388 | +# laf.link(laf.port(logic,k),laf.port(e,'value')) | |
389 | +# i += 1 | |
390 | + | |
391 | + | |
392 | +class Entry(Tkinter.Entry,object): | |
393 | + def __init__(self,master=None,format='%s',cnf={},**kw): | |
394 | + Tkinter.Entry.__init__(self,master,cnf,**kw) | |
395 | + self.format = format | |
396 | + self._buffer = None | |
397 | + self._updated = False | |
398 | + self._callback_id = self.bind('<Return>',self._backward) # RETURNキーが押されたら値を確定する | |
399 | + self._idle_loop() | |
400 | + def _idle_loop(self): | |
401 | + if self._updated: | |
402 | + self._forward(self._buffer) | |
403 | + self._updated = False | |
404 | + self.after(50,self._idle_loop) | |
405 | + @event | |
406 | + def value(self): | |
407 | + self._buffer = self.value | |
408 | + self._updated = True | |
409 | + def _forward(self,value): | |
410 | + self.delete(0,len(self.get())) | |
411 | + self.insert(0,self.format % value) | |
412 | + def _backward(self,*args): | |
413 | + container = laf.port(self,'value').container | |
414 | + try: | |
415 | + self.value = type(container.value)(self.get()) | |
416 | + except ValueError: | |
417 | + self._buffer = container.value | |
418 | + self._updated = True | |
419 | + | |
420 | +#FIXME: | |
282 | 421 | class StayEventDispatcher: |
283 | 422 | def __init__(self,obj): |
284 | 423 | self.isstayed = False |
@@ -0,0 +1,33 @@ | ||
1 | +# coding: utf-8 | |
2 | + | |
3 | +from ingredient import event | |
4 | + | |
5 | +class SpecificData(object): pass | |
6 | + | |
7 | +class Point(SpecificData): | |
8 | + #FIXME: 相互同期メカニズム | |
9 | + def __init__(self,x=0,y=0,z=0): | |
10 | + self.x = x | |
11 | + self.y = y | |
12 | + self.z = z | |
13 | + @event | |
14 | + def data(self): | |
15 | + self._block = None | |
16 | + self.x = self.data[0] | |
17 | + self.y = self.data[1] | |
18 | + self.z = self.data[2] | |
19 | + del self._block | |
20 | + @event | |
21 | + def x(self): self.update() | |
22 | + @event | |
23 | + def y(self): self.update() | |
24 | + @event | |
25 | + def z(self): self.update() | |
26 | + def update(self): | |
27 | + try: | |
28 | + self._block | |
29 | + except: | |
30 | + self.data = (self.x,self.y,self.z) | |
31 | + | |
32 | +#class PositionWidget: | |
33 | + |
@@ -8,7 +8,7 @@ | ||
8 | 8 | |
9 | 9 | actualports = weakref.WeakKeyDictionary() |
10 | 10 | |
11 | -def getports(owner): | |
11 | +def getproxports(owner): | |
12 | 12 | '''オーナが保持するすべてのポートリストを取得する''' |
13 | 13 | if inspect.isclass(owner): |
14 | 14 | klass = owner |
@@ -22,6 +22,8 @@ | ||
22 | 22 | if not k in result: result[k] = v |
23 | 23 | return result |
24 | 24 | |
25 | + | |
26 | + | |
25 | 27 | class Singleton(type): |
26 | 28 | # http://code.activestate.com/recipes/412551/ |
27 | 29 | def __init__(self,*args): |
@@ -196,7 +198,7 @@ | ||
196 | 198 | self.sources |
197 | 199 | except AttributeError: |
198 | 200 | self.sources = self.proxy.sources |
199 | - ports = getports(self.owner) | |
201 | + ports = getproxports(self.owner) | |
200 | 202 | # check update requirements |
201 | 203 | for name in self.sources: |
202 | 204 | if self not in ports[name].actualport(self.owner).container.hootprint: |
@@ -231,7 +233,7 @@ | ||
231 | 233 | '''オーナーインスタンスからの参照名を取得する''' |
232 | 234 | if self._name == None: # オーナーインスタンスが生成されてから最初に参照されたときには名称探索をする |
233 | 235 | # 呼び出しのコンテキストから、オーナーインスタンスにオブジェクトが存在することが保証されているので(はずなので)チェック省略 |
234 | - for name, v in getports(owner).iteritems(): # オーナークラスのメンバ全体について | |
236 | + for name, v in getproxports(owner).iteritems(): # オーナークラスのメンバ全体について | |
235 | 237 | if v == self: |
236 | 238 | self._name = name # 自身と一致するインスタンスの名称をセットする |
237 | 239 | # まだオーナーに実体が生成されていなければすべての実体を生成する |
@@ -240,7 +242,7 @@ | ||
240 | 242 | return self._name |
241 | 243 | def newactualports(self,owner): |
242 | 244 | '''オーナーに属するすべてのターミナルの属性を生成する''' |
243 | - ports = getports(owner) | |
245 | + ports = getproxports(owner) | |
244 | 246 | for name, port in ports.iteritems(): |
245 | 247 | owner.__dict__[name] = port.ActualPort(owner,port,port.initvalue) |
246 | 248 |
@@ -266,7 +268,7 @@ | ||
266 | 268 | class PortGen(type): |
267 | 269 | def __new__(cls,cls_name,bases,attrs): |
268 | 270 | klass = type.__new__(cls,cls_name,bases,attrs) |
269 | - ports = getports(klass) | |
271 | + ports = getproxports(klass) | |
270 | 272 | for k,v in ports.iteritems(): |
271 | 273 | if not isinstance(v,Rule): |
272 | 274 | continue |
@@ -361,7 +363,7 @@ | ||
361 | 363 | |
362 | 364 | def port(owner,name): |
363 | 365 | '''オーナが保持するポートの実体を取得する''' |
364 | - ports = getports(owner) | |
366 | + ports = getproxports(owner) | |
365 | 367 | if name in ports: |
366 | 368 | return ports[name].actualport(owner) |
367 | 369 | else: |
@@ -2,6 +2,7 @@ | ||
2 | 2 | |
3 | 3 | import vtk |
4 | 4 | from pylafiii.ingredient import Logic,Port,rule,event |
5 | +from pylafiii.data import Point | |
5 | 6 | from base import vtkLogic |
6 | 7 | |
7 | 8 | class SphereSource(vtkLogic): |
@@ -9,3 +10,13 @@ | ||
9 | 10 | output = Port() |
10 | 11 | def initialize(self): |
11 | 12 | self.output = self.vtkobj.GetOutput() |
13 | + #FIXME: Pointが更新されたことを知る仕組みが必要! | |
14 | + self.center = Point(*self.vtkobj.GetCenter()) | |
15 | + self.radius = self.vtkobj.GetRadius() | |
16 | + @event | |
17 | + def center(self): | |
18 | + self.vtkobj.SetCenter(*self.center.data) | |
19 | + @event | |
20 | + def radius(self): | |
21 | + self.vtkobj.SetRadius(self.radius) | |
22 | + | |
\ No newline at end of file |