4234176113c39f3cd4a1493c7628f655a4467b7c
[remotepc] / pcremote-client-n8x0 / debian / pcremote-client / usr / share / pcremote-client / kineticlist.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3
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.
10
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.
15
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/>.
18
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
23 # Version      :1.0
24 # Module       :main
25 # Class        :This class are an adaptation of barbieri's demo 03 of edje
26 #              :python-bindings
27 # ============================================================================
28
29 import evas
30 import edje
31 import ecore
32 import time
33
34 class KineticList(evas.ClippedSmartObject):
35     (
36         SCROLL_PAGE_FORWARD,
37         SCROLL_PAGE_BACKWARD,
38         SCROLL_STEP_FORWARD,
39         SCROLL_STEP_BACKWARD,
40         SCROLL_PIXELS_DOWN,
41         SCROLL_PIXELS_UP
42     ) = range(6)
43
44
45     def __init__(self, ecanvas, file, item_width=-1, item_height=-1, father=None):
46         '''
47         if item_width or item_height is left out the width (resp. height)
48         of the List element is used.
49         '''
50         self.father = father
51         evas.ClippedSmartObject.__init__(self, ecanvas)
52         self.elements = []
53         self.objects = []
54         self.w = 32
55         self.h = 32
56
57         self.realized = False
58
59         self.top_pos = 0
60         self.last_top_pos = 0
61         self.last_start_row = -1
62
63         self.canvas = ecanvas
64         self.edje_file = file
65
66         self.row_width = item_width
67         self.row_height = item_height
68
69         self.__manage_objects()
70
71         self.mouse_down = False
72         self.last_y_pos = 0
73         self.start_pos = 0
74         self.mouse_moved = False
75         self.continue_scrolling = False
76         self.is_scrolling = False
77         self.do_freeze = False
78
79     def freeze(self):
80         self.do_freeze = True
81
82     def thaw(self):
83         self.do_freeze = False
84         if self.realized:
85             self.__update_variables_after_new_elements()
86             self.__update_screen()
87
88     def scroll(self, scroll_type, amount=1):
89         self.continue_scrolling = False
90
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
103         else:
104             return
105
106         self.__update_screen()
107
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", "")
112
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"))
118
119     def __on_mouse_move(self, edje_obj, emission, source, data=None):
120         if self.mouse_down:
121             x_pos, y_pos = self.canvas.pointer_canvas_xy
122             diff = int(self.last_y_pos - y_pos)
123
124             if diff == 0:
125                 return
126
127             self.mouse_moved = True
128
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()
134
135             self.last_diff = diff
136             self.top_pos += diff
137
138             self.last_y_pos = y_pos
139             self.__update_screen()
140             self.last_update_time = time.time()
141
142     #TODO: portela mod
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")
148
149     #TODO: portela mod
150
151     def show_list(self):
152         for obj in self.objects:
153             obj.signal_emit("program,start,fade,in","label")
154
155     def __on_mouse_down(self, edje_obj, emission, source, data=None):
156         if not self.is_scrolling:
157             self.mouse_moved = False
158
159         self.continue_scrolling = False
160         self.mouse_down = True
161
162         x_pos, y_pos = self.canvas.pointer_canvas_xy
163
164         self.last_diff = -1
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()
169
170     def __on_mouse_up(self, edje_obj, emission, source, data=None):
171         if self.mouse_down:
172             self.mouse_down = False
173
174             x_pos, end_pos = self.canvas.pointer_canvas_xy
175
176             if not self.mouse_moved and not self.is_scrolling:
177                 #self.__on_mouse_clicked(edje_obj, emission, source)
178                 return
179
180             self.mouse_moved = False
181             self.is_scrolling = False
182
183             # do not scroll automatically if the finger was paused
184             if time.time() - self.last_update_time > 0.1:
185                 return
186
187             end_time = time.time()
188
189             pos_diff =  end_pos - self.start_pos
190             time_diff = end_time - self.start_time
191
192             self.pixel_per_sec = pos_diff / time_diff
193             self.continue_scrolling = True
194             self.__do_scroll()
195
196     def __do_scroll(self):
197         self.is_scrolling = True
198
199         if self.continue_scrolling == False:
200             return
201
202         diff = int(self.pixel_per_sec / 10)
203
204         if abs(self.pixel_per_sec) - diff <= self.row_height:
205             offset = self.top_pos % self.row_height
206
207             if offset >= self.row_height / 2:
208                 self.sign = 1
209                 offset = self.row_height - offset
210             else:
211                 self.sign = -1
212
213             self.pixels_left = offset
214             self.__do_magnetic_scroll()
215
216             return
217
218         if diff != 0:
219             self.top_pos -= diff
220             self.pixel_per_sec -= self.pixel_per_sec / 10
221             self.__update_screen()
222
223         ecore.timer_add(0.02, self.__do_scroll)
224
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
229             return
230
231         self.pixel_per_sec -= (self.pixel_per_sec / 10)
232
233         pixels_to_substract = int(abs(self.pixel_per_sec / 10))
234         if abs(pixels_to_substract) < 1:
235             pixels_to_substract = 1
236
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
240         else:
241             self.top_pos += self.sign * self.pixels_left
242             self.pixels_left = 0
243
244         self.__update_screen()
245         ecore.timer_add(0.1, self.__do_magnetic_scroll)
246
247     def row_add(self, label):
248         self.elements.append(label)
249
250         if not self.do_freeze:
251             self.__update_variables_after_new_elements()
252             self.__update_screen()
253
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)
258
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");
263
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,*", "*",
269                                         self.__on_mouse_up)
270                 #TODO: portela mod
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)
276                 obj.clip = self
277                 self.objects.append(obj)
278
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
283                 #del self.objects[i]
284
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
290
291         # Invalidate variable in order to repaint all rows
292         # Some might not have been painted before (Didn't
293         # fit on the screen
294         self.last_start_row = -1
295
296         self.__update_variables_after_new_elements()
297
298     def __update_variables_after_new_elements(self):
299         if not self.realized:
300             return
301
302         self.min_pos = 0
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)
309
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
316
317         SCROLL_DOWN = self.top_pos > self.last_top_pos
318         SCROLL_UP = self.top_pos < self.last_top_pos
319
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
325             return
326
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
332             return
333
334         # Overflow scrolling down
335         if SCROLL_DOWN and end_row > self.row_amount:
336             offset = end_row - self.row_amount
337             end_row -= offset
338             start_row -= offset
339             row_offset -= offset - 1
340             self.top_pos = self.max_pos
341             pixel_offset = 0
342
343         # Overflow scrolling up
344         if SCROLL_UP and start_row < 0:
345             self.top_pos = self.min_pos
346             end_row -= start_row
347             start_row = 0
348             row_offset = 0
349             pixel_offset = 0
350
351         self.last_top_pos = self.top_pos
352
353         if start_row != self.last_start_row:
354             for i in range(0, len(self.objects)):
355                 self.objects[i].hide()
356
357         for i in range(start_row, end_row):
358             row_iter = i - start_row
359
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
363
364                 try:
365                     label = self.elements[data_iter]
366                 except Exception, e:
367                     break;
368
369                 offset = (self.w %
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) - \
373                     5 + pixel_offset
374
375                 self.objects[obj_iter].move(x, y)
376
377                 if start_row != self.last_start_row:
378                     self.objects[obj_iter].part_text_set("label", label)
379                     self.objects[obj_iter].show()
380
381         self.last_start_row = start_row
382
383     def resize(self, w, h):
384         if self.row_width == -1 or self.row_width == self.w:
385             self.row_width = w
386
387         if self.row_height == -1 or self.row_height == self.h:
388             self.row_height = h
389
390         self.w = w
391         self.h = h
392
393         self.__manage_objects()
394
395         for obj in self.objects:
396             obj.size = (self.row_width, self.row_height)
397
398         self.realized = True
399         self.__update_variables_after_resize()
400         self.__update_screen()