55from sage_widget_adapters .graphs .graph_grid_view_adapter import GraphGridViewAdapter
66from sage_combinat_widgets .grid_view_widget import GridViewWidget , ButtonCell , BlankButton , styled_button_cell
77from ipywidgets import Layout
8- from traitlets import dlink , HasTraits , Bool
8+ from traitlets import dlink , HasTraits , Bool , observe , All
99from contextlib import contextmanager
10+ from sage_combinat_widgets .grid_view_editor import extract_coordinates
1011
1112smallblyt = Layout (width = '12px' ,height = '12px' , margin = '0' , padding = '0' )
1213
@@ -26,7 +27,7 @@ def set_cell(self, obj, pos, val, dirty={}):
2627 if dirty : # if i'm a neighbor, then flip and return a new obj ; else return an error
2728 # Consider the relevant matching(s)
2829 for p in dirty :
29- if not dirty [p ]: # check this position is pressed
30+ if not dirty [p ]: # check this position was pressed
3031 continue
3132 d2 = obj .domino_for_position (p )
3233 if d2 == d1 or not d2 in d1 .neighbors ():
@@ -98,8 +99,8 @@ def _busy_updating(self):
9899 self .updating = False
99100
100101 def _update (self , change ):
101- if self .updating :
102- return
102+ # if self.updating or self.target[0].donottrack :
103+ # return
103104 with self ._busy_updating ():
104105 if self .logic == 'and' :
105106 if self .intermediate_value == False : # aucun bouton pressé avant
@@ -155,23 +156,25 @@ def __init__(self, parent, b1, b2):
155156 self .link = None
156157 self .direction = None
157158 self .orientation = None
158- self .compute (None )
159+ self .compute ()
160+ self .donottrack = False
159161
160162 def __repr__ (self ):
161163 if self .value :
162164 return repr (self .first ) + ' -> ' + repr (self .second ) + " PRESSED"
163165 return repr (self .first ) + ' -> ' + repr (self .second )
164166
165- def compute (self , css_classes = None ):
167+ def compute (self , css_classes = [ 'b0' , 'b1' , 'b2' , 'b3' , 'b4' ] ):
166168 """Compute buttons relative positions.
167169 Create double directional link from both buttons"""
168170 self .geometry .compute ()
171+ #print(self.geometry.__dict__)
169172 if css_classes :
170173 for cl in css_classes :
171174 self .first .remove_class (cl )
172175 self .second .remove_class (cl )
173- self .first .add_class (css_classes [self .geometry .index_for_display - 1 ])
174- self .second .add_class (css_classes [self .geometry .index_for_display - 1 ])
176+ self .first .add_class (css_classes [self .geometry .index_for_display ])
177+ self .second .add_class (css_classes [self .geometry .index_for_display ])
175178 if self .geometry .orientation == 1 :
176179 self .key = self .first .position
177180 else :
@@ -199,19 +202,19 @@ def is_pressed(self):
199202 """Is the domino pressed?"""
200203 return self .value
201204
202- def set_value (self , value ):
203- """Set domino value
204- As we have a directional link,
205- the domino value will also be set.
206- """
207- self .link .unlink ()
208- self .first .value = value
209- self .second .value = value
210- self .link = ddlink (((self .first , 'value' ), (self .second , 'value' )), (self , 'value' ), logic = 'and' , set_at_init = False ) # Fresh ddlink
205+ # def set_value(self, value):
206+ # """Set domino value
207+ # As we have a directional link,
208+ # the domino value will also be set.
209+ # """
210+ # self.link.unlink()
211+ # self.first.value = value
212+ # self.second.value = value
213+ # self.link = ddlink(((self.first, 'value'), (self.second, 'value')), (self, 'value'), logic='and', set_at_init=False) # Fresh ddlink
211214
212215 def reset (self ):
213216 """Full domino reset"""
214- self .set_value (False )
217+ # self.set_value(False)
215218 self .link .unlink ()
216219
217220 def flip (self , other ):
@@ -237,11 +240,12 @@ def cell_widget_class_index(pos):
237240class FlippingDominosWidget (GridViewWidget ):
238241 """A widget with dominos"""
239242
240- def __init__ (self , g ):
243+ def __init__ (self , g , css_classes = [ 'b0' , 'b1' , 'b2' , 'b3' , 'b4' ] ):
241244 r"""
242245 Init a flipping dominos widget
243246 with flipping aztec diamond graph `g`
244247 """
248+ self .css_classes = css_classes
245249 super (FlippingDominosWidget , self ).__init__ (g , adapter = FlippingDominosAdapter (),
246250 cell_layout = smallblyt ,
247251 cell_widget_classes = [styled_button_cell (),
@@ -252,19 +256,11 @@ def __init__(self, g):
252256 ],
253257 cell_widget_class_index = make_cell_widget_class_index (g ),
254258 blank_widget_class = BlankButton )
255- self .css_classes = ['b1' , 'b2' , 'b3' , 'b4' ]
256-
257259 def draw (self ):
258260 self .dominos = {}
259261 super (FlippingDominosWidget , self ).draw ()
260262 self .apply_matching (self .value .matching )
261263
262- def update (self ):
263- self .apply_matching (self .value .matching )
264- for k ,d in self .dominos .items ():
265- d .compute (self .css_classes )
266- d .set_value (False ) # unpress buttons
267-
268264 def match (self , b1 , b2 ):
269265 """Match buttons b1 and b2, that is: create a domino"""
270266 try :
@@ -286,7 +282,64 @@ def apply_matching(self, matching):
286282 self .match (self .children [d .first [0 ]].children [d .first [1 ]],
287283 self .children [d .second [0 ]].children [d .second [1 ]])
288284
289- def set_value (self , value ):
290- """Need to call self.update() manually, as the change is not obvious to the observer!"""
285+ def update (self ):
286+ self .apply_matching (self .value .matching )
287+ for k ,d in self .dominos .items ():
288+ d .compute (self .css_classes )
289+ #d.set_value(False) # unpress buttons
290+
291+ def domino_for_position (self , pos ):
292+ geometry = self .value .domino_for_position (pos )
293+ for t in (geometry .first , geometry .second ):
294+ if t in self .dominos :
295+ print ("domino for position" , t , ":" , self .dominos [t ].geometry , self .dominos [t ].value )
296+ return self .dominos [t ]
297+
298+ def not_tracking (self , value ):
299+ self .donottrack = value
300+ for d in self .dominos .values ():
301+ d .donottrack = value
302+
303+ @observe (All )
304+ def set_cell (self , change ):
305+ if self .donottrack :
306+ return
307+ if change .name .startswith ('cell_' ):
308+ print ("set_cell()" , change .name , change .old , change .new )
309+ else :
310+ print ("set_cell()" , change .name )
311+ # Try to reset everything right now to avoid unwanted propagations
312+ domino = self .domino_for_position (extract_coordinates (change .name ))
313+ # First, we want to make the pressed domino visible to the user
314+ self .not_tracking (True )
315+ domino .first .value = True
316+ domino .second .value = True
317+ # Any pressed neighbor?
318+ other = None
319+ if self .dirty :
320+ for pos in self .dirty :
321+ other = self .domino_for_position (pos )
322+ if other and not other .geometry in domino .geometry .neighbors ():
323+ other = None
324+ continue # we don't have to reset everything, I guess(hope)
325+ if not other :
326+ self .dirty [domino .geometry .first ] = True
327+ self .dirty [domino .geometry .second ] = True
328+ self .not_tracking (False )
329+ return
330+ if domino .link :
331+ domino .link .unlink ()
332+ if other .link :
333+ other .link .unlink ()
334+ self .not_tracking (False )
335+ super (FlippingDominosWidget , self ).set_cell (change )
336+ self .not_tracking (True )
337+ # And now, we want to reset everything before the flip
338+ domino .first .value = False
339+ domino .second .value = False
340+ other .first .value = False
341+ other .second .value = False
342+ # Now, recreate the 2 dominos and compute style
291343 self .reset_dirty ()
292344 self .update ()
345+ self .not_tracking (False )
0 commit comments