65
64
- a function to be called whenver the edge is visited during an update
66
65
cycle. this function will not be called if the condition function
69
def __init__(self, *widgets):
68
@ivar arcs: A map from widget to a list of edges originating in the widget.
69
@ivar update_funcs: A map from widget to a (callable, args) tuple.
71
74
self.update_funcs = {}
72
75
self.ignore_new_signals = False
73
for widget in widgets:
74
self.add_vertex(*widget)
76
def add_vertex(self, widget, update_func=None, signal=None, *args):
77
def addVertex(self, widget, signal=None, update_func=None,
79
"""Add a widget to the list of vertexes.
81
@param widget: The vertex to be added.
82
@type widget: gtk.Widget
83
@param signal: A signal of the widget to be monitored.
85
@param update_func: A callable object called when the vertex is visited.
86
@type update_func: function
87
@param update_func_args: The arguments for calling update_func.
88
@type update_func_args: tuple
78
widget.connect(signal, self._widget_value_changed)
79
self.update_funcs[widget] = (update_func, args)
91
widget.connect(signal, self._widgetValueChanged)
92
self.update_funcs[widget] = (update_func, update_func_args)
80
93
self.arcs[widget] = []
82
def add_edge(self, a, b, predicate = None,
84
self.arcs[a].append((b, predicate, edge_func))
86
def add_bi_edge(self, a, b, predicate = None,
88
self.add_edge(a, b, predicate, edge_func)
89
self.add_edge(b, a, predicate, edge_func)
91
def _widget_value_changed(self, widget, *unused):
95
def addEdge(self, widget_a, widget_b, predicate=None, edge_func=None):
96
"""Add a directional edge from widget_a to widget_b.
98
@param widget_a: The source vertex.
99
@type widget_a: gtk.Widget
100
@param widget_b: The target vertex.
101
@type widget_b: gtk.Widget
102
@param predicate: A callable object returning whether the edge may be
104
@type predicate: function
105
@param edge_func: A callable object called when the edge is traversed.
106
@type edge_func: function
108
self.arcs[widget_a].append((widget_b, predicate, edge_func))
110
def addBiEdge(self, widget_a, widget_b, predicate=None, edge_func=None):
111
"""Add a bidirectional edge between the specified vertexes.
115
self.addEdge(widget_a, widget_b, predicate, edge_func)
116
self.addEdge(widget_b, widget_a, predicate, edge_func)
118
def _widgetValueChanged(self, widget, *unused):
119
"""Handle an event generated by the specified widget."""
92
120
if self.ignore_new_signals:
95
123
self.ignore_new_signals = True
96
self._updateValues(widget)
97
self.ignore_new_signals = False
125
self._updateValues(widget)
127
self.ignore_new_signals = False
99
129
def _updateValues(self, widget):
100
queue = [(widget, v) for v in self.arcs[widget]]
130
"""Traverse the graph starting from the specified widget."""
131
# Initialize the list of (source_widget, arc) to be traversed.
132
queue = [(widget, arc) for arc in self.arcs[widget]]
101
133
visited = set([widget])
103
parent, (cur, predicate, edge_func) = queue.pop(0)
135
source_widget, arc = queue.pop(0)
136
target_widget, predicate, edge_func = arc
105
138
# ignore nodes we've seen
139
if target_widget in visited:
109
142
# check whether conditions permit this edge to be followed
110
if predicate and (not predicate()):
143
if predicate and not predicate():
113
# if so call the edge function
118
update_func, args = self.update_funcs[cur]
150
# visit the target node
151
update_func, update_func_args = self.update_funcs[target_widget]
120
update_func(parent, cur, *args)
153
update_func(source_widget, target_widget, *update_func_args)
154
visited.add(target_widget)
123
156
# enqueue children
124
queue.extend(((cur, v) for v in self.arcs[cur]))
157
for arc in self.arcs[target_widget]:
158
queue.append((target_widget, arc))