Changeset 381

Show
Ignore:
Timestamp:
09/15/07 17:51:11 (1 year ago)
Author:
bjourne
Message:

Major updates to the docs. These changes haven't occured yet, but
will. The doc updates specifies how the end result will look like. Add
two classes; PixbufDrawOpts and PixbufDrawCache. These correspond to
the (soon to be removed) classes ImageViewDrawer and DrawSettings in
gtkimageview. Also document the soon to be wrapped damage_pixels() and
image_to_widget_rect() methods and how the pixbuf_changed() has
changed.

Also add a section to the release history documenting these changes.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • pygtkimageview/docs/gtkimageview.py

    r374 r381  
    4848classes GtkImageView's classes subclass. Instead, see the class 
    4949descriptions for inheritance information. 
     50 
     51Release history 
     52=============== 
     53Major changes between version of PyGtkImageView. For a complete 
     54history, also see the *Release history* document in GtkImageView. 
     55 
     56Major changes in svn HEAD 
     57------------------------- 
     58* The methods `ImageView.damage_pixels()` and 
     59  `ImageView.image_to_widget_rect()` was added. 
     60* The `IImageTool.pixbuf_changed()` method got a third argument. 
     61 
     62Major changes in 1.0.0 
     63---------------------- 
     64None! First release. :) 
     65 
    5066 
    5167:author: `Björn Lindqvist <bjourne@gmail.com>`__ 
     
    5874:todo: Fix the PDF generation so that images can be used both in the 
    5975    HTML and in the PDF documentation. 
    60 :todo: Think out a good way to partially update the pixbuf. 
    6176:todo: Slap it up on PyPI. 
    6277 
     
    7388TRANSP_BACKGROUND = 3 
    7489 
     90#: Enumeration value to scale the area of the pixbuf to draw and put 
     91#: the result in cache. This is the slowest draw method as the whole 
     92#: area to be drawn must be rescaled. It is mostly used when no part of 
     93#: `PixbufDrawCache`:s cache is valid. 
     94#: 
     95#: :see: `PixbufDrawCache.get_method()` 
     96#: :see: `PixbufDrawCache.invalidate()` 
     97DRAW_METHOD_SCALE = 0 
     98#: Enumeration value to get the area of the pixbuf to draw from the  
     99#: cache and not update the cache afterwards. 
     100#: 
     101#: :see: `PixbufDrawCache.get_method()` 
     102DRAW_METHOD_CONTAINS = 1 
     103#: Enumeration value to partially use the cache and scale the region  
     104#: not cached. The cache is updated with the result. 
     105#: 
     106#: :see: `PixbufDrawCache.get_method()` 
     107DRAW_METHOD_SCROLL = 2 
     108 
     109class PixbufDrawOpts: 
     110    ''' 
     111    Container class which holds options for how the pixbuf should be 
     112    drawn. Options include such things like the source rectangle in 
     113    the pixbuf to draw, where to draw it, which zoom to use and so on. 
     114 
     115    :see: `PixbufDrawCache.draw()` 
     116    ''' 
     117    def __init__(self, zoom, zoom_rect, widget_x, widget_y, interp, pixbuf, check_color1, check_color2): 
     118        self.zoom = zoom 
     119        '''Zoom factor.''' 
     120        self.zoom_rect = zoom_rect 
     121        '''Rectangle in zoom space coordinates of the area to draw.''' 
     122        self.widget_x = widget_x 
     123        '''X-coordinate of the draw location on the widget.''' 
     124        self.widget_y = widget_y 
     125        '''Y-coordinate of the draw location on the widget.''' 
     126        self.interp = interp 
     127        '''Which ``gtk.gdk.InterpType`` to use.''' 
     128        self.pixbuf = pixbuf 
     129        '''Pixbuf to draw from.''' 
     130        self.check_color1 = check_color1 
     131        '''The first color to use for drawing transparent parts.''' 
     132        self.check_color2 = check_color2 
     133        '''The second color to use for drawing transparent parts.''' 
     134 
     135class PixbufDrawCache: 
     136    ''' 
     137    Cache that ensures fast redraws by storing the last draw 
     138    operation. For example, when resizing an `ImageView`, it will 
     139    receive an expose event and must redraw the damaged region. Unless 
     140    fitting is ``True``, most of the pixels it should draw are 
     141    indentical to the ones drawn the previous time. Redrawing them is 
     142    wasteful because scaling and especially bilinear scaling is very 
     143    slow. Therefore, PixbufDrawCache objectifies the drawing process 
     144    and adds a cache with the last draw from which pixels can be 
     145    fetched. 
     146 
     147    This class is present purely to ensure optimal speed. An 
     148    `IImageTool` that is asked to redraw a part of the image view 
     149    widget could either do it manually with something like this: 
     150 
     151    .. python:: 
     152 
     153       def paint_image(self, draw_opts, drawable): 
     154           zoom_rect = draw_opts.zoom_rect 
     155           scaled = draw_opts.pixbuf.scale(0, 0, 
     156                                           zoom_rect.width, zoom_rect.height, 
     157                                           -zoom_rect.x, -zoom_rect.y, 
     158                                           draw_opts.zoom, 
     159                                           draw_opts.interp, 
     160                                           zoom_rect.x, zoom_rect.y, 
     161                                           16, 
     162                                           draw_opts.check_color1, 
     163                                           draw_opts.check_color2) 
     164           drawable.draw_pixbuf(NULL, scaled, 
     165                                0, 0, 
     166                                draw_opts.widget_x, draw_opts.widget_y, 
     167                                zoom_rect.width, zoom_rect.height, 
     168                                gtk.gdk.RGB_DITHER_MAX, 
     169                                draw_opts.widget_x, draw_opts.widget_y) 
     170 
     171    ''' 
     172 
     173     
     174    def __init__(self): 
     175        ''' 
     176        Create a new pixbuf draw cache. 
     177        ''' 
     178 
     179    def invalidate(self): 
     180        ''' 
     181        Force the draw cache to scale the pixbuf at the next draw.  
     182 
     183        `PixbufDrawCache` tries to minimize the number of scale 
     184        operations needed by caching the last drawn pixbuf. It would 
     185        be inefficient to check the individual pixels inside the 
     186        pixbuf so it assumes that if the memory address of the pixbuf 
     187        has not changed, then the cache is good to use. 
     188 
     189        However, when the image data is modified, this assumtion 
     190        breaks, which is why this method must be used to tell draw 
     191        cache about it. 
     192 
     193        :see: `DRAW_METHOD_SCALE` 
     194        :see: `draw()` 
     195        :see: `ImageView.damage_pixels()` 
     196        ''' 
     197 
     198    def draw(self, draw_opts, drawable): 
     199        ''' 
     200        Draw on the drawable using the specified draw options. 
     201        ''' 
     202 
     203    @classmethod 
     204    def get_method(cls, last_opts, new_opts): 
     205        ''' 
     206        Get the fastest method to draw the specified draw options. 
     207        `last_opts` is assumed to be the last `PixbufDrawOpts` used 
     208        and `new_opts` is the one to use this time. 
     209 
     210        This function returns one of the three constants 
     211        `DRAW_METHOD_CONTAINS`, `DRAW_METHOD_SCROLL` or 
     212        `DRAW_METHOD_SCALE`. 
     213 
     214        :param last_opts: the last draw options used 
     215        :param new_opts: the current draw options 
     216        :return: the best draw method to use to draw 
     217        ''' 
     218 
    75219class IImageTool: 
    76220    ''' 
     
    102246    def motion_notify(self, ev_motion): 
    103247        pass 
    104     def pixbuf_changed(self, reset_fit): 
    105         ''' 
    106         This method is called by the view whenever its pixbuf or its 
    107         tool changes. That is, when any of the methods 
    108         `ImageView.set_pixbuf()` or `ImageView.set_tool()` is invoked. 
    109         If the `reset_fit` parameter is ``True``, then the tool is 
    110         free to treat the pixbuf as completely new. See also 
    111         `ImageView.sig_pixbuf_changed`. 
    112  
     248    def pixbuf_changed(self, reset_fit, rect): 
     249        ''' 
     250        Indicate to the tool that either a part of, or the whole 
     251        pixbuf that the image view shows has changed. This method is 
     252        called by the view whenever its pixbuf or its tool changes. 
     253        That is, when any of the following method are used: 
     254 
     255        * `ImageView.set_pixbuf()` 
     256        * `ImageView.set_tool()` 
     257        * `ImageView.damage_pixels()` 
     258         
     259        If the `reset_fit` parameter is ``True``, it means that a new 
     260        pixbuf has been loaded into the view. `rect` is a rectangle in 
     261        image space coordinates that indicates which region of the 
     262        pixbufs pixels that is modified. `rect` can be ``None`` which 
     263        means that all image data in the pixbuf has been changed. 
     264 
     265        :see: `ImageView.sig_pixbuf_changed` 
    113266        :param reset_fit: whether the view is resetting its fit mode 
    114267            or not 
     268        :param rect: a ``gtk.gdk.Rectangle`` containing the changed 
     269            area or ``None`` 
    115270        ''' 
    116271 
     
    128283    def cursor_at_point(self, x, y): 
    129284        ''' 
    130         Ask the tool what cursor it wants displayed. 
     285        Get the cursor to display when the mouse pointer is over the 
     286        widget coordinate (`x`, `y`). 
    131287 
    132288        :param x: the mouse pointers x-coordinate 
     
    317473class ImageScrollWin: 
    318474    ''' 
    319     ImageScrollWin provides a widget similar in appearance to 
     475    Provides a widget similar in appearance to 
    320476    ``gtk.ScrollableWindow`` that is more suitable for displaying 
    321477    `ImageView`'s. 
     
    446602    However, this feature means that a client application must signal 
    447603    to the view when it changes the pixels on the pixbuf that the view 
    448     shows. The right way to do that is to use `ImageView.set_pixbuf()` 
    449     with the old pixbuf as the argument. In particular, code that 
    450     merely tries to update the view by requesting that it should be 
    451     redrawn will not work. 
     604    shows. The right way to do that is to use 
     605    `ImageView.damage_pixels()`. Code that merely tries to update the 
     606    view by requesting that it should be redrawn will not work. 
    452607 
    453608    .. python:: 
     
    456611       view.queue_draw_area(10, 10, 50, 50)     # Incorrect! 
    457612 
    458     In future versions of PyGtkImageView a method will be added that 
    459     marks an area of the pixbuf as dirty and forces the view to flush 
    460     its cache. 
    461      
    462613    Example 
    463614    ======= 
     
    491642        get_interpolation, set_interpolation, 
    492643        get_show_cursor, set_show_cursor, get_show_frame, set_show_frame 
    493     :group Zooming: zoom_in, zoom_out     
    494     ''' 
     644    :group Actions: zoom_in, zoom_out, damage_pixels, 
     645        image_to_widget_rect ''' 
    495646 
    496647    def __init__(self): 
     
    513664        ''' 
    514665        The pixbuf-changed signal is emitted when the pixbuf the image 
    515         view shows is changed. Listening to this signal is useful if 
    516         you, for example, have a label that displays the width and 
    517         height of the pixbuf in the view. 
     666        view shows or its image data is changed. Listening to this 
     667        signal is useful if you, for example, have a label that 
     668        displays the width and height of the pixbuf in the view. 
    518669 
    519670        .. python:: 
     
    547698           view.connect('zoom-changed', zoom_cb, label) 
    548699        ''' 
    549      
     700 
    550701    def zoom_in(self): 
    551702        ''' 
     
    558709        Zoom in the view one step. The widget is immidiately 
    559710        repainted. 
     711        ''' 
     712 
     713    def damage_pixels(self, rect): 
     714        ''' 
     715        Mark the pixels in the rectangle as damaged. That the pixels 
     716        are damaged, means that they have been modified and that the 
     717        view must redraw them to ensure that the visible part of the 
     718        image corresponds to the pixels in that image. 
     719 
     720        Damaging first causes the `IImageTool.pixbuf_changed()` to be 
     721        called which allows the tool to, for example, update its cache 
     722        of the pixbuf if it has one. 
     723 
     724        The signal `sig_pixbuf_changed` is emitted which enables 
     725        interested listeners to update their view of the pixbuf. And 
     726        finally is the visible part of the damaged rectangle queued 
     727        for redraw. 
     728 
     729        :param rect: the ``gtk.gdk.Rectangle`` in image space 
     730            coordinates to mark as dirty. 
     731        :see: `set_pixbuf()` 
     732        :see: `sig_pixbuf_changed` 
     733        ''' 
     734 
     735    def image_to_widget_rect(self, rect): 
     736        ''' 
     737        Converts a rectangle in image space coordinates to widget 
     738        space coordinates. If the view is not realized, or if it 
     739        contains no pixbuf, then the conversion cannot be done and 
     740        ``None`` is returned. 
     741 
     742        Note that this method may return a rectangle that is not 
     743        visible on the widget. 
     744 
     745        A use for this method would be if you for example is 
     746        implementing an `IImageTool` and want to return a special 
     747        ``gtk.gdk.Cursor`` if the pointer is over a hotspot in the 
     748        image: 
     749 
     750        .. python:: 
     751 
     752           def cursor_at_point(self, x, y): 
     753               wid_rect = self.view.image_to_widget_rect(self.hotspot) 
     754               # Use the default cursor if the the view isn't realized 
     755               # or if the pointer isn't over the hotspot. 
     756               if not wid_rect: 
     757                   return None 
     758               if not (x >= wid_rect.x and x < wid_rect.x + wid_rect.width and 
     759                       y >= wid_rect.y and y < wid_rect.y + wid_rect.height): 
     760                   return None 
     761               # Use the hotspot cursor if the pointer is over the hotspot. 
     762               return self.hotspot_cursor 
     763 
     764        :param rect: a ``gtk.gdk.Rectangle`` in image space 
     765            coordinates. 
     766        :return: a ``gtk.gdk.Rectangle`` of the widget space 
     767            coordinates or ``None`` 
    560768        ''' 
    561769 
     
    9011109        The default pixbuf animation is ``None``. 
    9021110 
     1111        :see: `ImageView.set_pixbuf()` 
    9031112        :param anim: a pixbuf animation to play 
    9041113        '''