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 __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 (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 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()
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 __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 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)
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 __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 _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)
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)
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)
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)
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())
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)
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)
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)
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)
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])
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()