67
72
elif key == 'scroll-image':
68
73
self.scroll_image = value
69
74
self._scroll_image.set_source(self.scroll_image)
70
self._scroll_image._update_layout()
75
self._scroll_image._update_layout()
72
77
def _update_layout(self):
73
78
""" Updates layout """
75
80
super(ScrollArea, self)._update_layout()
82
# Subscribe to key-press events
84
_stage = self.get_stage()
85
_stage.connect('key-press-event', self.do_key_press_event)
87
# Update background layout
77
88
self._background_image._update_layout()
78
self._scroll_image._update_layout()
90
# Update scroll area layout, account for previous scroll position
91
x_factor = y_factor = 0.0
92
if self._scroll_image.get_xu() != 0:
94
self._scroll_image.get_widthu() / self._scroll_image.get_xu()
95
if self._scroll_image.get_yu() != 0:
97
self._scroll_image.get_heightu() / self._scroll_image.get_yu()
99
self._scroll_image._update_layout()
102
self._scroll_image.set_xu(
103
self._scroll_image.get_widthu() / x_factor
106
self._scroll_image.set_yu(
107
self._scroll_image.get_heightu() / y_factor
110
# Update layout for packed items
80
111
for item in self._items:
81
112
item._update_layout()
113
# FIXME: Raising item to top shouldn't be necessary
83
#print self._scroll_image.get_height(), item.get_height()
116
# Clip the scroll area
85
117
self.set_clipu(0, 0, self.get_widthu(), self.get_heightu())
86
#self._scroll_image.set_clipu(0, 0, self._scroll_image.get_widthu(), self._scroll_image.get_heightu())
88
def _scroll_up(self, factor=0.2, px=None):
93
self._scroll_image.get_y() - px
96
self._scroll_image.get_y() - self._scroll_image.get_height() * factor
98
if not self._timeline or not self._timeline.is_playing():
99
if target_y < self.get_height() - self._scroll_image.get_height():
100
self._timeline = clutter.Timeline(fps=60, duration=200)
101
alpha = clutter.Alpha(self._timeline, clutter.sine_inc_func)
102
self._behaviour = clutter.BehaviourPath(alpha)
103
self._behaviour.append_knots(
104
(0, self._scroll_image.get_y()),
106
(0, -(self._scroll_image.get_height() - self.get_height()))
109
self._timeline = clutter.Timeline(fps=60, duration=100)
110
alpha = clutter.Alpha(self._timeline, clutter.smoothstep_inc_func)
111
self._behaviour = clutter.BehaviourPath(alpha)
112
self._behaviour.append_knots(
113
(0, self._scroll_image.get_y()),
116
self._behaviour.apply(self._scroll_image)
117
self._timeline.start()
120
def _scroll_down(self, factor=0.2, px=None):
125
self._scroll_image.get_y() + px
128
self._scroll_image.get_y() + self._scroll_image.get_height() * factor
129
if not self._timeline or not self._timeline.is_playing():
131
self._timeline = clutter.Timeline(fps=60, duration=200)
132
alpha = clutter.Alpha(self._timeline, clutter.sine_inc_func)
133
self._behaviour = clutter.BehaviourPath(alpha)
134
self._behaviour.append_knots(
140
self._timeline = clutter.Timeline(fps=60, duration=100)
141
alpha = clutter.Alpha(self._timeline, clutter.smoothstep_inc_func)
142
self._behaviour = clutter.BehaviourPath(alpha)
143
self._behaviour.append_knots(
144
(0, self._scroll_image.get_y()),
147
self._behaviour.apply(self._scroll_image)
148
self._timeline.start()
150
def _scroll_to(self, factor):
151
""" Scrolls to a given position
153
factor -- (float) position as a factor of the scroll area height
119
def pack(self, widget):
120
""" Packs a widget into the scroll area """
122
self._scroll_image.add(widget)
123
self._items.append(widget)
125
self._update_layout()
127
def unpack(self, widget):
128
""" Unpacks a widget from the scroll widget """
130
self._scroll_image.remove(widget)
131
self._items.remove(widget)
133
self._update_layout()
135
def scroll(self, horiz_factor=0.0, vert_factor=0.0):
136
""" Scroll by a horizontal and/or vertical factor
138
horiz_factor -- (float) Horizontal factor to scroll
139
vert_factor -- (float) Vertical factor to scroll
156
if self._previous_scroll_image_y:
157
_scroll_image_y = self._previous_scroll_image_y
159
_scroll_image_y = self._scroll_image.get_y()
160
target_y = _scroll_image_y + self._scroll_image.get_height() * factor
142
self._horiz_factor += horiz_factor
143
self._vert_factor += vert_factor
145
# Determine target x and y values for the scroll image
146
horiz_factor_as_units = \
147
self._horiz_factor * self._scroll_image.get_widthu()
148
target_x = self._scroll_image.get_xu() + horiz_factor_as_units
150
vert_factor_as_units = \
151
self._vert_factor * self._scroll_image.get_heightu()
152
target_y = self._scroll_image.get_yu() + vert_factor_as_units
154
# Normalize targets out of bounds
157
elif target_x < self.get_widthu() - self._scroll_image.get_widthu():
158
target_x = -(self._scroll_image.get_widthu() - self.get_widthu())
161
elif target_y < self.get_heightu() - self._scroll_image.get_heightu():
162
target_y = -(self._scroll_image.get_heightu() - self.get_heightu())
164
# Neutralize horizontal and/or vertical factors when the scroll area
166
right_bound = self.get_widthu() - self._scroll_image.get_widthu()
167
if self._scroll_image.get_xu() == 0 or \
168
self._scroll_image.get_xu() == right_bound:
169
self._horiz_factor = 0.0
170
right_bound = self.get_heightu() - self._scroll_image.get_heightu()
171
if self._scroll_image.get_yu() == 0 or \
172
self._scroll_image.get_yu() == right_bound:
173
self._vert_factor = 0.0
175
# Kick-start scroll animations
162
176
if self._timeline:
163
177
self._timeline.rewind()
165
179
self._timeline = clutter.Timeline(fps=60, duration=200)
166
alpha = clutter.Alpha(self._timeline, clutter.sine_inc_func)
180
alpha = clutter.Alpha(self._timeline, clutter.sine_inc_func)
167
181
self._behaviour = clutter.BehaviourPath(alpha)
168
182
self._behaviour.append_knots(
169
(0, self._scroll_image.get_y()),
183
(self._scroll_image.get_x(), self._scroll_image.get_y()),
184
(clutter.units_to_device(target_x), clutter.units_to_device(target_y))
172
self._previous_scroll_image_y = target_y
173
186
self._behaviour.apply(self._scroll_image)
174
187
self._timeline.start()
176
#self._scroll_image.set_y(int(target_y))
178
def pack(self, widget):
179
""" Packs a widget into the scroll area """
181
self._scroll_image.add(widget)
182
self._items.append(widget)
184
if isinstance(widget, Scrollable):
185
widget.connect('view-changed', self.on_scrollable_view_changed)
187
self._update_layout()
189
def unpack(self, widget):
190
""" Unpacks a widget in the scroll widget """
192
self._scroll_image.remove(widget)
193
self._items.remove(widget)
195
self._update_layout()
197
def on_scroll_event(self, widget, event):
189
def do_scroll_event(self, widget, event):
190
""" Handles scroll event """
200
192
if event.direction == clutter.SCROLL_UP:
193
self.scroll(vert_factor=0.1)
202
194
elif event.direction == clutter.SCROLL_DOWN:
195
self.scroll(vert_factor=-0.1)
204
196
elif event.direction == clutter.SCROLL_LEFT:
206
198
elif event.direction == clutter.SCROLL_RIGHT:
209
def on_scrollable_view_changed(self, widget, event, offset):
210
""" Scrollable view changed """
212
# Get event widget allocation box (clutter units)
213
xu, yu, widthu, heightu = event
215
# Update xu, yu for coords relative to self
217
while parent != self:
218
yu += parent.get_yu()
219
parent = parent.get_parent()
221
scroll_delta = float(heightu) / float(self._scroll_image.get_heightu())
223
self._scroll_to(scroll_delta)
224
elif yu + heightu > self.get_heightu():
225
self._scroll_to(-scroll_delta)
201
def do_key_press_event(self, widget, event):
202
""" Handles key press event """
204
if event.keyval == clutter.keysyms.Up:
205
self.scroll(vert_factor=0.1)
206
elif event.keyval == clutter.keysyms.Down:
207
self.scroll(vert_factor=-0.1)
208
elif event.keyval == clutter.keysyms.Left:
210
elif event.keyval == clutter.keysyms.Right: