예제 #1
0
    def __init__(self, uuid, label):

        #self.__last_rotate = 0

        # throbber pixbuf
        #self.__throbber = None
        #self.__throbber_width = 0
        #self.__throbber_height = 0

        # number of frames in throbber animation
        #self.__number_of_frames = 0
        #self.__current_frame = 0

        self.uuid = uuid

        self.__save_under = Pixmap(None, _WIDTH, _HEIGHT)
        self.__buffer = Pixmap(None, _WIDTH, _HEIGHT)

        Widget.__init__(self)
        self.set_size(_WIDTH, 200)

        self.__label = Label(label, theme.font_mb_plain,
                             theme.color_mb_panel_text)
        self.__label.set_alignment(self.__label.CENTERED)
        self.__label.set_pos(10, 10)
        self.__label.set_size(_WIDTH - 20, 0)
        self.add(self.__label)
예제 #2
0
    def __init__(self):
                
        self.__render_map_next = 0

        # not everybody wants Europe in the center
        self.__map_offset = 0
                
        self.__night = gtk.gdk.pixbuf_new_from_file(
            os.path.join(_PATH, "0-Night.jpg"))
            
        self.__sun = gtk.gdk.pixbuf_new_from_file(
            os.path.join(_PATH, "sun.png"))
            
        self.__numbers = gtk.gdk.pixbuf_new_from_file(
            os.path.join(_PATH, "numbers.png"))
    
        Widget.__init__(self)
        self.set_size(800, 400)
    
        # mask for overlaying the night
        self.__mask = gtk.gdk.Pixmap(None, 800, 400, 1)
        self.__mask_gc = self.__mask.new_gc()
    
        # buffer for holding the rendered map
        self.__map = Pixmap(None, 800, 400)
    
        # buffer for the screen
        self.__screen = Pixmap(None, 800, 400)
예제 #3
0
    def render_this(self):

        x, y = self.get_screen_pos()
        w, h = self.get_size()
        screen = self.get_screen()

        if (not self.__buffer):
            self.__buffer = Pixmap(None, w, h)

        if (self.__background):
            self.__buffer.draw_pixbuf(self.__background, 0, 0)
        else:
            self.__buffer.fill_area(0, 0, w, h, theme.color_mb_background)

        sw = self.__button_pbuf.get_width()
        sh = self.__button_pbuf.get_height()

        if (self.__is_active):
            if (self.__mode == self.HORIZONTAL):
                pos = int((w - sw) * self.__value)
                self.__buffer.draw_pixbuf(self.__button_pbuf, pos, 0)
            else:
                pos = int((h - sh) * self.__value)
                self.__buffer.draw_pixbuf(self.__button_pbuf, 0, pos)
            self.__previous_pos = pos
        #end if

        screen.copy_buffer(self.__buffer, 0, 0, x, y, w, h)
예제 #4
0
    def set_size(self, w, h):

        Widget.set_size(self, w, h)

        if ((w, h) != self.__visible_size):
            self.__visible_size = (w, h)
            self.__invalidated = True
            self.__offscreen = Pixmap(None, w, h)
            self.__buffer = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, True, 8, w,
                                           h)

            if (self.__original_size != (0, 0)):
                self._render()
                self.__scale_to_fit()
예제 #5
0
    def set_size(self, w, h):

        if (w < h):
            edges = Pixmap.LEFT
        else:
            edges = Pixmap.TOP

        if (not self.__bg_pmap or (w, h) != self.get_size()):
            self.__buffer = None
            self.__bg_pmap = Pixmap(None, w, h)
            self.__bg_pmap.fill_area(0, 0, w, h, theme.color_mb_background)
            self.__bg_pmap.draw_frame(theme.mb_panel, 0, 0, w, h, True, edges)

            self.__box.set_size(w, h)

        Widget.set_size(self, w, h)
예제 #6
0
    def __init_buffer(self):
        """
        Initializes the offscreen buffer.
        """

        w, h = self.get_size()

        self.__background = Pixmap(None, w, h)
        self.__background.clear_translucent()
        self.set_background(self.__bg_color)

        self.__buffer = Pixmap(None, w, h)
        self.invalidate()

        for i in range(len(self.get_items())):
            self.__render_item(i)
예제 #7
0
    def set_size(self, w, h):

        if ((w, h) != self.get_size()):
            self.__offscreen_buffer = Pixmap(None, w, h)
            self.__cover_scaled = None
            
        Player.set_size(self, w, h)
예제 #8
0
    def __handle_configure_event(self):
        """
        Handles the last window configure event in a row. Maemo5 sometimes
        shoots several in a row and we should only react on the last one.
        """

        # thaw rendering at the last of possibly several configure events in
        # a row
        self.set_frozen(False)

        self.__configure_event_handler = None
        w, h = self.__window.get_size()
        self.__screen = Pixmap(self.__window.window)
        self.__screen.fill_area(0, 0, w, h, theme.color_mb_background)
        self.set_screen(self.__screen)

        self.set_size(w, h)
        self.render()
예제 #9
0
 def __prepare_scala(self):
 
     w, h = self.get_size()
     #h -= 20
     self.__scala_pmap = Pixmap(None, w, h)
     self.__scala_pmap.fill_area(0, 0, w, h, theme.color_mb_background)
     
     a, b = self.__range
     step_size = h / (b - a)
     
     i = 0
     j = a
     while (j < b + 0.1):
         y = int(i + 0.5)   # because floor(x + 0.5) = round(x)
         if (int(j - 0.4) != int(j)):
             self.__scala_pmap.draw_line(0, y, 55, y, "#666666")
             if (int(j) % 5 == 0):
                 self.__scala_pmap.draw_text("%3.1f" % (j + 0.5),
                                             theme.font_mb_micro, 
                                             2, y, "#666666")
         else:
             self.__scala_pmap.draw_line(40, y, 55, y, "#666666")
         i += step_size / 2
         j += 0.5
예제 #10
0
    def _get_cached_pixmap(self):
        """
        Returns a cached pixmap object for this item, and whether it was newly
        created.
        
        @return: tuple of (pixmap, is_new)
        """
        
        w, h = self.get_size()
        
        cnt = 0
        for ident, pmap in _CACHE:
            if (ident == self):
                if ((w, h) == pmap.get_size()):
                    # cached pixmap is OK
                    return (pmap, False)

                else:
                    # remove pixmap from cache
                    del _CACHE[cnt]
                    break
            #end if
            cnt += 1
        #end for
        
        # pixmap is not cached yet; create a new one
        pmap = Pixmap(None, w, h)

        # cache some items to accelerate rendering
        if (self.__is_cachable):
            _CACHE.append((self, pmap))
        
        # remove old pixmaps from cache
        while (len(_CACHE) > _CACHE_SIZE):
            del _CACHE[0]

        return (pmap, True)
예제 #11
0
    def set_toolbar(self, *tbset):
        """
        Sets the given toolbar on this panel.
        """

        if (tuple(tbset) == tuple(self.__current_set)):
            return

        self.__current_set = tbset

        for c in self.__box.get_children():
            self.__box.remove(c)

        for c in tbset:
            self.__box.add(c, True)
            c.set_visible(True)

        if (not self.__buffer):
            w, h = self.get_size()
            if (w > 0 and h > 0):
                self.__buffer = Pixmap(None, w, h)

        if (self.__buffer):
            self.render_buffered(self.__buffer)
예제 #12
0
class Slider(Widget):
    """
    A horizontal or vertical slider widget.
    @since: 0.96.5
    """

    HORIZONTAL = 0
    VERTICAL = 1

    EVENT_VALUE_CHANGED = "value-changed"

    def __init__(self, button_pbuf):
        """
        Creates a new slider with the given pixbuf for the slider.
        
        @param button_pbuf: pixbuf for the slider
        """

        # background pbuf
        self.__background = None

        # offscreen buffer
        self.__buffer = None

        self.__mode = self.HORIZONTAL
        self.__value = 0.0
        self.__button_pbuf = button_pbuf

        self.__is_dragging = False
        self.__grab_point = 0
        self.__previous_pos = 0

        self.__is_active = True

        # time of last motion
        self.__last_motion_time = 0

        Widget.__init__(self)
        self.connect_button_pressed(self.__on_press)
        self.connect_button_released(self.__on_release)
        self.connect_pointer_moved(self.__on_motion)

    def connect_value_changed(self, cb, *args):

        self._connect(self.EVENT_VALUE_CHANGED, cb, *args)

    def _reload(self):

        w, h = self.get_size()
        self.__buffer = None

    def set_active(self, value):

        self.__is_active = value
        self.render()

    def set_image(self, pbuf):

        self.__button_pbuf = pbuf
        self.render()

    def set_background(self, pbuf):

        self.__background = pbuf

    def set_size(self, w, h):

        Widget.set_size(self, w, h)

        if (w == 0 or h == 0): return

        if (self.__buffer and (w, h) != self.__buffer.get_size()):
            self.__buffer = None

    def set_mode(self, mode):
        """
        Switches the orientation mode.
        
        @param mode: one of C{HORIZONTAL} or C{VERTICAL}
        """

        self.__mode = mode

    def set_value(self, v):
        """
        Sets the slider value within the range [0.0, 1.0].
        This action does not emit a "value-changed" event.
        
        @param v: value
        """

        v = min(1.0, max(0.0, v))
        if (self.__mode == self.VERTICAL):
            v = 1.0 - v
        if (abs(v - self.__value) > 0.01):
            self.__value = v
            self.move(v)

    def get_value(self):
        """
        Returns the current value within the range [0.0, 1.0].

        @return: current value
        """

        return self.__value

    def render_this(self):

        x, y = self.get_screen_pos()
        w, h = self.get_size()
        screen = self.get_screen()

        if (not self.__buffer):
            self.__buffer = Pixmap(None, w, h)

        if (self.__background):
            self.__buffer.draw_pixbuf(self.__background, 0, 0)
        else:
            self.__buffer.fill_area(0, 0, w, h, theme.color_mb_background)

        sw = self.__button_pbuf.get_width()
        sh = self.__button_pbuf.get_height()

        if (self.__is_active):
            if (self.__mode == self.HORIZONTAL):
                pos = int((w - sw) * self.__value)
                self.__buffer.draw_pixbuf(self.__button_pbuf, pos, 0)
            else:
                pos = int((h - sh) * self.__value)
                self.__buffer.draw_pixbuf(self.__button_pbuf, 0, pos)
            self.__previous_pos = pos
        #end if

        screen.copy_buffer(self.__buffer, 0, 0, x, y, w, h)

    def move(self, v):

        if (not self.__buffer): return

        x, y = self.get_screen_pos()
        w, h = self.get_size()
        screen = self.get_screen()
        btn_w = self.__button_pbuf.get_width()
        btn_h = self.__button_pbuf.get_height()

        if (self.__mode == self.HORIZONTAL):
            new_pos = int((w - btn_w) * v)
        else:
            new_pos = int((h - btn_h) * v)

        pos = self.__previous_pos
        min_pos = min(new_pos, pos)
        max_pos = max(new_pos, pos)
        delta = new_pos - pos

        if (delta == 0): return

        self.render()
        self.__previous_pos = new_pos
        return

        if (self.__mode == self.HORIZONTAL):
            #self.__render_background(self.__buffer,
            #                         min_pos, 0,
            #                         max_pos - min_pos + btn_w, btn_h)
            self.__buffer.draw_pixbuf(self.__button_pbuf, pos, 0)
            """
            self.__buffer.move_area(pos, 0, btn_w, btn_h, delta, 0)
            if (delta > 0):
                self.__render_background(self.__buffer,
                                         min_pos, 0,
                                         abs(delta), btn_h)
            else:
                self.__render_background(self.__buffer,
                                         min_pos + btn_w, 0,
                                         abs(delta), btn_h)
            
            """
            if (self.may_render()):
                screen.copy_buffer(self.__buffer, min_pos, 0, x + min_pos, y,
                                   btn_w + abs(delta), btn_h)
        else:
            #self.__render_background(self.__buffer,
            #                         0, min_pos,
            #                         btn_w, max_pos - min_pos + btn_h)
            self.__buffer.draw_pixbuf(self.__button_pbuf, 0, pos)
            """
            self.__buffer.move_area(0, pos, btn_w, btn_h, 0, delta)
            if (delta > 0):
                self.__render_background(self.__buffer,
                                         0, min_pos,
                                         btn_w, abs(delta))
            else:
                self.__render_background(self.__buffer,
                                         0, min_pos + btn_h,
                                         btn_w, abs(delta))

            """
            if (self.may_render()):
                screen.copy_buffer(self.__buffer, 0, min_pos, x, y + min_pos,
                                   btn_w, btn_h + abs(delta))

    def __render_background(self, buf, x, y, w, h):

        if (self.__background):
            buf.draw_subpixbuf(self.__background, x, y, x, y, w, h)
        else:
            buf.fill_area(x, y, w, h, theme.color_mb_background)

    def __on_press(self, px, py):

        self.__is_dragging = True

        w, h = self.get_size()
        sw = self.__button_pbuf.get_width()
        sh = self.__button_pbuf.get_height()

        if (self.__mode == self.HORIZONTAL):
            pos = (w - sw) * self.__value
            self.__grab_point = max(0, min(px - pos, sw))
        else:
            pos = (h - sh) * self.__value
            self.__grab_point = max(0, min(py - pos, sh))
        self.__on_motion(px, py)

    def __on_release(self, px, py):

        self.__is_dragging = False

    def __on_motion(self, px, py):

        if (self.__is_dragging):
            #now = time.time()
            #if (now - self.__last_motion_time < 0.1): return
            #self.__last_motion_time = now

            w, h = self.get_size()
            sw = self.__button_pbuf.get_width()
            sh = self.__button_pbuf.get_height()

            if (self.__mode == self.HORIZONTAL):
                px -= self.__grab_point
                px = min(w - sw, max(0, px))
                v = px / float(w - sw)
            else:
                py -= self.__grab_point
                py = min(h - sh, max(0, py))
                v = 1.0 - py / float(h - sh)

            self.set_value(v)

            #self.render()
            self.send_event(self.EVENT_VALUE_CHANGED, v)
예제 #13
0
class DeviceDialog(Widget):
    def __init__(self, uuid, label):

        #self.__last_rotate = 0

        # throbber pixbuf
        #self.__throbber = None
        #self.__throbber_width = 0
        #self.__throbber_height = 0

        # number of frames in throbber animation
        #self.__number_of_frames = 0
        #self.__current_frame = 0

        self.uuid = uuid

        self.__save_under = Pixmap(None, _WIDTH, _HEIGHT)
        self.__buffer = Pixmap(None, _WIDTH, _HEIGHT)

        Widget.__init__(self)
        self.set_size(_WIDTH, 200)

        self.__label = Label(label, theme.font_mb_plain,
                             theme.color_mb_panel_text)
        self.__label.set_alignment(self.__label.CENTERED)
        self.__label.set_pos(10, 10)
        self.__label.set_size(_WIDTH - 20, 0)
        self.add(self.__label)

    """def set_throbber(self, throbber):

        self.__throbber = throbber
        self.__throbber_height = throbber.get_height()
        self.__throbber_width = self.__throbber_height
        self.__current_frame = 0
        self.__number_of_frames = throbber.get_width() / self.__throbber_width

        w, h = self.get_size()
        h = self.__throbber_height + 60
        self.set_size(w, h)

        self.__label.set_pos(10, self.__throbber_height + 20)

        self.__save_under = Pixmap(None, w, h)
        self.__buffer = Pixmap(None, w, h)"""
    """def set_text(self, text):
    
        self.__label.set_text(text)"""

    def render_this(self):

        parent = self.get_parent()
        px, py = parent.get_screen_pos()
        pw, ph = parent.get_size()

        w, h = self.get_size()
        screen = self.get_screen()

        x = (pw - w) / 2
        y = (ph - h) / 2
        self.set_pos(x, y)

        x, y = self.get_screen_pos()

        screen.draw_frame(theme.mb_panel, x, y, w, h, True)

        self.__save_under.copy_buffer(screen, x, y, 0, 0, w, h)
        #self.__render_current()

    """def __render_current(self):

        x, y = self.get_screen_pos()
        w, h = self.get_size()
        screen = self.get_screen()

        self.__buffer.copy_pixmap(self.__save_under, 0, 0, 0, 0, w, h)

        if (self.__throbber):
            tx = (w - self.__throbber_width) / 2
            ty = 10

            frame_offset = self.__current_frame * self.__throbber_width
            self.__buffer.draw_subpixbuf(self.__throbber, frame_offset, 0, 
                         tx, ty, self.__throbber_width, self.__throbber_height)
        
        if (self.may_render()):
            screen.copy_pixmap(self.__buffer, tx, ty, x + tx, y + ty,
                               self.__throbber_width, self.__throbber_height)"""
    """def rotate(self):
    
        now = time.time()
        if (now - self.__last_rotate > 0.05):    
            self.__render_current()
            self.__current_frame += 1
            self.__current_frame %= self.__number_of_frames
            while(gtk.events_pending()): gtk.main_iteration()
        
            self.__last_rotate = now
        #end if"""

    def set_visible(self, value):

        if (not value): time.sleep(0.25)
        self.set_events_blocked(value)
        Widget.set_visible(self, value)
예제 #14
0
    def __init__(self):

        # client-side buffer for scaling
        self.__buffer = None

        # color of the background
        self.__bg_color = "#000000"

        # offscreen drawing pixmap
        self.__offscreen = Pixmap(None, gtk.gdk.screen_width(),
                                  gtk.gdk.screen_height())

        # original size of the image
        self.__original_size = (0, 0)

        # the visible size is the size of the image widget
        self.__visible_size = (100, 100)

        # the virtual size is the size of whole image zoomed
        self.__virtual_size = (0, 0)

        # center is the point on the virtual area that is in the
        # center of the visible area
        self.__center_pos = (0, 0)

        # the previous offset allows us to determine what to render
        # new and what to simply copy
        self.__previous_offset = (0, 0)

        # render completely new when this flag is set, e.g. after zooming
        self.__invalidated = True

        # flag for marking new images that have not been rendered to screen yet
        self.__is_new_image = False

        self.__hi_quality_timer = None

        # the currently available zoom levels (= _ZOOM_LEVELS + fitting)
        self.__zoom_levels = []
        self.__zoom_level = 4
        self.__zoom_value = 1.0
        self.__zoom_fit = 0
        self.__zoom_100 = 0

        self.__current_file = ""

        # the loader contains the complete image
        self.__loader = None
        self.__is_loading = False
        self.__currently_loading = None
        self.__pixbuf = None

        # flag for aborting the load process if it would cause trouble
        self.__loading_aborted = False

        # slide from right or left
        self.__slide_from_right = True

        # progress percentage value
        self.__progress = 0

        # amount by which the image is dragged
        self.__drag_amount = 0

        # rendering overlays
        self.__overlays = []

        Widget.__init__(self)

        # create a client-side pixmap for scaling
        self.__buffer = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, True, 8,
                                       gtk.gdk.screen_width(),
                                       gtk.gdk.screen_height())
