2 # -*- coding: utf-8 -*-
4 # ****************************************************************************
5 # Copyright (c) 2008 INdT/Fucapi.
6 # This program is free software: you can redistribute it and/or modify
7 # it under the terms of the GNU Lesser General Public License as published by
8 # the Free Software Foundation, either version 3 of the License, or
9 # (at your option) any later version.
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU Lesser General Public License for more details.
16 # You should have received a copy of the GNU Lesser General Public License
17 # along with this program. If not, see <http://www.gnu.org/licenses/>.
19 # ============================================================================
20 # Project Name :PC Remote
21 # Author :Gustavo Sverzut Barbieri ; André Luiz do Canto Portela
22 # Email :barbieri@gmail.com ; andre_portela_@hotmail.com
25 # Class :This class are an adaptation of barbieri's demo 03 of edje
27 # ============================================================================
34 class KineticList(evas.ClippedSmartObject):
45 def __init__(self, ecanvas, file, item_width=-1, item_height=-1, father=None):
47 if item_width or item_height is left out the width (resp. height)
48 of the List element is used.
51 evas.ClippedSmartObject.__init__(self, ecanvas)
61 self.last_start_row = -1
66 self.row_width = item_width
67 self.row_height = item_height
69 self.__manage_objects()
71 self.mouse_down = False
74 self.mouse_moved = False
75 self.continue_scrolling = False
76 self.is_scrolling = False
77 self.do_freeze = False
83 self.do_freeze = False
85 self.__update_variables_after_new_elements()
86 self.__update_screen()
88 def scroll(self, scroll_type, amount=1):
89 self.continue_scrolling = False
91 if scroll_type == self.SCROLL_PAGE_FORWARD:
92 self.top_pos += amount * self.row_height * self.max_visible_rows
93 elif scroll_type == self.SCROLL_PAGE_BACKWARD:
94 self.top_pos -= amount * self.row_height * self.max_visible_rows
95 elif scroll_type == self.SCROLL_STEP_FORWARD:
96 self.top_pos += amount * self.row_height
97 elif scroll_type == self.SCROLL_STEP_BACKWARD:
98 self.top_pos -= amount * self.row_height
99 elif scroll_type == self.SCROLL_PIXELS_DOWN:
100 self.top_pos += amount
101 elif scroll_type == self.SCROLL_PIXELS_UP:
102 self.top_pos -= amount
106 self.__update_screen()
108 def __on_mouse_clicked(self, edje_obj, emission, source, data=None):
109 #for obj in self.objects:
110 # if obj != edje_obj:
111 # obj.signal_emit("fadeout", "")
113 #edje_obj.signal_emit("open", "")
114 #TODO:portela - it works! :D
115 edje_obj.signal_emit("program,start","label")
116 #we are setting up the choice's text on the main edje object
117 self.parent_get().part_text_set("choice",edje_obj.part_text_get("label"))
119 def __on_mouse_move(self, edje_obj, emission, source, data=None):
121 x_pos, y_pos = self.canvas.pointer_canvas_xy
122 diff = int(self.last_y_pos - y_pos)
127 self.mouse_moved = True
129 # Reset the data if the direction of the mouse move is changed
130 if self.last_diff != -1 and (diff < 0) != (self.last_diff < 0):
131 self.last_y_pos = y_pos
132 self.start_pos = y_pos
133 self.start_time = time.time()
135 self.last_diff = diff
138 self.last_y_pos = y_pos
139 self.__update_screen()
140 self.last_update_time = time.time()
143 def __on_blink_ended(self, edje_obj, emission, source, data=None):
144 for obj in self.objects:
145 obj.signal_emit("program,start,fade,out","label")
146 #we are sending a signal for the application connect the target
147 self.parent_get().signal_emit("connect_to","choice")
152 for obj in self.objects:
153 obj.signal_emit("program,start,fade,in","label")
155 def __on_mouse_down(self, edje_obj, emission, source, data=None):
156 if not self.is_scrolling:
157 self.mouse_moved = False
159 self.continue_scrolling = False
160 self.mouse_down = True
162 x_pos, y_pos = self.canvas.pointer_canvas_xy
165 self.last_y_pos = y_pos
166 self.start_pos = y_pos
167 self.start_time = time.time()
168 self.last_update_time = time.time()
170 def __on_mouse_up(self, edje_obj, emission, source, data=None):
172 self.mouse_down = False
174 x_pos, end_pos = self.canvas.pointer_canvas_xy
176 if not self.mouse_moved and not self.is_scrolling:
177 #self.__on_mouse_clicked(edje_obj, emission, source)
180 self.mouse_moved = False
181 self.is_scrolling = False
183 # do not scroll automatically if the finger was paused
184 if time.time() - self.last_update_time > 0.1:
187 end_time = time.time()
189 pos_diff = end_pos - self.start_pos
190 time_diff = end_time - self.start_time
192 self.pixel_per_sec = pos_diff / time_diff
193 self.continue_scrolling = True
196 def __do_scroll(self):
197 self.is_scrolling = True
199 if self.continue_scrolling == False:
202 diff = int(self.pixel_per_sec / 10)
204 if abs(self.pixel_per_sec) - diff <= self.row_height:
205 offset = self.top_pos % self.row_height
207 if offset >= self.row_height / 2:
209 offset = self.row_height - offset
213 self.pixels_left = offset
214 self.__do_magnetic_scroll()
220 self.pixel_per_sec -= self.pixel_per_sec / 10
221 self.__update_screen()
223 ecore.timer_add(0.02, self.__do_scroll)
225 def __do_magnetic_scroll(self):
226 if self.pixels_left <= 0 or abs(self.pixel_per_sec) < 1:
227 self.mouse_moved = False
228 self.is_scrolling = False
231 self.pixel_per_sec -= (self.pixel_per_sec / 10)
233 pixels_to_substract = int(abs(self.pixel_per_sec / 10))
234 if abs(pixels_to_substract) < 1:
235 pixels_to_substract = 1
237 if self.pixels_left - pixels_to_substract > 0:
238 self.pixels_left -= pixels_to_substract
239 self.top_pos += self.sign * pixels_to_substract
241 self.top_pos += self.sign * self.pixels_left
244 self.__update_screen()
245 ecore.timer_add(0.1, self.__do_magnetic_scroll)
247 def row_add(self, label):
248 self.elements.append(label)
250 if not self.do_freeze:
251 self.__update_variables_after_new_elements()
252 self.__update_screen()
254 def __manage_objects(self):
255 remain = (self.h % self.row_height) > 1
256 needed_objects = ((self.h / self.row_height) + 1 + remain) * (self.w / self.row_width)
257 current_objects = len(self.objects)
259 if current_objects < needed_objects:
260 for i in range(current_objects, needed_objects):
261 obj = edje.Edje(self.canvas);
262 obj.file_set(self.edje_file, "list_item");
264 obj.signal_callback_add("mouse,move", "*",
265 self.__on_mouse_move)
266 obj.signal_callback_add("mouse,down,*", "*",
267 self.__on_mouse_down)
268 obj.signal_callback_add("mouse,up,*", "*",
271 obj.signal_callback_add("animation_blink_ended", "label",
272 self.__on_blink_ended)
273 obj.signal_callback_add("mouse,clicked,*", "label",
274 self.__on_mouse_clicked)
275 obj.size = (self.row_width, self.row_height)
277 self.objects.append(obj)
279 elif needed_objects < current_objects:
280 for i in range(needed_objects, current_objects):
281 pass # Make this work, it throws exception that makes
282 # things stop working properly
285 def __update_variables_after_resize(self):
286 self.max_visible_rows = (self.h / self.row_height) + 1
287 self.max_horiz_elements = (self.w / self.row_width)
288 self.max_visible_elements = self.max_visible_rows * \
289 self.max_horiz_elements
291 # Invalidate variable in order to repaint all rows
292 # Some might not have been painted before (Didn't
294 self.last_start_row = -1
296 self.__update_variables_after_new_elements()
298 def __update_variables_after_new_elements(self):
299 if not self.realized:
303 remainer1 = (len(self.elements) % self.max_horiz_elements) > 0
304 remainer2 = (self.h % self.row_height) > 0
305 self.row_amount = (len(self.elements) / self.max_horiz_elements) + \
306 remainer1 + remainer2
307 self.max_pos = self.row_height * \
308 (self.row_amount - self.max_visible_rows + 1)
310 def __update_screen(self):
311 remainer = (self.h % self.row_height) > 0
312 row_offset = (self.top_pos / self.row_height)
313 pixel_offset = - (self.top_pos % self.row_height)
314 start_row = row_offset
315 end_row = self.max_visible_rows + row_offset + remainer
317 SCROLL_DOWN = self.top_pos > self.last_top_pos
318 SCROLL_UP = self.top_pos < self.last_top_pos
320 # Let's not move over the last element
321 if SCROLL_DOWN and self.last_top_pos >= self.max_pos:
322 self.top_pos = self.max_pos
323 self.last_top_pos = self.top_pos
324 self.continue_scrolling = False
327 # Let's not move over the first element
328 if SCROLL_UP and self.last_top_pos <= self.min_pos:
329 self.top_pos = self.min_pos
330 self.last_top_pos = self.top_pos
331 self.continue_scrolling = False
334 # Overflow scrolling down
335 if SCROLL_DOWN and end_row > self.row_amount:
336 offset = end_row - self.row_amount
339 row_offset -= offset - 1
340 self.top_pos = self.max_pos
343 # Overflow scrolling up
344 if SCROLL_UP and start_row < 0:
345 self.top_pos = self.min_pos
351 self.last_top_pos = self.top_pos
353 if start_row != self.last_start_row:
354 for i in range(0, len(self.objects)):
355 self.objects[i].hide()
357 for i in range(start_row, end_row):
358 row_iter = i - start_row
360 for k in range(self.max_horiz_elements):
361 obj_iter = row_iter * self.max_horiz_elements + k
362 data_iter = i * self.max_horiz_elements + k
365 label = self.elements[data_iter]
370 (self.row_width * self.max_horiz_elements)) / 2
371 x = self.row_width * k + self.top_left[0] + offset
372 y = self.top_left[1] + self.row_height * (i - row_offset) - \
375 self.objects[obj_iter].move(x, y)
377 if start_row != self.last_start_row:
378 self.objects[obj_iter].part_text_set("label", label)
379 self.objects[obj_iter].show()
381 self.last_start_row = start_row
383 def resize(self, w, h):
384 if self.row_width == -1 or self.row_width == self.w:
387 if self.row_height == -1 or self.row_height == self.h:
393 self.__manage_objects()
395 for obj in self.objects:
396 obj.size = (self.row_width, self.row_height)
399 self.__update_variables_after_resize()
400 self.__update_screen()