Home | Trees | Indices | Help |
|
---|
|
1 #! /usr/bin/env python 2 # -*- coding: utf-8 -*- 3 4 # Copyright (C) 2011 ~ 2012 Deepin, Inc. 5 # 2011 ~ 2012 Xia Bin 6 # 7 # Author: Xia Bin <xiabin@linuxdeepin.com> 8 # Maintainer: Xia Bin <xiabin@linuxdeepin.com> 9 # 10 # This program is free software: you can redistribute it and/or modify 11 # it under the terms of the GNU General Public License as published by 12 # the Free Software Foundation, either version 3 of the License, or 13 # any later version. 14 # 15 # This program is distributed in the hope that it will be useful, 16 # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 # GNU General Public License for more details. 19 # 20 # You should have received a copy of the GNU General Public License 21 # along with this program. If not, see <http://www.gnu.org/licenses/>. 22 23 from gtk import gdk 24 from theme import ui_theme 25 from utils import remove_signal_id, color_hex_to_cairo 26 import gobject 27 import gtk 28 29 __all__ = ['ScrolledWindow'] 30 31 # the p_range is the virtual width/height, it's value is smaller than 32 # the allocation.width/height when scrollbar's width/height smaller than 33 # the minmum scrollbar length. 34 # p_range = allocation.width/height - (min_bar_len - *bar_len*) 35 # the *bar_len* = (adj.page_size / adj.upper) * allocation.width/height 36 # by this processing, 0~(adj.upper-adj.page_size) will be mapped to 0~p_range.38 ''' 39 Compute the scrollbar position by the adjustment value. 40 ''' 41 if upper == 0: return 0 42 return p_range * float(value) / upper4345 ''' 46 Compute the adjustment value by the scrollbar position. 47 ''' 48 if p_range == 0 : return 0 49 return pos * upper / p_range5052 ''' 53 The scrolled window with deepin's custom scrollbar. 54 55 @undocumented: do_enter_notify_event 56 @undocumented: _test_calc 57 @undocumented: do_remove 58 @undocumented: do_unmap 59 @undocumented: do_map 60 @undocumented: set_policy 61 @undocumented: set_shadow_type 62 @undocumented: do_realize 63 @undocumented: do_size_request 64 @undocumented: do_unrealize 65 @undocumented: update_scrollbar 66 @undocumented: do_size_allocate 67 @undocumented: do_add 68 @undocumented: hadjustment_changed 69 @undocumented: vadjustment_changed 70 @undocumented: calc_hbar_allocation 71 @undocumented: calc_hbar_length 72 @undocumented: calc_vbar_allocation 73 @undocumented: calc_vbar_length 74 @undocumented: do_motion_notify_event 75 @undocumented: do_leave_notify_event 76 @undocumented: do_scroll_event 77 @undocumented: make_bar_bigger 78 @undocumented: make_bar_smaller 79 @undocumented: do_button_release_event 80 @undocumented: draw_vbar 81 @undocumented: draw_hbar 82 @undocumented: do_expose_event 83 ''' 84121 122 self._horizaontal = Record() 123 self._vertical = Record() 124 125 self.set_can_focus(True) 126 self.vallocation = gdk.Rectangle() 127 self.hallocation = gdk.Rectangle() 128 self.set_vadjustment(gtk.Adjustment()) 129 self.set_hadjustment(gtk.Adjustment()) 130 self.set_has_window(False) 13188 ''' 89 Init scrolled window. 90 91 @param right_space: the space between right border and the vertical scroolbar. 92 @param top_bottom_space: the space between top border and the vertical scroolbar. 93 ''' 94 gtk.Bin.__init__(self) 95 self.bar_min_length = 50 #scrollbar smallest height 96 self.bar_small_width = 7 97 self.bar_width = 14 #normal scrollbar width 98 self.bar_background = ui_theme.get_color("scrolledbar") 99 self.right_space = right_space 100 self.top_bottom_space = top_bottom_space 101 102 self.h_value_change_id = None 103 self.h_change_id = None 104 self.v_value_change_id = None 105 self.v_change_id = None 106 107 class Record(): 108 def __init__(self): 109 self.bar_len = 0 #scrollbar length 110 self.last_pos = 0 #last mouse motion pointer's position (x or y) 111 112 #last mouse motion timestamp, if user moved the window 113 #then the last_pos is likely become invalid so we need "last_time" 114 #to deal with this situation. 115 self.last_time = 0 116 self.virtual_len = 0 #the virtual window height or width length 117 self.bar_pos = 0 #the scrollbar topcorner/leftcorner position 118 self.is_inside = False # is pointer in the scrollbar region? 119 self.in_motion = False # is user is draging scrollbar? 120 self.policy = gtk.POLICY_AUTOMATIC133 if e.window == self.vwindow: 134 self.draw_vbar() 135 return True 136 elif e.window == self.hwindow: 137 self.draw_hbar() 138 return True 139 else: 140 return False141143 #img = cairo.ImageSurface(cairo.FORMAT_ARGB32, 100, 100) 144 cr = self.vwindow.cairo_create() 145 cr.set_source_rgb(*color_hex_to_cairo(self.bar_background.get_color())) 146 cr.rectangle(0, 0, self.vallocation.width, self.vallocation.height) 147 cr.fill()148150 cr = self.hwindow.cairo_create() 151 cr.set_source_rgb(*color_hex_to_cairo(self.bar_background.get_color())) 152 cr.rectangle(0, 0, self.hallocation.width, self.hallocation.height) 153 cr.fill()154 168170 if orientation == gtk.ORIENTATION_HORIZONTAL: 171 region = gdk.region_rectangle(gdk.Rectangle(0, 0, int(self._horizaontal.bar_len), self.bar_small_width)) 172 173 if self.hallocation.x == 0: 174 self.hwindow.shape_combine_region(region, self.top_bottom_space, self.bar_width - self.bar_small_width -self.right_space) 175 else: 176 self.hwindow.shape_combine_region(region, -self.top_bottom_space, self.bar_width - self.bar_small_width -self.right_space) 177 elif orientation == gtk.ORIENTATION_VERTICAL: 178 region = gdk.region_rectangle(gdk.Rectangle(0, 0, self.bar_small_width, int(self._vertical.bar_len))) 179 180 if self.vallocation.y == 0: 181 self.vwindow.shape_combine_region(region, self.bar_width-self.bar_small_width - self.right_space, self.top_bottom_space) 182 else: 183 self.vwindow.shape_combine_region(region, self.bar_width-self.bar_small_width - self.right_space, -self.top_bottom_space) 184 else: 185 raise "make_bar_smaller's orientation must be gtk.ORIENTATION_VERTICAL or gtk.ORIENTATION_HORIZONTAL" 186 187 return False188190 if orientation == gtk.ORIENTATION_HORIZONTAL: 191 region = gdk.region_rectangle(gdk.Rectangle(0, 0, int(self._horizaontal.bar_len), self.bar_width)) 192 193 if self.hallocation.x == 0: 194 self.hwindow.shape_combine_region(region, self.top_bottom_space, -self.right_space) 195 else: 196 self.hwindow.shape_combine_region(region, -self.top_bottom_space, -self.right_space) 197 elif orientation == gtk.ORIENTATION_VERTICAL: 198 region = gdk.region_rectangle(gdk.Rectangle(0, 0, self.bar_width, int(self._vertical.bar_len))) 199 200 if self.vallocation.y == 0: 201 self.vwindow.shape_combine_region(region, -self.right_space, self.top_bottom_space) 202 else: 203 self.vwindow.shape_combine_region(region, -self.right_space, -self.top_bottom_space) 204 else: 205 raise "make_bar_bigger's orientation must be gtk.ORIENTATION_VERTICAL or gtk.ORIENTATION_HORIZONTAL"206208 value = self.vadjustment.value 209 step = self.vadjustment.step_increment 210 page_size = self.vadjustment.page_size 211 upper = self.vadjustment.upper 212 213 #TODO: need handle other scrolltype? I can only capture below two scrolltype at the moment 214 if e.direction == gdk.SCROLL_DOWN: 215 self.vadjustment.set_value(min(upper-page_size-1, value+step)) 216 return True 217 elif e.direction == gdk.SCROLL_UP: 218 self.vadjustment.set_value(max(0, value-step)) 219 return True 220 else: 221 return False222224 if e.window == self.hwindow : 225 self._horizaontal.is_inside = False 226 #if e.y < 0 and not self._horizaontal.in_motion: 227 if not self._horizaontal.in_motion: 228 self.make_bar_smaller(gtk.ORIENTATION_HORIZONTAL) 229 return True 230 elif e.window == self.vwindow: 231 self._vertical.is_inside = False 232 if not self._vertical.in_motion: 233 #if e.x < 0 and not self._vertical.in_motion: 234 self.make_bar_smaller(gtk.ORIENTATION_VERTICAL) 235 return True 236 else: 237 return False238240 if e.window == self.hwindow: 241 self.make_bar_bigger(gtk.ORIENTATION_HORIZONTAL) 242 self._horizaontal.is_inside = True 243 return True 244 elif e.window == self.vwindow: 245 self.make_bar_bigger(gtk.ORIENTATION_VERTICAL) 246 self._vertical.is_inside = True 247 return True 248 else: 249 return False250252 if not (e.window == self.hwindow or e.window == self.vwindow): return False 253 254 if e.window == self.hwindow and (e.state & gtk.gdk.BUTTON1_MASK) == gtk.gdk.BUTTON1_MASK: 255 self.make_bar_bigger(gtk.ORIENTATION_HORIZONTAL) 256 if self._horizaontal.last_time == 0: 257 self._horizaontal.last_time = e.time 258 elif e.time - self._horizaontal.last_time > 1000: 259 self._horizaontal.last_time = 0 260 self._horizaontal.last_pos = 0 261 262 if self._horizaontal.last_pos == 0 or self._horizaontal.last_time == 0: 263 self._horizaontal.last_pos = e.x_root 264 return True 265 deltaX = e.x_root - self._horizaontal.last_pos 266 upper = self.hadjustment.upper 267 268 #the pos maybe beyond the effective range, but we will immediately corrected 269 #it's value. 270 #the "invariant" is the "value" always in the effective range. 271 value = pos2value(self._horizaontal.bar_pos+deltaX, self._horizaontal.virtual_len, upper) 272 value = max(0, min(value, self.hadjustment.upper-self.hadjustment.page_size)) 273 self.hadjustment.set_value(value) 274 275 self._horizaontal.last_pos = e.x_root 276 self._horizaontal.last_time = e.time 277 self._horizaontal.in_motion = True 278 return True 279 280 elif e.window == self.vwindow and (e.state & gtk.gdk.BUTTON1_MASK) == gtk.gdk.BUTTON1_MASK: 281 self.make_bar_bigger(gtk.ORIENTATION_VERTICAL) 282 if self._vertical.last_time == 0: 283 self._vertical.last_time = e.time 284 elif e.time - self._vertical.last_time > 1000: 285 self._vertical.last_time = 0 286 self._vertical.last_pos = 0 287 288 if self._vertical.last_pos == 0 or self._vertical.last_time == 0: 289 self._vertical.last_pos = e.y_root 290 return True 291 292 upper = self.vadjustment.upper 293 deltaY = e.y_root - self._vertical.last_pos 294 295 value = pos2value(self._vertical.bar_pos+deltaY, self._vertical.virtual_len, upper) 296 value = max(0, min(value, self.vadjustment.upper-self.vadjustment.page_size)) 297 self.vadjustment.set_value(value) 298 299 self._vertical.last_pos = e.y_root 300 self._vertical.last_time = e.time 301 self._vertical.in_motion = True 302 return True303305 self._vertical.virtual_len = self.allocation.height 306 if self.vadjustment.upper <= 1 or self._vertical.policy == gtk.POLICY_NEVER: 307 self._vertical.bar_len = 0 308 return 309 310 ratio = float(self.vadjustment.page_size) / (self.vadjustment.upper-self.vadjustment.lower) 311 312 # assert(self.vadjustment.upper >= self.vadjustment.page_size) 313 if ratio == 1: 314 self._vertical.bar_len = 0 315 else: 316 bar_len = self._vertical.virtual_len * ratio 317 if bar_len < self.bar_min_length: 318 self._vertical.virtual_len -= (self.bar_min_length - bar_len) 319 self._vertical.bar_len = max(bar_len, self.bar_min_length)320322 self.vallocation = gdk.Rectangle( 323 self.allocation.width - self.bar_width, int(self._vertical.bar_pos), 324 self.bar_width, int(self._vertical.bar_len))325327 self._horizaontal.virtual_len = self.allocation.width 328 if self.hadjustment.upper <= 1 or self._horizaontal.policy == gtk.POLICY_NEVER: 329 self._horizaontal.bar_len = 0 330 return 331 332 333 ratio = float(self.hadjustment.page_size) / (self.hadjustment.upper-self.hadjustment.lower) 334 # assert(self.hadjustment.lower == 0) 335 336 # assert(self.hadjustment.upper >= self.hadjustment.page_size) 337 if ratio == 1: 338 self._horizaontal.bar_len = 0 339 else: 340 bar_len = self._horizaontal.virtual_len * ratio 341 if bar_len < self.bar_min_length: 342 self._horizaontal.virtual_len -= (self.bar_min_length - bar_len) 343 self._horizaontal.bar_len = max(bar_len, self.bar_min_length)344346 #assert 0 <= int(self.hpos) <= self.allocation.width - self.hbar_length,\ 347 # "self.hpos %f self.allocation.width %f self.hbar_lengh %f" % (self.hpos, self.allocation.width, 348 # self.hbar_length) 349 self.hallocation = gdk.Rectangle( 350 int(self._horizaontal.bar_pos), self.allocation.height - self.bar_width, 351 int(self._horizaontal.bar_len), self.bar_width)352354 if self.get_realized(): 355 # assert(self.vadjustment.value <= self.vadjustment.upper-self.vadjustment.page_size) 356 upper = self.vadjustment.upper 357 self._vertical.bar_pos = value2pos(adj.value, self._vertical.virtual_len, upper) 358 self.calc_vbar_allocation() 359 self.vwindow.move_resize(*self.vallocation) 360 self.queue_draw()361363 if self.get_realized(): 364 # assert(self.hadjustment.value <= self.hadjustment.upper-self.hadjustment.page_size) 365 upper = self.hadjustment.upper 366 self._horizaontal.bar_pos = value2pos(adj.value, self._horizaontal.virtual_len, upper) 367 self.calc_hbar_allocation() 368 self.hwindow.move_resize(*self.hallocation) 369 self.queue_draw()370 371373 ''' 374 Used to add children without native scrolling capabilities. 375 376 If a child has native scrolling, use ScrolledWindow.add() insetad 377 378 of this function. 379 380 @param child: the child without native scrolling. 381 ''' 382 vp = gtk.Viewport() 383 vp.set_shadow_type(gtk.SHADOW_NONE) 384 vp.add(child) 385 vp.show() 386 self.add(vp)387389 ''' 390 Add the child to this ScrolledWindow.The child should have 391 392 native scrolling capabilities. 393 394 @param child: the child with native scrolling. 395 ''' 396 self.add_with_viewport(child)397 #raise Exception, "use add_with_viewport instead add_child" 398 399401 self.child = None 402 gtk.Bin.do_add(self, child) 403 404 child.set_scroll_adjustments(self.hadjustment, self.vadjustment)405407 if self.child: 408 #print "sel size_request", (requsition.width, requsition.height) 409 self.child.do_size_request(self.child, requsition)410 #print "child size request:", (requsition.width, requsition.height) 411413 #print "do_size_allocate", allocation 414 self.allocation = allocation 415 416 if self.get_realized(): 417 self.binwindow.move_resize(*self.allocation) 418 419 #must before calc_xxx_length, because we need child to cumpute the adjustment value 420 if self.child: 421 (allocation.x, allocation.y) = (0, 0) 422 self.child.do_size_allocate(self.child, allocation) 423 424 self.update_scrollbar() 425 426 if self.get_realized(): 427 self.make_bar_smaller(gtk.ORIENTATION_VERTICAL) 428 self.make_bar_smaller(gtk.ORIENTATION_HORIZONTAL)429431 if self.get_realized(): 432 self.calc_vbar_length() 433 self.calc_hbar_length() 434 self.vadjustment.emit('value-changed') 435 self.hadjustment.emit('value-changed')436438 #print "do_unrealize" 439 440 self.binwindow.set_user_data(None) 441 self.binwindow.destroy() 442 self.binwindow = None 443 self.vwindow.set_user_data(None) 444 self.vwindow.destroy() 445 self.vwindow = None 446 self.hwindow.set_user_data(None) 447 self.hwindow.destroy() 448 self.hwindow = None 449 450 # assert(self.get_realized() == True) 451 gtk.Bin.do_unrealize(self)452 # assert(self.get_realized() == False) 453 454456 #print "self.get_parent_window():", self.get_parent_window() 457 #print "do_realize", self.get_realized() 458 459 # assert(self.get_realized() == False) 460 gtk.Bin.do_realize(self) 461 # assert(self.get_realized() == True) 462 463 self.binwindow = gtk.gdk.Window(self.get_parent_window(), 464 x=self.allocation.x, 465 y=self.allocation.y, 466 width=self.allocation.width, 467 height=self.allocation.height, 468 window_type=gtk.gdk.WINDOW_CHILD, 469 wclass=gtk.gdk.INPUT_OUTPUT, 470 event_mask=(self.get_events()| gdk.EXPOSURE_MASK | gdk.VISIBILITY_NOTIFY_MASK | gdk.ALL_EVENTS_MASK ), 471 visual=self.get_visual(), 472 colormap=self.get_colormap(), 473 ) 474 self.binwindow.set_user_data(self) 475 476 self.vwindow = gtk.gdk.Window(self.binwindow, 477 x=self.vallocation.x, 478 y=self.vallocation.y, 479 width=self.vallocation.width, 480 height=self.vallocation.height, 481 window_type=gtk.gdk.WINDOW_CHILD, 482 wclass=gtk.gdk.INPUT_OUTPUT, 483 visual=self.get_visual(), 484 colormap=self.get_colormap(), 485 event_mask=(self.get_events() 486 | gdk.EXPOSURE_MASK 487 | gdk.ENTER_NOTIFY_MASK | gdk.LEAVE_NOTIFY_MASK | gdk.BUTTON_RELEASE_MASK 488 | gdk.BUTTON_MOTION_MASK 489 | gdk.POINTER_MOTION_HINT_MASK | gdk.BUTTON_PRESS_MASK 490 ) 491 ) 492 self.vwindow.set_user_data(self) 493 #sefl.vwindow.get_ 494 #self.vwindow.set_background(self.bar_background) 495 496 self.hwindow = gtk.gdk.Window(self.binwindow, 497 x=self.hallocation.x, 498 y=self.hallocation.y, 499 width=self.hallocation.width, 500 height=self.hallocation.height, 501 window_type=gtk.gdk.WINDOW_CHILD, 502 wclass=gtk.gdk.INPUT_OUTPUT, 503 colormap=self.get_colormap(), 504 visual=self.get_visual(), 505 event_mask=(self.get_events() 506 | gdk.EXPOSURE_MASK 507 | gdk.ENTER_NOTIFY_MASK | gdk.LEAVE_NOTIFY_MASK | gdk.BUTTON_RELEASE_MASK 508 | gdk.BUTTON_MOTION_MASK 509 | gdk.POINTER_MOTION_HINT_MASK | gdk.BUTTON_PRESS_MASK 510 ) 511 ) 512 self.hwindow.set_user_data(self) 513 #self.hwindow.set_background(self.bar_background) 514 515 if self.child: 516 self.child.set_parent_window(self.binwindow) 517 518 self.queue_resize()519 520 524 525527 ''' 528 Set the policy of ScrolledWindow's scrollbar 529 530 @param h: the horizontal scrollbar policy 531 @param v: the vertical scrollbar policy 532 ''' 533 self._horizaontal.policy = h 534 self._vertical.policy = v 535 return536538 gtk.Bin.do_map(self) #must before self.xwindow.show(), didn't know the reason. 539 self.binwindow.show() 540 self.hwindow.show() 541 self.vwindow.show() 542 if self.child and not self.child.get_mapped() and self.child.get_visible(): 543 self.child.do_map(self.child)544546 #self.set_mapped(False) 547 self.binwindow.hide() 548 self.hwindow.hide() 549 self.vwindow.hide() 550 gtk.Bin.do_unmap(self)551553 #TODO: need this? 554 #child.set_scroll_adjustments(None, None) 555 gtk.Bin.do_remove(self, child)556558 ''' 559 Returns the vertical scrollbar's adjustment, 560 used to connect the vectical scrollbar to the child widget's 561 vertical scroll functionality. 562 ''' 563 return self.vadjustment564566 ''' 567 Returns the horizontal scrollbar's adjustment, 568 used to connect the horizontal scrollbar to the child 569 widget's horizontal scroll functionality. 570 ''' 571 return self.hadjustment572574 ''' 575 Sets the gtk.Adjustment for the horizontal scrollbar. 576 577 @param adj: horizontal scroll adjustment 578 ''' 579 remove_signal_id(self.h_value_change_id) 580 remove_signal_id(self.h_change_id) 581 582 self.hadjustment = adj 583 h_value_change_handler_id = self.hadjustment.connect('value-changed', self.hadjustment_changed) 584 h_change_handler_id = self.hadjustment.connect('changed', self.update_scrollbar) 585 self.h_value_change_id = (self.hadjustment, h_value_change_handler_id) 586 self.h_change_id = (self.hadjustment, h_change_handler_id)587589 ''' 590 Sets the gtk.Adjustment for the vertical scrollbar. 591 592 @param adj: vertical scroll adjustment 593 ''' 594 remove_signal_id(self.v_value_change_id) 595 remove_signal_id(self.v_change_id) 596 597 self.vadjustment = adj 598 v_value_change_handler_id = self.vadjustment.connect('value-changed', self.vadjustment_changed) 599 v_change_handler_id = self.vadjustment.connect('changed', self.update_scrollbar) 600 self.v_value_change_id = (self.vadjustment, v_value_change_handler_id) 601 self.v_change_id = (self.vadjustment, v_change_handler_id)602604 for i in xrange(0, int(self.vadjustment.upper-self.vadjustment.page_size), 30): 605 pos = value2pos(i, self._vertical.virtual_len, self.vadjustment.upper) 606 print "value:%f --> pos:%d" % (i, pos), 607 assert(pos <= self.allocation.height-self._vertical.bar_len),\ 608 "pos(%f) should small than(%f)" % (pos, self.allocation.height-self._vertical.bar_len) 609 value = pos2value(pos, self._vertical.virtual_len, self.vadjustment.upper) 610 print "\t pos:%d -->value:%f" % (pos, value) 611 612 print "v_len:%f, height:%f, vir_bar_len:%d" % ( self._vertical.virtual_len, 613 self.allocation.height, self._vertical.bar_len)614 615 gobject.type_register(ScrolledWindow) 616
Home | Trees | Indices | Help |
|
---|
Generated by Epydoc 3.0.1 on Wed Aug 8 13:17:39 2012 | http://epydoc.sourceforge.net |