예제 #15
0
class Image(Widget):
    """
    Class for rendering images.
    """
    def __init__(self):

        # client-side buffer for scaling
        self.__buffer = None

        # color of the background
        self.__bg_color = "#000000"

        # offscreen drawing pixmap
        self.__offscreen = Pixmap(None, gtk.gdk.screen_width(),
                                  gtk.gdk.screen_height())

        # original size of the image
        self.__original_size = (0, 0)

        # the visible size is the size of the image widget
        self.__visible_size = (100, 100)

        # the virtual size is the size of whole image zoomed
        self.__virtual_size = (0, 0)

        # center is the point on the virtual area that is in the
        # center of the visible area
        self.__center_pos = (0, 0)

        # the previous offset allows us to determine what to render
        # new and what to simply copy
        self.__previous_offset = (0, 0)

        # render completely new when this flag is set, e.g. after zooming
        self.__invalidated = True

        # flag for marking new images that have not been rendered to screen yet
        self.__is_new_image = False

        self.__hi_quality_timer = None

        # the currently available zoom levels (= _ZOOM_LEVELS + fitting)
        self.__zoom_levels = []
        self.__zoom_level = 4
        self.__zoom_value = 1.0
        self.__zoom_fit = 0
        self.__zoom_100 = 0

        self.__current_file = ""

        # the loader contains the complete image
        self.__loader = None
        self.__is_loading = False
        self.__currently_loading = None
        self.__pixbuf = None

        # flag for aborting the load process if it would cause trouble
        self.__loading_aborted = False

        # slide from right or left
        self.__slide_from_right = True

        # progress percentage value
        self.__progress = 0

        # amount by which the image is dragged
        self.__drag_amount = 0

        # rendering overlays
        self.__overlays = []

        Widget.__init__(self)

        # create a client-side pixmap for scaling
        self.__buffer = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, True, 8,
                                       gtk.gdk.screen_width(),
                                       gtk.gdk.screen_height())

    def add_overlay(self, overlay):

        self.__overlays.append(overlay)

    def __copy_image_buffer(self, buf1, buf2):

        x, y = self.get_screen_pos()
        w, h = self.get_size()

        if (self.__drag_amount >= 0):
            src_x = 0
            dst_x = x + self.__drag_amount
            dst_w = w - self.__drag_amount
            if (self.__drag_amount != 0):
                buf2.fill_area(0, 0, self.__drag_amount, h, self.__bg_color)
        else:
            src_x = 0 - self.__drag_amount
            dst_x = x
            dst_w = w + self.__drag_amount
            buf2.fill_area(dst_w, 0, abs(self.__drag_amount), h,
                           self.__bg_color)

        buf2.copy_pixmap(buf1, 0, 0, x, y, w, h)

    def render_this(self):

        x, y = self.get_screen_pos()
        w, h = self.get_size()
        if (self.__progress): h -= 16
        screen = self.get_screen()
        if (self.__invalidated):
            self._render()
        else:
            self.__copy_image_buffer(self.__offscreen, screen)

    def set_size(self, w, h):

        Widget.set_size(self, w, h)

        if ((w, h) != self.__visible_size):
            self.__visible_size = (w, h)
            self.__invalidated = True
            self.__offscreen = Pixmap(None, w, h)
            self.__buffer = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, True, 8, w,
                                           h)

            if (self.__original_size != (0, 0)):
                self._render()
                self.__scale_to_fit()
                #gobject.idle_add(self.__scale_to_fit)

    def set_background(self, col):

        self.__bg_color = col
        self.__invalidated = True
        #self.__offscreen.fill_area(0, 0, 800, 480, self.__bg_color)

    def __hi_quality_render(self):

        self.__invalidated = True
        self._render(True)

    def scroll_to(self, x, y):

        width, height = self.__visible_size
        vwidth, vheight = self.__virtual_size
        x = max(width / 2, min(x, vwidth - width / 2))
        y = max(height / 2, min(y, vheight - height / 2))
        self.__center_pos = (x, y)

        self._render(False)
        #gobject.idle_add(self._render, False)

    def scroll_by(self, dx, dy):

        cx, cy = self.__center_pos
        self.scroll_to(cx + dx, cy + dy)

    def move(self, dx, dy):

        self.scroll_by(dx, dy)
        return (dx, dy)

    def set_drag_amount(self, amount):

        self.__drag_amount = amount
        self.render()

    def __get_offset(self):
        """
        Returns the required offset coordinates for the
        current center.
        """

        cx, cy = self.__center_pos
        width, height = self.__visible_size
        vwidth, vheight = self.__virtual_size

        offx = max(0, min(cx - width / 2, vwidth - width))
        offy = max(0, min(cy - height / 2, vheight - height))

        return (int(offx), int(offy))

    def is_image_fitting(self):
        """
        Returns whether the image fits the screen (True) or has to be
        scrolled (False).
        """

        w, h = self.get_size()
        virtual_w, virtual_h = self.__virtual_size

        return (virtual_w <= w and virtual_h <= h)

    def zoom_fit(self, animated=True):

        if (animated):
            self.__zoom_animated(self.__zoom_fit)
        else:
            self.zoom(self.__zoom_fit)

    def zoom_100(self, animated=True):

        if (animated):
            self.__zoom_animated(self.__zoom_100)
        else:
            self.zoom(self.__zoom_100)

    def zoom_in(self, animated=True):

        if (animated):
            self.__zoom_animated(self.__zoom_level + 1)
        else:
            self.zoom(self.__zoom_level + 1)

    def zoom_out(self, animated=True):

        if (animated):
            self.__zoom_animated(self.__zoom_level - 1)
        else:
            self.zoom(self.__zoom_level - 1)

    def zoom(self, level, zoom_value=0):

        if (not self.__zoom_levels): return

        cx, cy = self.__center_pos
        cx /= self.__zoom_value
        cy /= self.__zoom_value

        if (not zoom_value):
            self.__zoom_level = max(0, min(len(self.__zoom_levels) - 1, level))
            self.__zoom_value = self.__zoom_levels[self.__zoom_level] / 100.0
        else:
            for i in range(len(self.__zoom_levels)):
                zl = self.__zoom_levels[i]
                if (zl > zoom_value):
                    self.__zoom_level = i
                    break
            #end for
            self.__zoom_value = zoom_value

        bufwidth, bufheight = self.__original_size
        self.__virtual_size = (int(bufwidth * self.__zoom_value),
                               int(bufheight * self.__zoom_value))

        #for i in range(3): gc.collect()
        self.__invalidated = True

        self.scroll_to(cx * self.__zoom_value, cy * self.__zoom_value)
        #gobject.timeout_add(0, self.scroll_to, cx * self.__zoom_value,
        #                                       cy * self.__zoom_value)

    def __zoom_animated(self, level):
        def f(params):
            from_value, to_value = params
            dv = (to_value - from_value) / 3

            if (abs(dv) > 0.01):
                self.zoom(0, from_value + dv)
                params[0] = from_value + dv
                return True
            else:
                self.zoom(0, to_value)
                return False

        level = max(0, min(len(self.__zoom_levels) - 1, level))
        from_value = self.__zoom_value
        to_value = self.__zoom_levels[level] / 100.0

        self.animate(25, f, [from_value, to_value])
        self.__zoom_level = level

    def _render(self, high_quality=False):
        """
        Renders the visible area of the image.
        """

        screen = self.get_screen()

        offx, offy = self.__get_offset()
        width, height = self.__visible_size
        vwidth, vheight = self.__virtual_size

        # find the area that can be copied (reused) and doesn't have to
        # be rendered again, and find the areas which have to be rendered
        prev_x, prev_y = self.__previous_offset
        dx = offx - prev_x
        dy = offy - prev_y

        areas = []
        if (dx >= 0):
            src_x = dx
            dest_x = 0
            src_w = width - dx
            areas.append((width - dx, 0, dx, height))
        elif (dx < 0):
            src_x = 0
            dest_x = -dx
            src_w = width + dx
            areas.append((0, 0, -dx, height))
        if (dy >= 0):
            src_y = dy
            dest_y = 0
            src_h = height - dy
            areas.append((0, height - dy, width, dy))
        elif (dy < 0):
            src_y = 0
            dest_y = -dy
            src_h = height + dy
            areas.append((0, 0, width, -dy))

        #self._render_clear()

        if (self.__invalidated):
            # draw full area
            areas = [(0, 0, width, height)]
            self.__invalidated = False

            if (vwidth + 1 < width):
                bw = (width - vwidth) / 2
                self.__offscreen.fill_area(0, 0, bw, height, self.__bg_color)
                self.__offscreen.fill_area(width - bw - 1, 0, bw + 1, height,
                                           self.__bg_color)

            if (vheight + 1 < height):
                bh = (height - vheight) / 2
                self.__offscreen.fill_area(0, 0, width, bh, self.__bg_color)
                self.__offscreen.fill_area(0, height - bh - 1, width, bh + 1,
                                           self.__bg_color)

        else:
            # copy on the server-side (this is our simple trick for
            # fast scrolling!)
            self.__offscreen.move_area(src_x, src_y, src_w, src_h, -dx, -dy)

        # render borders
        for rx, ry, rw, rh in areas:
            self.__render_area(rx, ry, rw, rh, high_quality)

        # copy to screen
        if (self.may_render()):
            if (self.__is_new_image):
                self.__is_new_image = False
                self.fx_slide_in()
            #else:
            #    screen.copy_pixmap(self.__offscreen, x, y, x, y, width, height)

            if (not high_quality):
                if (self.__hi_quality_timer):
                    gobject.source_remove(self.__hi_quality_timer)

                self.__hi_quality_timer = \
                  gobject.timeout_add(1000, self.__hi_quality_render)
            else:
                self.__hi_quality_timer = None

        self.__previous_offset = (offx, offy)

        #self.render()
        if (self.may_render()):
            x, y = self.get_screen_pos()
            self.render_at(TEMPORARY_PIXMAP, x, y)
            for o in self.__overlays:
                o(TEMPORARY_PIXMAP, x, y, width, height)
            screen.copy_pixmap(TEMPORARY_PIXMAP, x, y, x, y, width, height)

    def __render_area(self, rx, ry, rw, rh, high_quality=False):
        """
        Renders the given area. The coordinates are given in
        screen coordinates.
        """

        if (rw <= 0 or rh <= 0): return
        rx = max(0, rx)
        ry = max(0, ry)
        #print "RENDER", rx, ry, rw, rh

        offx, offy = self.__get_offset()
        width, height = self.__visible_size
        vwidth, vheight = self.__virtual_size

        offx += rx
        offy += ry

        destwidth = int(min(rw, vwidth - offx))
        destheight = int(min(rh, vheight - offy))

        # determine interpolation type
        if (high_quality): interp = gtk.gdk.INTERP_BILINEAR
        else: interp = gtk.gdk.INTERP_NEAREST

        pbuf = self.__pixbuf  # self.__loader.get_pixbuf()
        if (not pbuf): return

        destpbuf = self.__buffer.subpixbuf(rx, ry, destwidth, destheight)

        if (abs(self.__zoom_value - 1.0) < 0.0001):
            # for zoom = 100% we simply copy the area
            pbuf.copy_area(offx, offy, destwidth, destheight, destpbuf, 0, 0)
        else:
            pbuf.scale(destpbuf, 0, 0, destwidth, destheight, -offx, -offy,
                       self.__zoom_value, self.__zoom_value, interp)

        # copy from client-side pixmap to server-side pixmap
        # I wish we could avoid this time-consuming step... (server-side
        # scaling would be nice!)

        # maybe we have to center the image?
        if (vwidth < width or vheight < height):
            if (vwidth < width): rx += (width - vwidth) / 2
            if (vheight < height): ry += (height - vheight) / 2

        self.__offscreen.draw_pixbuf(destpbuf, rx, ry)

    def load(self, f):
        """
        Loads the given image file.
        """

        if (f != self.__current_file):
            if (self.__hi_quality_timer):
                gobject.source_remove(self.__hi_quality_timer)

            self.__current_file = f
            self.__load_img(f, self.__use_pixbuf)

    def __load_img(self, f, cb, *args):
        """
        Loads the image.
        """
        def on_data(d, amount, total):

            if (d):
                self.__loader.write(d)
            else:
                try:
                    self.__loader.close()
                    pixbuf = self.__finish_loading()
                    cb(pixbuf, *args)
                except:
                    pass

        self.__currently_loading = f
        self.__is_loading = True
        self.__loading_aborted = False
        try:
            self.__loader.close()
        except:
            pass
        self.__loader = gtk.gdk.PixbufLoader()
        self.__loader.connect("size-prepared", self.__on_check_size)

        dl = Downloader(f.resource, on_data)

    def __finish_loading(self):
        """
        Cleans up and displays the image.
        """

        #print "REF", self.__loader.__grefcount__

        pbuf = self.__loader.get_pixbuf()

        # properly support images with alpha channel
        if (pbuf.get_has_alpha()):
            pbuf2 = pbuf.composite_color_simple(pbuf.get_width(),
                                                pbuf.get_height(),
                                                gtk.gdk.INTERP_NEAREST, 0xff,
                                                32, 0, 0)
            del pbuf
            pbuf = pbuf2
            del pbuf2
        #end if

        # automatically rotate images in portrait format
        w, h = self.get_size()
        if (w > h and pbuf.get_width() < pbuf.get_height()
                or w < h and pbuf.get_width() > pbuf.get_height()):
            try:
                # rotating is only supported by pygtk >= 2.10
                pixbuf = pbuf.rotate_simple(gtk.gdk.PIXBUF_ROTATE_CLOCKWISE)
            except:
                pixbuf = pbuf
        else:
            pixbuf = pbuf

        del pbuf

        return pixbuf

        # collect three generations of garbage
        #for i in range(3): gc.collect()

    def __use_pixbuf(self, pbuf):

        self.__pixbuf = pbuf
        w, h = self.__pixbuf.get_width(), self.__pixbuf.get_height()
        self.__original_size = (w, h)

        self.__is_new_image = True
        self.__scale_to_fit()

        del pbuf

    def __scale_to_fit(self):
        """
        Scales the image up or down to fit the screen.
        """

        orig_width, orig_height = self.__original_size
        w, h = orig_width, orig_height
        width, height = self.__visible_size
        fit_factor = 1
        fit_factor2 = 1

        if (w != width or h != height):
            factor1 = width / float(orig_width)
            factor2 = height / float(orig_height)
            fit_factor = min(factor1, factor2)
            fit_factor2 = max(factor1, factor2)

        fitting = int(fit_factor * 100)
        fitting2 = int(fit_factor2 * 100)

        self.__zoom_levels = _ZOOM_LEVELS[:]
        if (not fitting in self.__zoom_levels):
            self.__zoom_levels.append(fitting)
        if (not fitting2 in self.__zoom_levels):
            self.__zoom_levels.append(fitting2)
        self.__zoom_levels.sort()

        self.__zoom_fit = self.__zoom_levels.index(fitting)
        self.__zoom_100 = self.__zoom_levels.index(100)
        self.zoom_fit(animated=False)

    def __on_check_size(self, loader, width, height):
        """
        Resizes the image while loading if it's too large for
        the little device.
        """

        #print "%d megapixels" % ((width * height) / 1000000),
        # TODO: this is hardcoded for now. value could be made dependent
        #       on available RAM, or so
        factor = 1
        if (width > 1000 or height > 1000):
            factor1 = 1000 / float(width)
            factor2 = 1000 / float(height)
            factor = min(factor1, factor2)

        if (width * height > 8000000):
            logging.info(
                "aborted loading image because resolution is"
                " too high: %dx%d, %0.2f megapixels", width, height,
                width * height / 1000000.0)
            self.__loading_aborted = True

        if (factor != 1):
            loader.set_size(int(width * factor), int(height * factor))

    def slide_from_left(self):

        self.__slide_from_right = False

    def slide_from_right(self):

        self.__slide_from_right = True

    def fx_slide_in(self, wait=True):

        x, y = self.get_screen_pos()
        w, h = self.get_size()
        screen = self.get_screen()

        if (self.__slide_from_right):
            self.fx_slide_horizontal(self.__offscreen, 0, 0, w, h,
                                     self.SLIDE_LEFT)
        else:
            self.fx_slide_horizontal(self.__offscreen, 0, 0, w, h,
                                     self.SLIDE_RIGHT)
