~glitter-team/glitter/trunk

« back to all changes in this revision

Viewing changes to glitter/scroll_area.py

  • Committer: Jan Jokela
  • Date: 2009-06-06 16:55:58 UTC
  • mfrom: (29.1.4 scroll_area)
  • Revision ID: jan@jan-laptop-20090606165558-1rpvn6tiywgvggup
(Merge) From scroll area widget

Show diffs side-by-side

added added

removed removed

Lines of Context:
22
22
    
23
23
    """
24
24
    
25
 
    def __init__(self, area_height=1.0):
 
25
    def __init__(self, area_width=1.0, area_height=1.0):
26
26
        """ Initialize scroll area """
27
27
        
28
28
        super(ScrollArea, self).__init__()
29
29
        
 
30
        # Scroll area dimensions
 
31
        self.area_width = area_width
30
32
        self.area_height = area_height
31
33
        
32
 
        self._previous_scroll_image_y = None
33
 
        
34
34
        self._items = []
 
35
        
 
36
        # Set actor reactive and subscribe to scroll event
35
37
        self.set_reactive(True)
36
 
        self.connect('scroll-event', self.on_scroll_event)
 
38
        self.connect('scroll-event', self.do_scroll_event) 
37
39
        
38
40
        self._init_elements()
39
41
        self._init_animations()
40
 
        
41
42
        self._update_style(self.style)
42
 
 
 
43
        
43
44
    def _init_elements(self):
44
45
        """ Initializes graphical elements """
45
46
        
48
49
        
49
50
        self._scroll_image = Image()
50
51
        self.add(self._scroll_image)
 
52
        self._scroll_image.natural_width = self.area_width
51
53
        self._scroll_image.natural_height = self.area_height
52
54
    
53
55
    def _init_animations(self):
 
56
        """ Initializes animations """
54
57
    
55
58
        self._timeline = None
56
 
        
 
59
        self._horiz_factor=0.0
 
60
        self._vert_factor=0.0
 
61
 
57
62
    def _update_style(self, props=None):
58
63
        """ Updates style """
59
64
        
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()   
71
76
 
72
77
    def _update_layout(self):
73
78
        """ Updates layout """
74
79
        
75
80
        super(ScrollArea, self)._update_layout()
76
 
        
 
81
 
 
82
        # Subscribe to key-press events
 
83
        if self.get_stage():
 
84
            _stage = self.get_stage()
 
85
            _stage.connect('key-press-event', self.do_key_press_event)
 
86
            
 
87
        # Update background layout
77
88
        self._background_image._update_layout()
78
 
        self._scroll_image._update_layout()      
79
 
        
 
89
        
 
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:
 
93
            x_factor = \
 
94
              self._scroll_image.get_widthu() / self._scroll_image.get_xu()
 
95
        if self._scroll_image.get_yu() != 0:
 
96
            y_factor = \
 
97
              self._scroll_image.get_heightu() / self._scroll_image.get_yu()
 
98
        
 
99
        self._scroll_image._update_layout()  
 
100
        
 
101
        if x_factor != 0:
 
102
            self._scroll_image.set_xu(
 
103
              self._scroll_image.get_widthu() / x_factor
 
104
            )
 
105
        if y_factor != 0:
 
106
            self._scroll_image.set_yu(
 
107
              self._scroll_image.get_heightu() / y_factor
 
108
            )
 
109
        
 
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  
82
114
            item.raise_top()
83
 
            #print self._scroll_image.get_height(), item.get_height()
84
 
        
 
115
 
 
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())
87
 
        
88
 
    def _scroll_up(self, factor=0.2, px=None):
89
 
        """ Scrolls up """
90
 
        
91
 
        if px:
92
 
            target_y = \
93
 
              self._scroll_image.get_y() - px
94
 
        else:
95
 
            target_y = \
96
 
              self._scroll_image.get_y() - self._scroll_image.get_height() * factor
97
 
              
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()), 
105
 
                  (0, target_y),
106
 
                  (0, -(self._scroll_image.get_height() - self.get_height()))
107
 
                )
108
 
            else:
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()), 
114
 
                  (0, target_y)
115
 
                )
116
 
            self._behaviour.apply(self._scroll_image)
117
 
            self._timeline.start()
118
 
            
119
 
 
120
 
    def _scroll_down(self, factor=0.2, px=None):
121
 
        """ Scrolls up """
122
 
        
123
 
        if px:
124
 
            target_y = \
125
 
              self._scroll_image.get_y() + px
126
 
        else:
127
 
            target_y = \
128
 
              self._scroll_image.get_y() + self._scroll_image.get_height() * factor
129
 
        if not self._timeline or not self._timeline.is_playing():
130
 
            if target_y > 0:
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(
135
 
                  (0, 0), 
136
 
                  (0, target_y),
137
 
                  (0, 0)
138
 
                )
139
 
            else:
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()), 
145
 
                  (0, target_y)
146
 
                )
147
 
            self._behaviour.apply(self._scroll_image)
148
 
            self._timeline.start()
149
 
            
150
 
    def _scroll_to(self, factor):
151
 
        """ Scrolls to a given position