예제 #16
0
class RadioScale(Widget):

    EVENT_TUNED = "event-tuned"
    

    def __init__(self):
        
        self.__range = (0.0, 1.0)
        self.__scala_pmap = None
        self.__needle_pos = 0

        # whether the user is currently dragging
        self.__is_dragging = False
        
        
        Widget.__init__(self)
        self.connect_button_pressed(self.__on_button_press)
        self.connect_button_released(self.__on_button_release)
        self.connect_pointer_moved(self.__on_motion)        
        
        
        
    def _reload(self):
    
        self.__prepare_scala()
        
        
    def render_this(self):
    
        x, y = self.get_screen_pos()
        w, h = self.get_size()
        screen = self.get_screen()
        
        if (self.__scala_pmap):
            TEMPORARY_PIXMAP.draw_pixmap(self.__scala_pmap, 0, 0)
            TEMPORARY_PIXMAP.draw_pixbuf(theme.fmradio_tuner_needle,
                                         0, self.__needle_pos - 24)
            screen.copy_pixmap(TEMPORARY_PIXMAP, 0, 0, x, y, w, h)
        
        
    def __prepare_scala(self):
    
        w, h = self.get_size()
        #h -= 20
        self.__scala_pmap = Pixmap(None, w, h)
        self.__scala_pmap.fill_area(0, 0, w, h, theme.color_mb_background)
        
        a, b = self.__range
        step_size = h / (b - a)
        
        i = 0
        j = a
        while (j < b + 0.1):
            y = int(i + 0.5)   # because floor(x + 0.5) = round(x)
            if (int(j - 0.4) != int(j)):
                self.__scala_pmap.draw_line(0, y, 55, y, "#666666")
                if (int(j) % 5 == 0):
                    self.__scala_pmap.draw_text("%3.1f" % (j + 0.5),
                                                theme.font_mb_micro, 
                                                2, y, "#666666")
            else:
                self.__scala_pmap.draw_line(40, y, 55, y, "#666666")
            i += step_size / 2
            j += 0.5
        
        
    def set_range(self, a, b):
    
        self.__range = (a, b)
        self.__prepare_scala()
        self.render()
        
    
    def tune(self, freq):

        w, h = self.get_size()
        #h -= 20
        a, b = self.__range
        
        percents = (freq - a) / (b - a)
        self.__needle_pos = int(percents * h)
        self.render()
        
        
    def __on_button_press(self, px, py):
    
        self.__is_dragging = True
        self.__on_motion(px, py)


    def __on_button_release(self, px, py):
                   
        self.__is_dragging = False



    def __on_motion(self, px, py):
            
        if (self.__is_dragging):
            w, h = self.get_size()
            #h -= 20
            a, b = self.__range
            
            freq = a + ((b - a) * (py / float(h)))
            freq = max(a, min(b, freq))
            freq = int(freq * 10) / 10.0
            print freq
            self.tune(freq)
            self.send_event(self.EVENT_TUNED, freq)
        #end if
        
        
    def connect_tuned(self, cb, *args):
    
        self._connect(self.EVENT_TUNED, cb, *args)
예제 #17
0
class Toolbar(Widget):
    def __init__(self):

        # offscreen buffer
        self.__buffer = None

        self.__bg_pmap = None

        self.__current_set = []

        Widget.__init__(self)
        self.__box = Box()
        self.__box.set_spacing(2)
        self.__box.set_halign(self.__box.HALIGN_CENTER)
        self.__box.set_valign(self.__box.VALIGN_CENTER)
        self.add(self.__box)

    def _reload(self):

        self.__bg_pmap = None
        w, h = self.get_size()
        if (w and h):
            self.set_size(w, h)

    def set_size(self, w, h):

        if (w < h):
            edges = Pixmap.LEFT
        else:
            edges = Pixmap.TOP

        if (not self.__bg_pmap or (w, h) != self.get_size()):
            self.__buffer = None
            self.__bg_pmap = Pixmap(None, w, h)
            self.__bg_pmap.fill_area(0, 0, w, h, theme.color_mb_background)
            self.__bg_pmap.draw_frame(theme.mb_panel, 0, 0, w, h, True, edges)

            self.__box.set_size(w, h)

        Widget.set_size(self, w, h)

    def render_this(self):

        x, y = self.get_screen_pos()
        w, h = self.get_size()
        screen = self.get_screen()

        if (w < h):
            self.__box.set_orientation(Box.VERTICAL)
        else:
            self.__box.set_orientation(Box.HORIZONTAL)

        if (self.__bg_pmap):
            screen.draw_pixmap(self.__bg_pmap, x, y)

    def set_toolbar(self, *tbset):
        """
        Sets the given toolbar on this panel.
        """

        if (tuple(tbset) == tuple(self.__current_set)):
            return

        self.__current_set = tbset

        for c in self.__box.get_children():
            self.__box.remove(c)

        for c in tbset:
            self.__box.add(c, True)
            c.set_visible(True)

        if (not self.__buffer):
            w, h = self.get_size()
            if (w > 0 and h > 0):
                self.__buffer = Pixmap(None, w, h)

        if (self.__buffer):
            self.render_buffered(self.__buffer)
예제 #18
0
class Window(Widget):

    TYPE_TOPLEVEL = 0
    TYPE_SUBWINDOW = 1
    TYPE_DIALOG = 2

    RETURN_OK = 0
    RETURN_CANCEL = 1
    RETURN_YES = 2
    RETURN_NO = 3

    EVENT_CLOSED = "event-closed"

    # one window may be exclusive at a time. input in other windows will be
    # ignored and the exclusive window gets hidden in such case (e.g. for
    # simulating the Maemo5 dialog paradigma on Maemo4)
    __exclusive_window = [None]

    # window stack for systems which don't support stackable windows
    __window_stack = []

    def __init__(self, wtype):

        self.__wtype = wtype
        self.__flags = 0

        # widget of the windows contents
        self.__contents = []

        # window menu
        if (platforms.MAEMO5):
            self.__menu = hildon.AppMenu()
        elif (platforms.MAEMO4):
            self.__menu = gtk.Menu()
        else:
            self.__menu = gtk.Menu()

        # table: name -> menu_item
        self.__menu_items = {}

        self.__size = (0, 0)
        self.__has_size_set = False
        self.__is_button_pressed = False
        self.__screen = None

        # whether this window should be stackable
        self.__is_stackable = False

        # timeout handler for handling the window configure events
        self.__configure_event_handler = None

        Widget.__init__(self)

        if (wtype == self.TYPE_TOPLEVEL):
            self.__is_stackable = True
            if (platforms.MAEMO5):
                self.__window = hildon.StackableWindow()
                self.__window.set_app_menu(self.__menu)
                # stacking is handled by Maemo5
                self.__is_stackable = False
            elif (platforms.MAEMO4):
                self.__window = hildon.Window()
                #self.__window.set_menu(self.__menu)
                self.__window.fullscreen()
            elif (platforms.MEEGO_WETAB):
                self.__window = gtk.Window(gtk.WINDOW_TOPLEVEL)
                self.__window.set_decorated(False)
                self.__window.maximize()
            elif (platforms.MEEGO_NETBOOK):
                self.__window = gtk.Window(gtk.WINDOW_TOPLEVEL)
                self.__window.set_decorated(False)
                self.__window.maximize()
                #self.__window.fullscreen()
                #self.__window.set_size_request(gtk.gdk.screen_width(),
                #                               gtk.gdk.screen_height())
            else:
                self.__window = gtk.Window(gtk.WINDOW_TOPLEVEL)

        elif (wtype == self.TYPE_SUBWINDOW):
            self.__is_stackable = True
            if (platforms.MAEMO5):
                self.__window = hildon.StackableWindow()
                self.__window.set_app_menu(self.__menu)
                # stacking is handled by Maemo5
                self.__is_stackable = False
            elif (platforms.MAEMO4):
                self.__window = gtk.Window()
                #self.__window.set_decorated(False)
                self.__window.fullscreen()
                # hide some ugly separator :)
                #self.__window.vbox.get_children()[0].hide()
            elif (platforms.MEEGO_WETAB):
                self.__window = gtk.Window()
                self.__window.maximize()
                self.__window.set_decorated(False)
            elif (platforms.MEEGO_NETBOOK):
                self.__window = gtk.Dialog()
                self.__window.set_decorated(False)
                self.__window.maximize()
                #self.__window.set_size_request(gtk.gdk.screen_width(),
                #                               gtk.gdk.screen_height())
                # hide some ugly separator :)
                self.__window.vbox.get_children()[0].hide()
            else:
                self.__window = gtk.Window(gtk.WINDOW_TOPLEVEL)
                # hide some ugly separator :)
                #self.__window.vbox.get_children()[0].hide()

        elif (wtype == self.TYPE_DIALOG):
            if (platforms.MAEMO5):
                self.__window = gtk.Dialog()
            elif (platforms.MAEMO4 or platforms.MEEGO_NETBOOK):
                self.__window = gtk.Dialog()
                # hide some ugly separator :)
                self.__window.vbox.get_children()[0].hide()
            else:
                self.__window = gtk.Dialog()
                # hide some ugly separator :)
                self.__window.vbox.get_children()[0].hide()

        # title bar on some platforms
        if (not platforms.MAEMO5 and wtype != self.TYPE_DIALOG):
            self.__title_bar = TitleBar()
            self.__title_bar.connect_switch(lambda: self.__window.iconify())
            self.__title_bar.connect_menu(lambda: self.show_menu())
            self.__title_bar.connect_close(
                lambda: self.emit_event(self.EVENT_CLOSED))
            if (wtype == self.TYPE_SUBWINDOW):
                self.__title_bar.set_mode(TitleBar.MODE_SUBWINDOW)

            Widget.add(self, self.__title_bar)

        else:
            self.__title_bar = None

        self.__window.set_title(" ")
        self.__window.set_default_size(480, 800)  #800, 480)
        self.__window.set_app_paintable(True)
        self.__window.set_double_buffered(False)

        self.__window.connect("configure-event", self.__on_configure)
        self.__window.connect("expose-event", self.__on_expose)
        self.__window.connect("button-press-event", self.__on_button_pressed)
        self.__window.connect("button-release-event",
                              self.__on_button_released)
        self.__window.connect("motion-notify-event", self.__on_pointer_moved)
        self.__window.connect("key-press-event", self.__on_key_pressed)
        self.__window.connect("key-release-event", self.__on_key_released)
        self.__window.connect("delete-event", self.__on_close_window)

        self.__window.set_events(gtk.gdk.BUTTON_PRESS_MASK
                                 | gtk.gdk.BUTTON_RELEASE_MASK
                                 | gtk.gdk.POINTER_MOTION_MASK
                                 | gtk.gdk.POINTER_MOTION_HINT_MASK
                                 | gtk.gdk.KEY_PRESS_MASK
                                 | gtk.gdk.KEY_RELEASE_MASK)

        self.__window.realize()

        if (platforms.MAEMO5):
            if (wtype in [self.TYPE_TOPLEVEL, self.TYPE_SUBWINDOW]):
                pass  #self.__set_portrait_property("_HILDON_PORTRAIT_MODE_SUPPORT", 1)
            else:
                self.__set_portrait_property("_HILDON_PORTRAIT_MODE_SUPPORT",
                                             1)

        self.__layout = gtk.Fixed()
        self.__layout.show()
        try:
            self.__window.vbox.add(self.__layout)
        except:
            self.__window.add(self.__layout)

        # video screen
        self.__vidscreen = gtk.DrawingArea()
        self.__vidscreen.set_double_buffered(False)

        self.__vidscreen.modify_bg(gtk.STATE_NORMAL,
                                   gtk.gdk.color_parse("#000000"))
        self.__vidscreen.set_events(gtk.gdk.BUTTON_PRESS_MASK
                                    | gtk.gdk.BUTTON_RELEASE_MASK
                                    | gtk.gdk.POINTER_MOTION_MASK
                                    | gtk.gdk.KEY_PRESS_MASK
                                    | gtk.gdk.KEY_RELEASE_MASK)
        self.__layout.put(self.__vidscreen, 0, 0)

        self.__update_window_background()

    def connect_closed(self, cb, *args):

        self._connect(self.EVENT_CLOSED, cb, *args)

    def get_window(self):

        return self

    def set_flags(self, flags):
        """
        Sets the window flags.
        @since: 2010.02.12
        
        @param flags: window flags
        """

        changes = []
        for flag in [
                windowflags.FULLSCREEN, windowflags.ASR, windowflags.PORTRAIT,
                windowflags.CATCH_VOLUME_KEYS, windowflags.BUSY,
                windowflags.FRAMELESS, windowflags.EXCLUSIVE
        ]:
            if (flags & flag != self.__flags & flag):
                changes.append((flag, flags & flag))
        #end for
        self.__flags = flags

        for flag, value in changes:
            self._update_flag(flag, value)

    def set_flag(self, flag, value):
        """
        Sets or unsets a single window flag.
        @since: 2010.02.12
        
        @param flag: the flag to change
        @param value: whether to set (C{True}) or unset (C{False})
        """

        new_flags = self.__flags
        if (value):
            new_flags |= flag
        elif (self.__flags & flag):
            new_flags -= flag

        self.set_flags(new_flags)

    def get_flag(self, flag):
        """
        Returns the current value of a window flag.
        @since: 2010.10.16
        
        @param flag: the flag
        """

        return (self.__flags & flag)

    """
    def get_size(self):
    
        w, h = Widget.get_size(self)
        return (696, 396)


    def get_screen_pos(self):
    
        return (12, 0)
    """

    def add(self, w):
        """
        Adds a widget to this window. If you don't override L{render_this}, all
        widgets occupy the whole window area.
        """

        Widget.add(self, w)
        if (not w in self.__contents):
            self.__contents.append(w)

    def __check_exclusive(self):
        """
        Checks for the presence of an exclusive window and hides it, if there
        is one. This allows us to hide dialogs by clicking outside on platforms
        where the window manager doesn't provide this feature already.
        """

        if (self.__exclusive_window[0] and self.__exclusive_window[0] != self):
            self.__exclusive_window[0].set_visible(False)
            self.__exclusive_window[0] = None
            return False
        else:
            return True

    def _reload(self):

        self.__update_window_background()

    def __update_window_background(self):

        #self.__window.modify_bg(gtk.STATE_NORMAL,
        #                  gtk.gdk.color_parse(str(theme.color_mb_background)))
        pass

    def __on_configure(self, src, ev):

        w = ev.width
        h = ev.height
        if ((w, h) != self.__size):
            self.__size = (w, h)
            if (self.__configure_event_handler):
                gobject.source_remove(self.__configure_event_handler)
            else:
                # freeze rendering at the first of possibly several configure events
                # in a row
                self.set_frozen(True)

            self.__configure_event_handler = gobject.timeout_add(
                100, self.__handle_configure_event)
        #end if

    def __handle_configure_event(self):
        """
        Handles the last window configure event in a row. Maemo5 sometimes
        shoots several in a row and we should only react on the last one.
        """

        # thaw rendering at the last of possibly several configure events in
        # a row
        self.set_frozen(False)

        self.__configure_event_handler = None
        w, h = self.__window.get_size()
        self.__screen = Pixmap(self.__window.window)
        self.__screen.fill_area(0, 0, w, h, theme.color_mb_background)
        self.set_screen(self.__screen)

        self.set_size(w, h)
        self.render()

    def __on_expose(self, src, ev):

        if (self.__screen):
            x, y, w, h = ev.area
            self.__screen.restore(x, y, w, h)

    def __on_close_window(self, src, ev):

        self.emit_event(self.EVENT_CLOSED)
        return True

    def __on_button_pressed(self, src, ev):

        if (not self.__check_exclusive()):
            return

        if (ev.button == 1):
            px, py = src.get_pointer()
            self._handle_event(self.EVENT_BUTTON_PRESS, px, py)
            self.__is_button_pressed = True

        return True

    def __on_button_released(self, src, ev):

        if (ev.button == 3):
            if (self.__menu_items):
                self.__menu.popup(None, None, None, ev.button, ev.get_time(),
                                  None)

        elif (ev.button == 1):
            if (self.__is_button_pressed):
                px, py = src.get_pointer()
                self._handle_event(self.EVENT_BUTTON_RELEASE, px, py)
                self.__is_button_pressed = False

        return True

    def __on_pointer_moved(self, src, ev):

        if (self.__is_button_pressed):
            px, py = src.get_pointer()
            self._handle_event(self.EVENT_MOTION, px, py)
        return True

    def __on_key_pressed(self, src, ev):

        if (not self.__check_exclusive()):
            return

        keyval = ev.keyval
        c = gtk.gdk.keyval_to_unicode(keyval)
        if (c > 31):
            key = unichr(c)
        else:
            key = gtk.gdk.keyval_name(keyval)

        self.emit_event(self.EVENT_KEY_PRESSED, key)

        # kill queued events
        if (key in ["Up", "Down", "Left", "Right"]):
            while (True):
                e = gtk.gdk.event_get()
                if (not e): break

        return False

    def __on_key_released(self, src, ev):

        keyval = ev.keyval
        c = gtk.gdk.keyval_to_unicode(keyval)
        if (c > 31):
            key = unichr(c)
        else:
            key = gtk.gdk.keyval_name(keyval)

        self.emit_event(self.EVENT_KEY_RELEASED, key)

        return False

    def __set_portrait_property(self, prop, value):

        self.__window.window.property_change(prop, "CARDINAL", 32,
                                             gtk.gdk.PROP_MODE_REPLACE,
                                             [value])

    def __unset_portrait_property(self, prop):

        self.__window.window.property_delete(prop)

    def _update_flag(self, flag, value):

        if (flag == windowflags.FULLSCREEN):
            self.__vidscreen.set_size_request(-1, -1)
            now = time.time()
            while (gtk.events_pending() and time.time() < now + 1):
                gtk.main_iteration(False)

            if (platforms.MAEMO5):
                if (value):
                    self.__window.fullscreen()
                else:
                    self.__window.unfullscreen()

            elif (platforms.MAEMO4):
                self.__title_bar.set_visible(not value)
                self.render()

            else:
                if (self.__title_bar):
                    self.__title_bar.set_visible(not value)
                    if (value):
                        self.__window.fullscreen()
                    else:
                        self.__window.unfullscreen()
                    #self.render()

        elif (flag == windowflags.ASR):
            if (platforms.MAEMO5):
                if (value):
                    self.__set_portrait_property(
                        "_HILDON_PORTRAIT_MODE_SUPPORT", 1)
                    #self.__set_portrait_property("_HILDON_PORTRAIT_MODE_REQUEST", 0)
                else:
                    self.__unset_portrait_property(
                        "_HILDON_PORTRAIT_MODE_SUPPORT")

        elif (flag == windowflags.PORTRAIT):
            if (platforms.MAEMO5):
                #self.__set_portrait_property("_HILDON_PORTRAIT_MODE_SUPPORT", 1)
                if (value):
                    self.__set_portrait_property(
                        "_HILDON_PORTRAIT_MODE_REQUEST", 1)
                else:
                    self.__unset_portrait_property(
                        "_HILDON_PORTRAIT_MODE_REQUEST")
            elif (platforms.MAEMO4):
                from utils import xrandr
                if (value):
                    xrandr.set_orientation(xrandr.RIGHT)
                else:
                    xrandr.set_orientation(xrandr.NORMAL)

        elif (flag == windowflags.BUSY):
            if (platforms.MAEMO5):
                hildon.hildon_gtk_window_set_progress_indicator(
                    self.__window, value and 1 or 0)

        elif (flag == windowflags.CATCH_VOLUME_KEYS):
            if (platforms.MAEMO5):
                self.__window.window.property_change("_HILDON_ZOOM_KEY_ATOM",
                                                     "XA_INTEGER", 32,
                                                     gtk.gdk.PROP_MODE_REPLACE,
                                                     [value and 1 or 0])

        elif (flag == windowflags.FRAMELESS):
            self.__title_bar.set_visible(not value)

        elif (flag == windowflags.EXCLUSIVE):
            self.__exclusive_window[0] = self

    def _get_window_impl(self):

        return self.__window

    def _visibility_changed(self):

        if (self.is_visible()):
            if (platforms.MAEMO5):
                if (self.__wtype != self.TYPE_TOPLEVEL):
                    if (self.__has_size_set):
                        w, h = self.get_size()
                        self.__window.resize(gtk.gdk.screen_width(), h)
                    else:
                        self.__window.resize(gtk.gdk.screen_width(),
                                             gtk.gdk.screen_height() - 120)

            elif (platforms.MAEMO4):
                if (self.__wtype != self.TYPE_TOPLEVEL
                        and self.__has_size_set):
                    w, h = self.__window.get_size()
                    self.__window.move(0, 480 - max(h, 400))

            #endif

            self.render()
            self.__window.show()
            if (self.__is_stackable
                    and not self.__window in self.__window_stack):
                if (self.__window_stack):
                    x, y = self.__window_stack[-1].get_position()
                    self.__window.move(x, y)
                    self.__window_stack[-1].hide()
                self.__window_stack.append(self.__window)
            #self.emit_event(self.EVENT_RAISED)

        else:
            #self.emit_event(self.EVENT_HID)
            if (self.__is_stackable and self.__window in self.__window_stack):
                self.__window_stack.pop(-1)
                if (self.__window_stack):
                    x, y = self.__window.get_position()
                    self.__window_stack[-1].move(x, y)
                    self.__window_stack[-1].show()
            self.__window.hide()

    def set_parent_window(self, parent):

        if (not platforms.MEEGO_NETBOOK):
            self.__window.set_transient_for(parent._get_window_impl())

    def destroy(self):

        self.__window.destroy()
        if (self.__exclusive_window[0] == self):
            self.__exclusive_window[0] = None

    def has_focus(self):

        return self.__window.has_focus

    def set_window_size(self, w, h):

        if (self.__title_bar):
            h += 57
        self.__window.resize(w, h)
        self.__has_size_set = True

    def render_this(self):

        w, h = self.get_size()
        if (self.__title_bar and self.__title_bar.is_visible()):
            self.__title_bar.set_geometry(0, 0, w, 57)
            offset = 57
        else:
            offset = 0
        for c in self.__contents:
            c.set_geometry(0, offset, w, h - offset)

    def set_title(self, title):

        self.__window.set_title(title)
        if (self.__title_bar):
            self.__title_bar.set_title(title)

    def show_menu(self):
        def positioner(menu):
            x, y = self.__window.window.get_position()
            return (x + 80, y + 57, False)

        if (self.__menu_items):
            self.__menu.popup(None, None, positioner, 1, 0)

    def set_menu_item(self, name, label, visible, cb):

        if (not name in self.__menu_items):
            if (platforms.MAEMO5):
                item = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
                item.set_label(label)
            else:
                item = gtk.MenuItem(label)
            self.__menu_items[name] = item
            self.__menu.append(item)
            if (platforms.MAEMO5):
                item.connect("clicked", lambda src, cb: cb(), cb)
            else:
                item.connect("activate", lambda src, cb: cb(), cb)

        else:
            item = self.__menu_items[name]

        if (visible):
            item.show()
        else:
            item.hide()

    def set_menu_choice(self, name, icons_labels, selected, visible, cb):

        if (not name in self.__menu_items):
            group = None
            items = []
            cnt = 0
            for icon, label in icons_labels:
                if (platforms.MAEMO5):
                    item = hildon.GtkRadioButton(gtk.HILDON_SIZE_AUTO, group)
                    item.set_mode(False)
                else:
                    item = gtk.RadioMenuItem(group, label)

                if (icon):
                    if (platforms.MAEMO5):
                        img = gtk.Image()
                        img.set_from_pixbuf(icon)
                        item.set_image(img)

                elif (label):
                    if (platforms.MAEMO5):
                        item.set_label(label)

                if (not group): group = item
                items.append(item)
                if (platforms.MAEMO5):
                    self.__menu.add_filter(item)
                    item.connect("clicked", lambda src, cb, cnt: cb(cnt), cb,
                                 cnt)

                else:
                    self.__menu.append(item)
                    item.connect("activate", lambda src, cb, cnt: cb(cnt), cb,
                                 cnt)

                cnt += 1
            #end for
            self.__menu_items[name] = items

        else:
            items = self.__menu_items[name]

        for item in items:
            if (visible):
                item.show()
            else:
                item.hide()
        #end for

        items[selected].set_active(True)

    def put_widget(self, widget, x, y, w, h):

        if (not widget in self.__layout.get_children()):
            self.__layout.put(widget, x, y)
        else:
            self.__layout.move(widget, x, y)
        widget.set_size_request(w, h)

    def show_video_overlay(self, x, y, w, h):

        self.__vidscreen.hide()
        self.__layout.move(self.__vidscreen, x, y)
        self.__vidscreen.set_size_request(w, h)
        gobject.idle_add(self.__vidscreen.show)

        return self.__vidscreen.window.xid

    def hide_video_overlay(self):

        #self.__vidscreen.hide()
        gobject.idle_add(self.__vidscreen.hide)

    def run(self):

        self.set_visible(True)
        while (self.is_visible()):
            gtk.main_iteration(True)
        #end while

        #if (self.__exclusive_window[0] == self):
        #    self.__exclusive_window[0] = None
        gobject.timeout_add(0, self.destroy)