152
 
        
153
 
        factor -- (float) position as a factor of the scroll area height
 
118
 
 
119
    def pack(self, widget):
 
120
        """ Packs a widget into the scroll area """
 
121
        
 
122
        self._scroll_image.add(widget)  
 
123
        self._items.append(widget)
 
124
            
 
125
        self._update_layout()
 
126
 
 
127
    def unpack(self, widget):
 
128
        """ Unpacks a widget from the scroll widget """
 
129
        
 
130
        self._scroll_image.remove(widget)  
 
131
        self._items.remove(widget)
 
132
        
 
133
        self._update_layout()
 
134
 
 
135
    def scroll(self, horiz_factor=0.0, vert_factor=0.0):
 
136
        """ Scroll by a horizontal and/or vertical factor 
 
137
        
 
138
        horiz_factor -- (float) Horizontal factor to scroll
 
139
        vert_factor -- (float) Vertical factor to scroll
154
140
        """
155
141
        
156
 
        if self._previous_scroll_image_y:
157
 
            _scroll_image_y = self._previous_scroll_image_y
158
 
        else:
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
 
144
        
 
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
161
149
 
 
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
 
153
        
 
154
        # Normalize targets out of bounds
 
155
        if target_x > 0:
 
156
            target_x = 0
 
157
        elif target_x < self.get_widthu() - self._scroll_image.get_widthu():
 
158
            target_x = -(self._scroll_image.get_widthu() - self.get_widthu())
 
159
        if target_y > 0: 
 
160
            target_y = 0
 
161
        elif target_y < self.get_heightu() - self._scroll_image.get_heightu():
 
162
            target_y = -(self._scroll_image.get_heightu() - self.get_heightu())     
 
163
        
 
164
        # Neutralize horizontal and/or vertical factors when the scroll area
 
165
        # hits bounds
 
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            
 
174
        
 
175
        # Kick-start scroll animations
162
176
        if self._timeline:
163
177
            self._timeline.rewind()
164
178
        else:
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()), 
170
 
          (0, target_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))
171
185
        )
172
 
        self._previous_scroll_image_y = target_y
173
186
        self._behaviour.apply(self._scroll_image)
174
187
        self._timeline.start()
175
 
                      
176
 
        #self._scroll_image.set_y(int(target_y))
177
 
 
178
 
    def pack(self, widget):
179
 
        """ Packs a widget into the scroll area """
180
 
        
181
 
        self._scroll_image.add(widget)  
182
 
        self._items.append(widget)
183
 
        
184
 
        if isinstance(widget, Scrollable):
185
 
            widget.connect('view-changed', self.on_scrollable_view_changed)
186
 
            
187
 
        self._update_layout()
188
 
 
189
 
    def unpack(self, widget):
190
 
        """ Unpacks a widget in the scroll widget """
191
 
        
192
 
        self._scroll_image.remove(widget)  
193
 
        self._items.remove(widget)
194
 
        
195
 
        self._update_layout()
196
 
        
197
 
    def on_scroll_event(self, widget, event):
198
 
        """ Scroll event """
 
188
 
 
189
    def do_scroll_event(self, widget, event):
 
190
        """ Handles scroll event """
199
191
 
200
192
        if event.direction == clutter.SCROLL_UP:
201
 
            self._scroll_up()
 
193
            self.scroll(vert_factor=0.1)
202
194
        elif event.direction == clutter.SCROLL_DOWN:
203
 
            self._scroll_down()
 
195
            self.scroll(vert_factor=-0.1)
204
196
        elif event.direction == clutter.SCROLL_LEFT:
205
 
            pass
 
197
            self.scroll(0.1)
206
198
        elif event.direction == clutter.SCROLL_RIGHT:
207
 
            pass
208
 
             
209
 
    def on_scrollable_view_changed(self, widget, event, offset):
210
 
        """ Scrollable view changed """
211
 
        
212
 
        # Get event widget allocation box (clutter units)
213
 
        xu, yu, widthu, heightu = event        
214
 
        
215
 
        # Update xu, yu for coords relative to self
216
 
        parent = widget
217
 
        while parent != self:
218
 
            yu += parent.get_yu()
219
 
            parent = parent.get_parent()
220
 
        
221
 
        scroll_delta = float(heightu) / float(self._scroll_image.get_heightu())
222
 
        if yu < 0:
223
 
            self._scroll_to(scroll_delta)
224
 
        elif yu + heightu > self.get_heightu():
225
 
            self._scroll_to(-scroll_delta)
 
199
            self.scroll(-0.1)
 
200
            
 
201
    def do_key_press_event(self, widget, event):
 
202
        """ Handles key press event """
226
203
 
227
 
            
 
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:
 
209
            self.scroll(0.1)
 
210
        elif event.keyval == clutter.keysyms.Right:
 
211
            self.scroll(-0.1)
 
212