예제 #19
0
class GridView(ItemView):
    def __init__(self):

        # offscreen buffer
        self.__buffer = None

        # background buffer
        self.__background = None

        # color of the background
        self.__bg_color = theme.color_mb_background

        # offset value of the currently visible area
        self.__offset = 0

        # offset values of the different sets
        # table: set_id -> offset
        self.__offsets = {}

        # columns per row values of the different sets
        # table: set id -> number
        self.__columns_per_row = {}

        # the currently floating item
        self.__floating_item = -1

        # position of the floating item on screen
        self.__floating_position = (0, 0)

        # list of overlay renderers
        self.__overlay_renderers = []

        # items per row
        self.__items_per_row = 1

        self.__is_invalidated = True

        ItemView.__init__(self)

    def set_size(self, w, h):

        old_w, old_h = self.get_size()
        ItemView.set_size(self, w, h)
        if ((old_w, old_h) != (w, h)):
            self.__init_buffer()
            self.set_items_per_row(self.__items_per_row)

    def append_item(self, item):

        ItemView.append_item(self, item)

        w, h = self.get_size()
        item_w = w / self.__items_per_row
        nil, item_h = item.get_size()
        item.set_size(item_w, item_h)

    def set_items_per_row(self, n):
        """
        Sets the number of items per row.
        
        @param n: number of columns
        """

        self.__items_per_row = max(1, n)

        if (self.get_items()):
            w, h = self.get_size()
            item_w = w / self.__items_per_row
            nil, item_h = self.get_item(0).get_size()
            for i in self.get_items():
                i.set_size(item_w, item_h)
            #end for
        #end if

    def get_items_per_row(self):

        return self.__items_per_row

    def set_background(self, color):
        """
        Sets the background color of the view.
        
        @param color: background color
        """

        self.__bg_color = color

        if (self.__background):
            w, h = self.__background.get_size()
            self.__background.fill_area(0, 0, w, h, color)
            self.invalidate()

    def _reload(self):

        self.__bg_color.reload()
        self.set_background(self.__bg_color)
        self.invalidate()
        for item in self.get_items():
            item._invalidate_cached_pixmap()

    def invalidate(self):
        """
        Invalidates this view. This causes the view to be redrawn completely
        the next time it gets rendered.
        If you just want to update particular items, then L{invalidate_item} is
        a better choice.
        """

        self.__is_invalidated = True

    def invalidate_item(self, idx):
        """
        Invalidates the given item. This causes the item to be redrawn on screen
        immediately.
        
        @param idx: index number of the item to invalidate
        """

        self.__render_item(idx, True)

    def switch_item_set(self, set_id):

        prev_set_id = self.get_set_id()
        self.__offsets[prev_set_id] = self.__offset
        self.__columns_per_row[prev_set_id] = self.__items_per_row

        ItemView.switch_item_set(self, set_id)
        #item_x, item_y = self.get_position_of_item(self.get_cursor())
        self.__offset = self.__offsets.get(set_id, 0)
        self.__items_per_row = self.__columns_per_row.get(set_id, 1)

    """
    def get_items_per_row(self):
        ""
        Returns the number of items per row.
        ""

        #return self.__items_per_row

        items = self.get_items()
        if (items):
            w, h = self.get_size()
            item = items[0]
            item_w, item_h = item.get_size()
            if (item_w > 0):
                return max(1, (w / item_w))
            else:
                return 1
        else:
            return 1
    """

    def get_total_size(self):
        """
        Returns the total size of this view.
        
        @return: tuple of (width, height)
        """

        items = self.get_items()
        if (items):
            item_w, item_h = items[0].get_size()
            per_row = self.get_items_per_row()
            total_w = per_row * item_w
            total_h = int(math.ceil(
                self.count_items() / float(per_row))) * item_h

        else:
            total_w = 0
            total_h = 0

        return (total_w, total_h)

    def __init_buffer(self):
        """
        Initializes the offscreen buffer.
        """

        w, h = self.get_size()

        self.__background = Pixmap(None, w, h)
        self.__background.clear_translucent()
        self.set_background(self.__bg_color)

        self.__buffer = Pixmap(None, w, h)
        self.invalidate()

        for i in range(len(self.get_items())):
            self.__render_item(i)

    def get_item_at(self, x, y):
        """
        Returns the index number of the item at the given position.
        """

        w, h = self.get_size()
        self.__offset = max(0, min(self.__offset,
                                   self.get_total_size()[1] - h))
        y += self.__offset
        items = self.get_items()
        if (items):
            item_w, item_h = items[0].get_size()
            items_per_row = self.get_items_per_row()
            idx = (y / item_h) * items_per_row + (x / item_w)
            return idx

        else:
            return -1

    def get_position_of_item(self, idx):

        items = self.get_items()
        if (items):
            item_w, item_h = items[0].get_size()
            items_per_row = self.get_items_per_row()
            item_x = (idx % items_per_row) * item_w
            item_y = (idx / items_per_row) * item_h
            return (item_x, item_y)

        else:
            return (0, 0)

    def __render_item(self, idx, to_screen=False):
        """
        Renders the given item.
        """

        w, h = self.get_size()
        item = self.get_item(idx)
        item_w, item_h = item.get_size()
        items_per_row = self.get_items_per_row()

        item_x = (idx % items_per_row) * item_w
        item_y = (idx / items_per_row) * item_h - self.__offset

        # render item if it's visible
        if (item_y + item_h >= 0 and item_y < h):
            self.__render_background(item_x, item_y, item_w, item_h)

            # render only if not floating
            if (idx != self.__floating_item):
                item.render_at(self.__buffer, item_x, item_y)
            else:
                self.__buffer.fill_area(item_x, item_y, item_w, item_h,
                                        "#66666620")
        #end if

        if (to_screen):
            x, y = self.get_screen_pos()
            screen = self.get_screen()
            if (screen):
                screen.copy_buffer(self.__buffer, item_x, item_y, x + item_x,
                                   y + item_y, item_w, item_h)

    def __render_floating_item(self):
        """
        Renders the floating item, if any.
        """

        if (self.__floating_item != -1):
            item = self.get_item(self.__floating_item)
            x, y = self.__floating_position
            item.render_at(self.__buffer, x, y)

    def __render(self, begin, end):

        items = self.get_items()

        if (items):
            w, h = self.get_size()
            item_w, item_h = items[0].get_size()
            lines = list(range(begin, end, item_h)) + [end]
            items_to_render = []

            for y in lines:
                for x in range(0, w - item_w + 1, item_w):
                    idx = self.get_item_at(x, y)
                    if (idx < len(items) and not idx in items_to_render):
                        items_to_render.append(idx)
                #end for
            #end for

            for idx in items_to_render:
                self.__render_item(idx)
        #end if

    def __render_background(self, x, y, w, h):

        if (self.__buffer and self.__background):
            self.__buffer.copy_buffer(self.__background, x, y, x, y, w, h)

    def render_this(self):

        if (not self.__buffer): return

        x, y = self.get_screen_pos()
        w, h = self.get_size()
        screen = self.get_screen()
        """
        screen.fill_area(x, y, w, h, theme.color_mb_background)
        screen.draw_centered_text("Empty",
                                  theme.font_mb_headline,
                                  x, y + h / 2 - 30, w, 30,
                                  theme.color_list_item_subtext)
        """

        # render background and items
        if (self.__is_invalidated):
            self.__is_invalidated = False
            self.__render_background(0, 0, w, h)
            self.__render(0, h)

        TEMPORARY_PIXMAP.copy_buffer(self.__buffer, 0, 0, 0, 0, w, h)

        # render floating item
        self.__render_floating_item()

        # render overlays
        for renderer in self.__overlay_renderers:
            renderer(self.__buffer)

        screen.copy_buffer(self.__buffer, 0, 0, x, y, w, h)
        self.__buffer.copy_buffer(TEMPORARY_PIXMAP, 0, 0, 0, 0, w, h)

    def add_overlay_renderer(self, renderer):

        self.__overlay_renderers.append(renderer)

    def get_offset(self):

        return self.__offset

    def move(self, dx, dy):

        if (not self.__buffer): return (dx, dy)

        w, h = self.get_size()
        total_w, total_h = self.get_total_size()
        total_h = max(h, total_h)

        if (self.__offset + dy < 0):
            dy = 0 - self.__offset

        elif (self.__offset + dy > total_h - h):
            dy = (total_h - h) - self.__offset

        self.__offset += dy

        abs_dy = abs(dy)
        if (dy < 0):
            self.__buffer.move_area(0, 0, w, h - abs_dy, 0, abs_dy)
            self.__render_background(0, 0, w, abs_dy)
            self.__render(0, abs_dy)

        elif (dy > 0):
            self.__buffer.move_area(0, abs_dy, w, h - abs_dy, 0, -dy)
            self.__render_background(0, h - abs_dy, w, abs_dy)
            self.__render(h - abs_dy, h)

        self.render()

        return (dx, dy)

    def scroll_to_item(self, pos):

        # get position of icon
        items = self.get_items()
        if (items):
            item_w, item_h = items[0].get_size()
            item_x, item_y = self.get_position_of_item(pos)

            w, h = self.get_size()

            # scroll if necessary
            if (item_y < self.__offset):
                self.move(0, item_y - self.__offset)
            elif (item_y > self.__offset + h - item_h):
                self.move(0, item_y - self.__offset - (h - item_h))

        #end if

    """
    def set_cursor(self, pos):
    
        #prev_pos = self.get_cursor()
        ItemView.set_cursor(self, pos)
        #if (prev_pos != -1):
        #    self.__render_item(prev_pos)            
        #self.__render_item(pos)
        self.scroll_to_item(pos)
        #self.render()
    """

    def float_item(self, pos, x=0, y=0):
        """
        Makes the given item floating. Only one item can be floating at a time.
        Pass C{-1} to disable floating.
        
        @param pos: position of the item to float
        @param x:   x-position of the floating item
        @param y:   y-position of the floating item
        """

        self.__floating_item = pos
        self.__floating_position = (x, y)

    def has_floating_item(self):
        """
        Returns whether there is an item currently floating.
        
        @return: whether an item is floating
        """

        return (self.__floating_item != -1)

    def get_floating_item(self):
        """
        Returns the index number of the currently floating item.

        @return: index number
        """

        return self.__floating_item

    def fx_slide_left(self):
        def fx(params):
            from_x, to_x = params
            dx = (to_x - from_x) / 4

            if (dx > 0):
                screen.move_area(x + dx, y, w - dx, h, -dx, 0)
                screen.copy_pixmap(buf, from_x, 0, x + w - dx, y, dx, h)

                params[0] = from_x + dx
                params[1] = to_x
                return True

            else:
                dx = to_x - from_x
                screen.move_area(x + dx, y, w - dx, h, -dx, 0)
                screen.copy_pixmap(buf, from_x, 0, x + w - dx, y, dx, h)

                return False

        if (not self.may_render()): return

        x, y = self.get_screen_pos()
        w, h = self.get_size()
        screen = self.get_screen()

        #if (self.__scrollbar_pmap):
        #    slider_width, nil = self.__scrollbar_pmap.get_size()
        #    slider_width /= 2
        #    w -= slider_width

        buf = self.__buffer
        buf.fill_area(0, 0, w, h, self.__bg_color)
        self.render_at(buf)

        self.animate(50, fx, [0, w])

    def fx_slide_right(self):
        def fx(params):
            from_x, to_x = params
            dx = (to_x - from_x) / 4

            if (dx > 0):
                screen.move_area(x, y, w - dx, h, dx, 0)
                screen.copy_pixmap(buf, w - from_x - dx, 0, x, y, dx, h)

                params[0] = from_x + dx
                params[1] = to_x
                return True

            else:
                dx = to_x - from_x
                screen.move_area(x, y, w - dx, h, dx, 0)
                screen.copy_pixmap(buf, w - from_x - dx, 0, x, y, dx, h)

                return False

        if (not self.may_render()): return

        x, y = self.get_screen_pos()
        w, h = self.get_size()
        screen = self.get_screen()

        #if (self.__scrollbar_pmap):
        #    slider_width, nil = self.__scrollbar_pmap.get_size()
        #    slider_width /= 2
        #    w -= slider_width

        buf = self.__buffer
        buf.fill_area(0, 0, w, h, self.__bg_color)
        self.render_at(buf)

        self.animate(50, fx, [0, w])
예제 #20
0
class SunClock(Widget):

    def __init__(self):
                
        self.__render_map_next = 0

        # not everybody wants Europe in the center
        self.__map_offset = 0
                
        self.__night = gtk.gdk.pixbuf_new_from_file(
            os.path.join(_PATH, "0-Night.jpg"))
            
        self.__sun = gtk.gdk.pixbuf_new_from_file(
            os.path.join(_PATH, "sun.png"))
            
        self.__numbers = gtk.gdk.pixbuf_new_from_file(
            os.path.join(_PATH, "numbers.png"))
    
        Widget.__init__(self)
        self.set_size(800, 400)
    
        # mask for overlaying the night
        self.__mask = gtk.gdk.Pixmap(None, 800, 400, 1)
        self.__mask_gc = self.__mask.new_gc()
    
        # buffer for holding the rendered map
        self.__map = Pixmap(None, 800, 400)
    
        # buffer for the screen
        self.__screen = Pixmap(None, 800, 400)


    def render_this(self):
    
        x, y = self.get_screen_pos()
        w, h = self.get_size()
        screen = self.get_screen()
        
        if (self.may_render()):
            if (time.time() > self.__render_map_next):
                self.__render_map()
                self.__render_map_next = time.time() + 10 * 60  # ten minutes

            self.__render_clock(screen, x, y)

         
        
    def __clear_mask(self):
    
        self.__mask_gc.set_foreground(gtk.gdk.Color(0, 0, 0, 0))
        self.__mask.draw_rectangle(self.__mask_gc, True, 0, 0, 800, 400)
        
        
        
    def __draw_mask(self, vertices):
    
        self.__mask_gc.set_foreground(gtk.gdk.Color(0, 0, 0, 1))
        
        for poly in vertices:
            self.__mask.draw_polygon(self.__mask_gc, True, poly)
        
        
    def __set_background(self, n):
    
        img = _MAPS[n]
        self.__bg.set_from_file(os.path.join(_PATH, img))
        
        
    def __get_current_map(self):

        years_since = time.localtime()[0] - 2005

        start_spring = _START_SPRING_2005 + years_since * _DELTA_SPRING
        start_summer = _START_SUMMER_2005 + years_since * _DELTA_SUMMER
        start_autumn = _START_AUTUMN_2005 + years_since * _DELTA_AUTUMN
        start_winter = _START_WINTER_2005 + years_since * _DELTA_WINTER
    
        now = datetime.datetime.utcnow()
        if (start_winter <= now < start_spring):
            return 0
        elif (start_spring <= now < start_summer):
            return 1
        elif (start_summer <= now < start_autumn):
            return 2
        elif (start_autumn <= now < start_winter):
            return 3
        else:
            # this does happen...
            return 3
        
        
    def move(self, dx, dy):
    
        self.__map_offset += dx
        self.__map_offset %= 800
        self.render()
        
        
    def __render_clock(self, screen, x, y):
    
        now = time.localtime(time.time())
        hours = now[3]
        mins = now[4]
        secs = now[5]

        screen.copy_pixmap(self.__map,
                           self.__map_offset, 0,
                           x, y,
                           800 - self.__map_offset, 400)
        if (self.__map_offset > 0):
            screen.copy_pixmap(self.__map,
                               x, y,
                               800 - self.__map_offset, 0,
                               self.__map_offset, 400)
                                  
        t = "%d:%02d" % (hours, mins)
        w = len(t) * 108
        h = 200
        x = x + 400 - w / 2
        y = y + 200 - h / 2
        for c in t:
            try:
                cx = int(c) * 108
            except:
                cx = 10 * 108
            screen.draw_subpixbuf(self.__numbers, cx, 0, x, y, 108, 200)
            x += 108
        #end for                           


    def __render_map(self):

        now = datetime.datetime.utcnow()
        year = now.year
        month = now.month
        day = now.day
        hours = now.hour
        mins = now.minute
        secs = now.second
    
        the_sun = sun.Sun()
        time_in_minutes = hours * 60.0 + (1.0 / 60.0 * mins)
                
        # compute declination of the sun
        n_days = the_sun.daysSince2000Jan0(year, month, day)
        res = the_sun.sunRADec(n_days)
        dec = res[1]
        
        # compute longitude position of the sun in degrees
        std = hours + mins / 60.0 + secs / 3600.0
        tau = the_sun.computeGHA(day, month, year, std)
               
        # (x0, y0) is the center of the map (0 deg, 0 deg) 
        k = math.pi / 180.0
        x0 = 180
        y0 = 90
        
        scale = 400 / 180.0
        
        # walk around the world and compute illumination
        vertices = []
        for i in range(-180, 180, 1):
            longitude = i + tau            
            tanlat = - math.cos(longitude * k) / math.tan(dec * k)
            arctanlat = math.atan(tanlat) / k
            y1 = y0 - int(arctanlat + 0.5)

            longitude += 1            
            tanlat = - math.cos(longitude * k) / math.tan(dec * k)
            arctanlat = math.atan(tanlat) / k
            y2 = y0 - int(arctanlat + 0.5)                        
            
            v1 = (int(scale * (x0 + i)), int(scale * y1))
            v2 = (int(scale * (x0 + i + 1)), int(scale * y2))
            if (dec > 0):
                v3 = (int(scale * (x0 + i + 1)), 400)
                v4 = (int(scale * (x0 + i)), 400)
            else:
                v3 = (int(scale * (x0 + i + 1)), 0)
                v4 = (int(scale * (x0 + i)), 0)
                
            vertices.append((v1, v2, v3, v4))
        #end for        
        
        sun_x = 400 - int(scale * tau)
        sun_y = 200 - int(scale * dec)
        if (sun_x < 0): sun_x = 800 + sun_x
        
        map_file = _MAPS[self.__get_current_map()]
        map_pbuf = gtk.gdk.pixbuf_new_from_file(os.path.join(_PATH, map_file))
                                       
        self.__clear_mask()
        self.__draw_mask(vertices)
        
        self.__map.draw_pixbuf(map_pbuf, 0, 0)
        self.__map.set_clip_mask(self.__mask)
        self.__map.draw_pixbuf(self.__night, 0, 0)
        self.__map.set_clip_mask()
        self.__map.draw_line(0, 200, 800, 200, "#0000ff")
        self.__map.draw_pixbuf(self.__sun, 
                               sun_x - self.__sun.get_width() / 2,
                               sun_y - self.__sun.get_height() / 2)
        
        del map_pbuf
        import gc; gc.collect()