Beispiel #1
0
class ToggleHoverButton(gtk.Button):
    def __init__(self, 
                 connect_function, argv,
                 normal_pixbuf_1 = app_theme.get_pixbuf("top_toolbar/cacel_window_above_normal.png"), 
                 hover_pixbuf_1 = app_theme.get_pixbuf("top_toolbar/cacel_window_above_hover.png"), 
                 normal_pixbuf_2 = app_theme.get_pixbuf("top_toolbar/window_above_normal.png"), 
                 hover_pixbuf_2 = app_theme.get_pixbuf("top_toolbar/window_above_hover.png")):
        gtk.Button.__init__(self)
        self.connect_function = connect_function
        self.argv = argv
        
        self.flags = True
        self.normal_pixbuf_1 = normal_pixbuf_1
        self.normal_pixbuf_2 = normal_pixbuf_2
        self.hover_pixbuf_1 = hover_pixbuf_1
        self.hover_pixbuf_2 = hover_pixbuf_2
        self.add_events(gtk.gdk.ALL_EVENTS_MASK)
        self.togglehoverbutton_event(self)
        self.cache_pixbuf = CachePixbuf()
        
    def togglehoverbutton_event(self, widget):    
        widget.connect("clicked", self.button_flags)
        widget.connect("expose-event", self.draw_button)
        widget.connect("motion-notify-event", self.show_toolbar)
        
    def draw_button(self, widget, event):
        if widget.state == gtk.STATE_NORMAL:
            if self.flags:
                image = self.normal_pixbuf_1.get_pixbuf()
            else:    
                image = self.normal_pixbuf_2.get_pixbuf()
        elif widget.state == gtk.STATE_PRELIGHT:
            if self.flags:
                image = self.hover_pixbuf_1.get_pixbuf()
            else:
                image = self.hover_pixbuf_2.get_pixbuf()
        elif widget.state == gtk.STATE_ACTIVE:
            if self.flags:
                image = self.hover_pixbuf_1.get_pixbuf()
            else:
                image = self.hover_pixbuf_2.get_pixbuf()
                
        widget.set_size_request(image.get_width(), image.get_height())        
        
        self.cache_pixbuf.scale(image, image.get_width(), image.get_height())
        cr = widget.window.cairo_create()
        draw_pixbuf(cr, self.cache_pixbuf.get_cache(), widget.allocation.x, widget.allocation.y)
        propagate_expose(widget, event)
        return True    
        
    def button_flags(self, widget):        
        self.flags = not self.flags
        
    def show_toolbar(self, widget, event):    
        pass
Beispiel #2
0
class TextPrompt(gtk.Button):
    def __init__(self, text="", max_width=135):

        # Init.
        gtk.Button.__init__(self)

        self.padding_x = 5
        self.max_width = max_width
        self.prompt_text = text
        self.font_size = 9
        self.widget_h = 26

        self.bg_left = app_theme.get_pixbuf(
            "combo/prompt_left.png").get_pixbuf()
        self.bg_middle = app_theme.get_pixbuf(
            "combo/prompt_middle.png").get_pixbuf()
        self.bg_right = app_theme.get_pixbuf(
            "combo/prompt_right.png").get_pixbuf()
        self.cache_bg_pixbuf = CachePixbuf()
        self.update_size()
        self.connect("expose-event", self.on_expose_event)

    def update_size(self):
        text_w, text_h = get_content_size(self.prompt_text, self.font_size)
        widget_w = text_w + self.padding_x * 2
        if widget_w > self.max_width:
            widget_w = self.max_width
        self.set_size_request(widget_w, self.widget_h)
        self.queue_draw()

    def on_expose_event(self, widget, event):
        cr = widget.window.cairo_create()
        rect = widget.allocation
        draw_pixbuf(cr, self.bg_left, rect.x, rect.y)
        bg_left_w = self.bg_left.get_width()
        self.cache_bg_pixbuf.scale(self.bg_middle, rect.width - bg_left_w * 2,
                                   self.bg_middle.get_height())
        draw_pixbuf(cr, self.cache_bg_pixbuf.get_cache(), rect.x + bg_left_w,
                    rect.y)
        draw_pixbuf(cr, self.bg_right, rect.x + rect.width - bg_left_w, rect.y)

        # draw text.
        text_rect = gtk.gdk.Rectangle(rect.x + self.padding_x, rect.y,
                                      rect.width - self.padding_x * 2,
                                      rect.height)
        render_text(cr, self.prompt_text, text_rect,
                    app_theme.get_color("labelText").get_color(), 8)

        return True

    def set_text(self, text):
        self.prompt_text = text
        Tooltip.text(self, self.prompt_text)
        self.update_size()
Beispiel #3
0
    def render(self, cr, rect):
        # Init.
        x, y, w, h = rect.x, rect.y, rect.width, rect.height

        # Draw background frame.
        with cairo_state(cr):
            cr.rectangle(x, y + 1, w, h - 2)
            cr.rectangle(x + 1, y, w - 2, h)
            cr.clip()

            cr.set_source_rgb(*color_hex_to_cairo(
                ui_theme.get_color(
                    "progressbar_background_frame").get_color()))
            cr.rectangle(x, y, w, h)
            cr.set_line_width(1)
            cr.stroke()

        # Draw background.
        with cairo_state(cr):
            cr.rectangle(x + 1, y + 1, w - 2, h - 2)
            cr.clip()

            draw_vlinear(
                cr,
                x + 1,
                y + 1,
                w - 2,
                h - 2,
                ui_theme.get_shadow_color(
                    "progressbar_background").get_color_info(),
            )
            cache_pixbuf_object = CachePixbuf()
            if self.progress > 0 and self.progress < 100:
                cache_pixbuf_object.scale(
                    self.percentage_dpixbuf[int(self.progress /
                                                10)].get_pixbuf(), w, h)
            if self.progress == 100:
                cache_pixbuf_object.scale(
                    self.percentage_dpixbuf[9].get_pixbuf(), w, h)
            draw_pixbuf(cr, cache_pixbuf_object.get_cache(), x, y)

        # Draw light.
        with cairo_disable_antialias(cr):
            cr.set_source_rgba(1, 1, 1, 0.5)
            cr.rectangle(x + 1, y + 1, w - 2, 1)
            cr.fill()
 def render(self, cr, rect):
     # Init.
     x, y, w, h = rect.x, rect.y, rect.width, rect.height
     
     # Draw background frame.
     with cairo_state(cr):
         cr.rectangle(x, y + 1, w, h - 2)
         cr.rectangle(x + 1, y, w - 2, h)
         cr.clip()
         
         cr.set_source_rgb(*color_hex_to_cairo(ui_theme.get_color("progressbar_background_frame").get_color()))
         cr.rectangle(x, y, w, h)
         cr.set_line_width(1)
         cr.stroke()
         
     # Draw background.
     with cairo_state(cr):
         cr.rectangle(x + 1, y + 1, w - 2, h - 2)
         cr.clip()
         
         draw_vlinear(cr, x + 1, y + 1, w - 2, h - 2,
                      ui_theme.get_shadow_color("progressbar_background").get_color_info(), 
                      )
         cache_pixbuf_object = CachePixbuf()
         if self.progress > 0 and self.progress < 100:
             cache_pixbuf_object.scale(self.percentage_dpixbuf[int(self.progress / 10)].get_pixbuf(), 
                                       w, 
                                       h)
         if self.progress == 100:
             cache_pixbuf_object.scale(self.percentage_dpixbuf[9].get_pixbuf(), 
                                       w, 
                                       h)
         draw_pixbuf(cr, cache_pixbuf_object.get_cache(), x, y)
     
     # Draw light.
     with cairo_disable_antialias(cr):
         cr.set_source_rgba(1, 1, 1, 0.5)
         cr.rectangle(x + 1, y + 1, w - 2, 1)
         cr.fill()
class VolumeButton(gtk.Button):
    
    __gsignals__ = { 
        "volume-state-changed" : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT)),
                     }
    
    def __init__(self, value=100, lower=0, upper=100, step=5, progress_width=45, auto_hide=True, mini_mode=False):
        gtk.Button.__init__(self)
        
        # Init data.
        self.__value = value
        self.__lower = lower
        self.__upper = upper
        self.__step = step
        self.progress_width = progress_width
        self.mute_flag = False
        self.state_press_flag = False
        self.drag_flag = False
        self.drag_out_area = False
        self.hide_progress_flag = True
        self.current_progress_width = self.value_to_width(self.__value)
        self.icon_state = STATE_NORMAL
        self.auto_hide = auto_hide
        
        # Init DPixbufs.
        if mini_mode:
            self.volume_prefix = "mini_volume"
        else:    
            self.volume_prefix = "volume"
        self.bg_dpixbuf = app_theme.get_pixbuf("%s/bg.png" % self.volume_prefix)
        self.fg_dpixbuf = app_theme.get_pixbuf("%s/fg.png" % self.volume_prefix)
        self.point_dpixbuf = app_theme.get_pixbuf("%s/point.png" % self.volume_prefix)
        self.update_state_dpixbufs(self.get_state_name(self.__value))
        
        # Init Dcolors.
        self.fg_left_dcolor = app_theme.get_color("progressBarLeft")
        self.fg_right_dcolor = app_theme.get_color("progressBarRight")
        
        
        # Init Sizes.
        self.padding_x = 0
        self.padding_y = 0
        self.progress_x = 0
        self.state_icon_rect = gtk.gdk.Rectangle(
            self.padding_x, self.padding_y,
            self.normal_dpixbuf.get_pixbuf().get_width() - 2,
            self.normal_dpixbuf.get_pixbuf().get_height())
        
        self.point_width = self.point_dpixbuf.get_pixbuf().get_width()
        self.base_width = self.padding_x * 2 + self.normal_dpixbuf.get_pixbuf().get_width()        
        self.expand_width = self.base_width + self.progress_width + self.progress_x  + self.point_width
        self.default_height = self.padding_y * 2 + self.normal_dpixbuf.get_pixbuf().get_height()
        self.point_offset = self.state_icon_rect.x + self.state_icon_rect.width + self.progress_x - 2
        self.fg_offset = self.bg_offset = self.point_offset + self.point_width / 2
        
        # Init CachePixbufs
        self.bg_cache_pixbuf = CachePixbuf()
        self.fg_cache_pixbuf = CachePixbuf()
        
        # Init Events.
        self.add_events(gtk.gdk.ALL_EVENTS_MASK)
        self.connect("expose-event", self.on_expose_event)
        self.connect("scroll-event", self.on_scroll_event)
        self.connect("enter-notify-event", self.on_enter_notify_event)
        self.connect("leave-notify-event", self.on_leave_notify_event)
        self.connect("button-press-event", self.on_button_press_event)
        self.connect("motion-notify-event", self.on_motion_notify_event)
        self.connect("button-release-event", self.on_button_release_event)
        
        if self.auto_hide:
            if self.hide_progress_flag:
                self.set_size_request(self.base_width, self.default_height)
            else:    
                self.set_size_request(self.expand_width, self.default_height)
        else:        
            self.set_size_request(self.expand_width, self.default_height)
            
    def value_to_width(self, value):    
        return value / float(self.__upper) * self.progress_width
    
    def get_size(self):
        if self.auto_hide:
            if self.hide_progress_flag:
                return (self.base_width, self.default_height)
        return (self.expand_width, self.default_height)    
    
    def width_to_value(self, width):
        return width / float(self.progress_width) * self.__upper 
    
    def update_state_by_value(self, emit=True):
        value = self.width_to_value(int(self.current_progress_width))
        state_name = self.get_state_name(value)
        self.update_state_dpixbufs(state_name, queue_draw=True)
        if emit:
            self.emit("volume-state-changed", self.get_value(), self.mute_flag)        
    
    def update_progress_width(self, event, emit=False):
        self.current_progress_width = int(event.x - self.fg_offset)
        if self.current_progress_width < 0:
            self.current_progress_width = 0
        elif self.current_progress_width > self.progress_width:    
            self.current_progress_width = self.progress_width
        self.update_state_by_value(emit=emit)    
        self.queue_draw()
        
    def update_state_dpixbufs(self, name, queue_draw=False):    
        self.normal_dpixbuf = app_theme.get_pixbuf("%s/%s_normal.png" % (self.volume_prefix, name))
        self.hover_dpixbuf = app_theme.get_pixbuf("%s/%s_hover.png" % (self.volume_prefix, name))
        self.press_dpixbuf = app_theme.get_pixbuf("%s/%s_press.png" % (self.volume_prefix, name))
        
        if queue_draw:
            self.queue_draw()
        
    def get_state_name(self, value):
        if value == 0:
            state_name = "zero"
        elif 0 < value <= self.__upper * (1.0/3):
            state_name = "low"
        elif self.__upper * (1.0/3) < value <= self.__upper * (2.0 / 3):    
            state_name = "medium"
        else:    
            state_name = "high"
        return state_name    
    
    def on_expose_event(self, widget, event):
        cr = widget.window.cairo_create()
        rect = widget.allocation
        
        self.draw_volume(cr, rect)
        return True
        
    def draw_volume(self, cr, rect):    
        # Draw state icon.
        if self.icon_state == STATE_HOVER:
            pixbuf = self.hover_dpixbuf.get_pixbuf()
        elif self.icon_state == STATE_PRESS:    
            pixbuf = self.press_dpixbuf.get_pixbuf()
        else:    
            pixbuf = self.normal_dpixbuf.get_pixbuf()
        draw_pixbuf(cr, pixbuf, rect.x + self.padding_x, rect.y + self.padding_y)    
        
        if self.auto_hide:
            if not self.hide_progress_flag:
                self.draw_progress_bar(cr, rect)
        else:        
            self.draw_progress_bar(cr, rect)
        
    def draw_progress_bar(self, cr, rect):                    
        
        # Draw progressbar background.
        bg_height = self.bg_dpixbuf.get_pixbuf().get_height()
        self.bg_cache_pixbuf.scale(self.bg_dpixbuf.get_pixbuf(), self.progress_width, 
                                   bg_height)
        

        bg_y = rect.y + (rect.height - bg_height) / 2
        draw_pixbuf(cr, self.bg_cache_pixbuf.get_cache(), rect.x + self.bg_offset, bg_y)
        
        # Draw progressbar foreground.
        if self.current_progress_width > 0:
            fg_height = self.fg_dpixbuf.get_pixbuf().get_height()
            # self.fg_cache_pixbuf.scale(self.fg_dpixbuf.get_pixbuf(), 
            #                            int(self.current_progress_width),
            #                            fg_height)
        
            fg_y = rect.y + (rect.height - fg_height) / 2
            # draw_pixbuf(cr, self.fg_cache_pixbuf.get_cache(),  rect.x + self.fg_offset, fg_y)
            
            lg_width = int(self.current_progress_width)
            pat = cairo.LinearGradient(rect.x + self.fg_offset, fg_y, rect.x + self.fg_offset + lg_width, fg_y)
            pat.add_color_stop_rgb(0.6, *color_hex_to_cairo(self.fg_left_dcolor.get_color()))
            pat.add_color_stop_rgb(1.0, *color_hex_to_cairo(self.fg_right_dcolor.get_color()))
            cr.set_operator(cairo.OPERATOR_OVER)
            cr.set_source(pat)
            cr.rectangle(rect.x + self.fg_offset, fg_y, lg_width, fg_height)
            cr.fill()
            
            with cairo_disable_antialias(cr):
                cr.set_line_width(1)
                cr.set_source_rgba(1, 1, 1, 0.3)
                cr.rectangle(rect.x + self.fg_offset, fg_y, lg_width, fg_height)
                cr.stroke()
        
        # Draw point.
        point_y = rect.y + (rect.height - self.point_dpixbuf.get_pixbuf().get_height()) / 2
        draw_pixbuf(cr, self.point_dpixbuf.get_pixbuf(), 
                    rect.x + self.point_offset + self.current_progress_width, 
                    point_y)
            
    def on_enter_notify_event(self, widget, event):
        if self.auto_hide:
            self.hide_progress_flag = False
            self.set_size_request(self.expand_width, self.default_height)
            self.queue_draw()
        
    def hide_progressbar(self):    
        self.hide_progress_flag = True
        self.set_size_request(self.base_width, self.default_height)
        self.icon_state = STATE_NORMAL
        set_cursor(self, None)
        self.queue_draw()
    
    def on_leave_notify_event(self, widget, event):
        if self.drag_flag:
            self.drag_out_area = True
        else:    
            if self.auto_hide:
                self.hide_progressbar()
                
        set_cursor(widget, None)        
    
    def pointer_in_state_icon(self, event):    
        if self.state_icon_rect.x <= event.x <= self.state_icon_rect.x + self.state_icon_rect.width  and \
                self.state_icon_rect.y <= event.y <= self.state_icon_rect.y + self.state_icon_rect.height:
            return True
        return False
        
    def on_button_press_event(self, widget, event):
        if self.pointer_in_state_icon(event):
            self.state_press_flag = True
            self.icon_state = STATE_PRESS
            self.drag_flag = False
        else:    
            self.update_progress_width(event, emit=True)            
            self.state_press_flag = False
            self.drag_flag = True
            self.mute_flag = False
            
        self.queue_draw()
    
    def on_motion_notify_event(self, widget, event):
        if self.pointer_in_state_icon(event):
            self.icon_state = STATE_HOVER
            set_cursor(widget, None)
        else:    
            self.icon_state = STATE_NORMAL
            set_cursor(widget, gtk.gdk.HAND2)
            
        if self.drag_flag:
            self.update_progress_width(event, emit=True)
        self.queue_draw()

    def on_button_release_event(self, widget, event):
        if self.drag_out_area:
            if self.auto_hide:
                self.hide_progressbar()
        self.drag_out_area = False    
        
        if self.state_press_flag:
            if self.mute_flag:
                self.update_state_by_value(emit=False)
                self.mute_flag = False
            else:    
                self.update_state_dpixbufs("mute")
                self.mute_flag = True
            
        self.emit("volume-state-changed", self.get_value(), self.mute_flag)    
                
        self.icon_state = STATE_NORMAL        
        self.state_press_flag = False        
        self.drag_flag = False
        self.queue_draw()
        
    def get_value(self):    
        return self.width_to_value(self.current_progress_width)
    
    def set_value(self, value, emit=True):
        self.current_progress_width = self.value_to_width(value)
        self.update_state_by_value(emit=emit)
        self.queue_draw()
        
    def set_mute(self):
        self.update_state_dpixbufs("mute")
        self.mute_flag = True
        self.queue_draw()
        
    def unset_mute(self):    
        self.mute_flag = False
        self.queue_draw()
        
    def on_scroll_event(self, widget, event):
        self.mute_flag = False
        if event.direction == gtk.gdk.SCROLL_UP:
            self.increase_value()
        elif event.direction == gtk.gdk.SCROLL_DOWN:
            self.decrease_value()
            
    def increase_value(self):    
        self.current_progress_width += self.value_to_width(self.__step)
        if self.current_progress_width > self.progress_width:
            self.current_progress_width = self.progress_width
        self.update_state_by_value()
        self.queue_draw()
            
    def decrease_value(self):        
        self.current_progress_width -= self.value_to_width(self.__step)
        if self.current_progress_width < 0:
            self.current_progress_width = 0
        self.update_state_by_value()
        self.queue_draw()
class RadioListItem(TreeItem):
    
    def __init__(self, channel_info):
        TreeItem.__init__(self)
        self.index = 0
        self.column_index = 0
        self.side_padding = 5
        self.normal_item_height = 55
        self.highlight_item_height = 80
        self.item_height = self.normal_item_height
        self.item_width = LIST_WIDTH
        self.is_highlight = False
        self.channel_info = channel_info
        self.icon_width = self.icon_height = 45
        cover_path = DoubanCover.get_cover(channel_info, try_web=False)
        if cover_path:
            self.normal_pixbuf = gtk.gdk.pixbuf_new_from_file(cover_path)
        else:    
            self.normal_pixbuf = app_theme.get_pixbuf("radio/default_cover.png").get_pixbuf()
        self.update_size()    
        
        self.animation_cache_pixbuf = CachePixbuf()
        self.animation_timeout = 100 # s
        self.animation_id = None
        self.active_size = 45
        
    def render_animation(self, cr, rect):    
        self.animation_cache_pixbuf.scale(self.normal_pixbuf, self.active_size, self.active_size)
        animation_pixbuf = self.animation_cache_pixbuf.get_cache()
        icon_x = rect.x + (rect.width - self.active_size) / 2
        icon_y = rect.y + (rect.height - self.active_size) / 2
        draw_pixbuf(cr, animation_pixbuf, icon_x, icon_y)
        
    def update_animation(self):    
        if self.is_hover:
            self.active_size += 2
            if self.active_size >= 55:
                self.active_size = 55
                return False
        else:    
            self.active_size -= 2
            if self.active_size < 45:
                self.active_size = 45
                return False
        self.emit_redraw_request()    
        return True
    
    def start_animation(self):
        gobject.timeout_add(self.animation_timeout, self.update_animation)
        
    @property
    def channel_id(self):
        return self.channel_info.get("id", "")
        
    def emit_redraw_request(self):
        if self.redraw_request_callback:
            self.redraw_request_callback(self)
        
    def update_size(self):    
        self.channel_name = utils.xmlescape(self.channel_info.get("name", ""))
        __, self.name_h = get_content_size(self.channel_name, text_size=9)
        
        self.detail_info = "%s首歌曲 %s制作" % (self.channel_info.get("song_num"),
                                       utils.xmlescape(self.channel_info.get("creator", {}).get("name", "")))
        __, self.detail_h = get_content_size(self.detail_info, text_size=8)
        
        intro = utils.xmlescape(self.channel_info.get("intro", "").strip())
        hotsongs = utils.xmlescape(" ".join(self.channel_info.get("hot_songs")))
        self.channel_intro = intro or hotsongs               
        __, self.intro_h = get_content_size(self.channel_intro, text_size=8)
    
    def render_content(self, cr, rect):
        if self.is_highlight:    
            draw_single_mask(cr, rect.x + 1, rect.y, rect.width, rect.height, "globalItemHighlight")
        elif self.is_select:    
            draw_single_mask(cr, rect.x + 1, rect.y, rect.width, rect.height, "globalItemSelect")
        elif self.is_hover:
            draw_single_mask(cr, rect.x + 1, rect.y, rect.width, rect.height, "globalItemHover")
        
        if self.is_highlight:
            text_color = "#ffffff"
        else:    
            text_color = app_theme.get_color("labelText").get_color()
            
        icon_pixbuf = self.normal_pixbuf    
        icon_y = rect.y + (rect.height - self.icon_height) / 2    
        padding_x = 10
        padding_y = 10
        
        animation_rect = gtk.gdk.Rectangle(rect.x + padding_x,  icon_y, self.icon_width, self.icon_height)                
        cr.save()
        cr.arc(animation_rect.x + animation_rect.width / 2,
               animation_rect.y + animation_rect.height / 2,
               animation_rect.width / 2,
               0, 2 * math.pi)
        # cr.rectangle(animation_rect.x, animation_rect.y, animation_rect.width, animation_rect.height)
        cr.clip()
        # self.render_animation(cr, animation_rect)
        draw_pixbuf(cr, self.normal_pixbuf, rect.x + padding_x, icon_y)        
        cr.restore()
        
        draw_text(cr, self.channel_name, rect.x + icon_pixbuf.get_width() + padding_x * 2, 
                  rect.y + padding_y, rect.width - icon_pixbuf.get_width() - padding_x * 3, self.name_h, 
                  text_color = text_color,
                  alignment=pango.ALIGN_LEFT, text_size=10)    
        
        if self.is_highlight:
            draw_text(cr, self.channel_intro, rect.x + icon_pixbuf.get_width() + padding_x * 2,
                      rect.y + padding_y  * 2 + self.name_h, 
                      rect.width - icon_pixbuf.get_width() - padding_x * 3,
                      self.intro_h,
                      text_color = text_color,
                      alignment=pango.ALIGN_LEFT, text_size=8)
        
        draw_text(cr, self.detail_info, rect.x + icon_pixbuf.get_width() + padding_x * 2, 
                  rect.y + (rect.height - self.detail_h - padding_y), 
                  rect.width - icon_pixbuf.get_width() - padding_x * 3, self.detail_h, 
                  text_color = text_color,
                  alignment=pango.ALIGN_LEFT, text_size=8)    
        
    def get_height(self):    
        if self.is_highlight:
            return self.highlight_item_height            
        else:
            return self.normal_item_height            
    
    
    def get_column_widths(self):
        return (self.item_width,)
    
    def unhover(self, column, offset_x, offset_y):
        self.is_hover = False
        # self.start_animation()
        self.emit_redraw_request()
    
    def hover(self, column, offset_x, offset_y):
        self.is_hover = True
        # self.start_animation()
        self.emit_redraw_request()
    
    def unselect(self):
        self.is_select = False
        self.emit_redraw_request()
    
    def select(self):    
        self.is_select = True
        self.emit_redraw_request()
        
    def highlight(self):    
        self.is_highlight = True
        self.is_select = False
        self.emit_redraw_request()
        
    def unhighlight(self):    
        self.is_highlight = False
        self.is_select = False
        self.emit_redraw_request()
        
    def get_column_renders(self):
        return (self.render_content,)
        
    def __hash__(self):
        return hash(self.channel_info.get("id"))
    
    def __repr__(self):
        return "<RadioItem %s>" % self.channel_info.get("id")
    
    def __cmp__(self, other_item):
        if not other_item:
            return -1
        try:
            return cmp(self.channel_info, other_item.channel_info)
        except AttributeError: return -1
        
    def __eq__(self, other_item):    
        try:
            return self.channel_info.get("id") == other_item.channel_info.get("id")
        except:
            return False
class HScalebar(gtk.HScale):
    def __init__(
        self,
        fg_dpixbuf=app_theme.get_pixbuf("scalebar/fg.png"),
        bg_dpixbuf=app_theme.get_pixbuf("scalebar/bg.png"),
        point_normal_dpixbuf=app_theme.get_pixbuf("scalebar/point_normal.png"),
        point_hover_dpixbuf=app_theme.get_pixbuf("scalebar/point_hover.png"),
        point_press_dpixbuf=app_theme.get_pixbuf("scalebar/point_press.png"),
    ):

        super(HScalebar, self).__init__()
        self.set_draw_value(False)
        self.set_range(0, 100)
        self.fg_dpixbuf = fg_dpixbuf
        self.bg_dpixbuf = bg_dpixbuf
        self.point_normal_dpixbuf = point_normal_dpixbuf
        self.point_hover_dpixbuf = point_hover_dpixbuf
        self.point_press_dpixbuf = point_press_dpixbuf
        self.bottom_side = 0
        self.fg_cache_pixbuf = CachePixbuf()
        self.bg_cache_pixbuf = CachePixbuf()
        self.side_cache_pixbuf = CachePixbuf()

        # Colors
        self.fg_left_dcolor = app_theme.get_color("progressBarLeft")
        self.fg_right_dcolor = app_theme.get_color("progressBarRight")

        self.set_size_request(-1, self.bg_dpixbuf.get_pixbuf().get_height())

        self.connect("expose-event", self.expose_h_scalebar)
        self.connect("button-press-event", self.press_volume_progressbar)

    def expose_h_scalebar(self, widget, event):
        cr = widget.window.cairo_create()
        rect = widget.allocation

        # Init pixbuf.
        fg_pixbuf = self.fg_dpixbuf.get_pixbuf()
        bg_pixbuf = self.bg_dpixbuf.get_pixbuf()
        point_normal_pixbuf = self.point_normal_dpixbuf.get_pixbuf()
        # point_hover_pixbuf = self.point_hover_dpixbuf.get_pixbuf()
        # point_press_pixbuf = self.point_press_dpixbuf.get_pixbuf()

        # Init value.
        upper = self.get_adjustment().get_upper()
        lower = self.get_adjustment().get_lower()
        total_length = max(upper - lower, 1)

        point_width = point_normal_pixbuf.get_width()
        point_height = point_normal_pixbuf.get_height()
        x, y, w, h = rect.x + point_width / 2, rect.y, rect.width - point_width, rect.height

        line_height = bg_pixbuf.get_height()

        line_y = y + (point_height - line_height) / 2
        value = int((self.get_value() - lower) / total_length * w)

        # Draw background.
        self.fg_cache_pixbuf.scale(bg_pixbuf, w + point_width, line_height)
        draw_pixbuf(cr, self.fg_cache_pixbuf.get_cache(), rect.x, line_y)

        self.bg_cache_pixbuf.scale(fg_pixbuf, point_width / 2, line_height)
        draw_pixbuf(cr, self.bg_cache_pixbuf.get_cache(), rect.x, line_y)

        if value > 0:
            pat = cairo.LinearGradient(0, 0, value + point_width, 0)
            pat.add_color_stop_rgb(0.7, *color_hex_to_cairo(self.fg_left_dcolor.get_color()))
            pat.add_color_stop_rgb(1.0, *color_hex_to_cairo(self.fg_right_dcolor.get_color()))
            cr.set_operator(cairo.OPERATOR_OVER)
            cr.set_source(pat)
            cr.rectangle(rect.x, line_y, value + point_width, line_height)
            cr.fill()

            with cairo_disable_antialias(cr):
                cr.set_line_width(1)
                cr.set_source_rgba(1, 1, 1, 0.5)
                cr.move_to(rect.x, line_y + 1)
                cr.rel_line_to(value + point_width, 0)
                cr.stroke()

                cr.set_source_rgba(1, 1, 1, 0.3)
                cr.move_to(rect.x, line_y + line_height)
                cr.rel_line_to(value + point_width, 0)
                cr.stroke()

            # self.side_cache_pixbuf.scale(
            #     fg_pixbuf, value + point_width, line_height)
            # draw_pixbuf(
            #     cr,
            #     self.side_cache_pixbuf.get_cache(),
            #     rect.x, line_y)

        if value > 0:
            draw_pixbuf(cr, point_normal_pixbuf, x + value - point_width / 2 + 2, y)
        else:
            draw_pixbuf(cr, point_normal_pixbuf, x + value - point_width / 2 - 1, y)

        return True

    def press_volume_progressbar(self, widget, event):
        # Init.
        if is_left_button(event):
            rect = widget.allocation
            lower = self.get_adjustment().get_lower()
            upper = self.get_adjustment().get_upper()
            point_width = self.point_normal_dpixbuf.get_pixbuf().get_width()

            self.set_value(lower + ((event.x - point_width / 2)) / (rect.width - point_width) * (upper - lower))
            self.queue_draw()

        return False
class VScalebar(gtk.Button):
    """
    Volume button.
    """

    __gtype_name__ = "VScalebar"
    __gsignals__ = {"value-changed": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (float,))}

    def __init__(self, value=100, lower=0, upper=100, step=5, default_height=100):
        gtk.Button.__init__(self)

        # Init default data.
        self.__value = value
        self.__lower = lower
        self.__upper = upper
        self.__step = step
        self.default_height = default_height
        self.current_y = 0

        # Init DPixbuf.
        self.bg_bottom_dpixbuf = app_theme.get_pixbuf("volume/bg_bottom.png")
        self.bg_middle_dpixbuf = app_theme.get_pixbuf("volume/bg_middle.png")
        self.bg_top_dpixbuf = app_theme.get_pixbuf("volume/bg_top.png")
        self.point_dpixbuf = app_theme.get_pixbuf("volume/point.png")

        # Init sizes.
        self.fg_width = self.bg_width = self.bg_middle_dpixbuf.get_pixbuf().get_width()
        self.bg_top_height = self.bg_top_dpixbuf.get_pixbuf().get_height()
        self.bg_bottom_height = self.bg_bottom_dpixbuf.get_pixbuf().get_height()
        self.point_width = self.point_dpixbuf.get_pixbuf().get_width()
        self.point_height = self.point_dpixbuf.get_pixbuf().get_height()
        self.bg_x_offset = (self.point_width - self.bg_width) / 2
        self.set_size_request(self.point_width, self.default_height)
        self.real_height = self.default_height - self.point_height

        # Init CachePixbuf.
        self.__bg_cache_pixbuf = CachePixbuf()

        # Init events.
        self.add_events(gtk.gdk.ALL_EVENTS_MASK)
        self.connect("button-press-event", self.on_button_press)
        self.connect("motion-notify-event", self.on_motion_notify)
        self.connect("button-release-event", self.on_button_release)
        self.connect("expose-event", self.on_expose_event)
        self.connect("scroll-event", self.on_scroll_event)

        # Init flags
        self.__button_press_flag = False

    def value_to_height(self, value):
        return self.__upper / float(self.real_height) * value

    def height_to_value(self, height):
        return height / float(self.real_height) * self.__upper

    def on_scroll_event(self, widget, event):
        if event.direction == gtk.gdk.SCROLL_UP:
            self.increase_value()
        elif event.direction == gtk.gdk.SCROLL_DOWN:
            self.decrease_value()

    def on_expose_event(self, widget, event):
        cr = widget.window.cairo_create()
        rect = widget.allocation
        x, y, w, h = (
            rect.x + self.bg_x_offset,
            rect.y + self.point_height / 2,
            rect.width,
            rect.height - self.point_height,
        )

        fg_x = bg_x = rect.x + self.bg_x_offset
        # Draw background.
        draw_pixbuf(cr, self.bg_top_dpixbuf.get_pixbuf(), bg_x, y)

        middle_height = h - self.bg_top_height - self.bg_bottom_height
        self.__bg_cache_pixbuf.scale(self.bg_middle_dpixbuf.get_pixbuf(), self.bg_width, middle_height)
        draw_pixbuf(cr, self.__bg_cache_pixbuf.get_cache(), bg_x, y + self.bg_top_height)
        draw_pixbuf(cr, self.bg_bottom_dpixbuf.get_pixbuf(), bg_x, y + h - self.bg_top_height)

        # Draw foreground.
        cr.set_source_rgb(*color_hex_to_cairo("#2868c7"))
        cr.rectangle(fg_x, y + self.current_y, self.fg_width, h - self.current_y)
        cr.fill()

        # # Draw point.
        draw_pixbuf(cr, self.point_dpixbuf.get_pixbuf(), rect.x, rect.y + self.current_y)
        return True

    def on_button_press(self, widget, event):
        if is_left_button(event):
            rect = widget.allocation
            if event.y < self.point_height / 2:
                motion_y = self.point_height / 2
            elif event.y > rect.height - self.point_height:
                motion_y = rect.height - self.point_height
            else:
                motion_y = event.y

            if self.current_y != motion_y:
                self.current_y = motion_y
                self.emit("value-changed", self.get_value())

                self.queue_draw()
            self.__button_press_flag = True

    def on_motion_notify(self, widget, event):
        if self.__button_press_flag:
            rect = widget.allocation
            if event.y < 0:
                motion_y = 0
            elif event.y > rect.height - self.point_height:
                motion_y = rect.height - self.point_height
            else:
                motion_y = event.y

            if self.current_y != motion_y:
                self.current_y = motion_y
                self.emit("value-changed", self.get_value())
                self.queue_draw()

    def on_button_release(self, widget, event):
        self.__button_press_flag = False

    def get_value(self):
        self.__value = self.height_to_value(self.real_height - self.current_y)
        return round(self.__value, 1)

    def set_value(self, value):
        self.current_y = self.real_height - self.value_to_height(value)
        self.queue_draw()

    def set_range(self, lower, upper):
        self.__lower = lower
        self.__upper = upper

    def increase_value(self):
        temp_y = self.current_y
        temp_y += self.value_to_height(self.__step)
        if temp_y > self.real_height:
            temp_y = self.real_height
        if temp_y != self.current_y:
            self.current_y = temp_y
            self.emit("value-changed", self.get_value())
            self.queue_draw()

    def decrease_value(self):
        temp_y = self.current_y
        temp_y -= self.value_to_height(self.__step)
        if temp_y < 0:
            temp_y = 0
        if temp_y != self.current_y:
            self.current_y = temp_y
            self.emit("value-changed", self.get_value())
            self.queue_draw()
class HScalebar(gtk.HScale):
    
    def __init__(self, 
                 fg_dpixbuf=app_theme.get_pixbuf("scalebar/fg.png"),
                 bg_dpixbuf=app_theme.get_pixbuf("scalebar/bg.png"),
                 point_normal_dpixbuf = app_theme.get_pixbuf("scalebar/point_normal.png"),
                 point_hover_dpixbuf = app_theme.get_pixbuf("scalebar/point_hover.png"),
                 point_press_dpixbuf = app_theme.get_pixbuf("scalebar/point_press.png"),
                 ):
        
        super(HScalebar, self).__init__()
        self.set_draw_value(False)
        self.set_range(0, 100)
        self.fg_dpixbuf = fg_dpixbuf
        self.bg_dpixbuf = bg_dpixbuf
        self.point_normal_dpixbuf = point_normal_dpixbuf
        self.point_hover_dpixbuf = point_hover_dpixbuf
        self.point_press_dpixbuf = point_press_dpixbuf
        self.bottom_side = 0
        self.fg_cache_pixbuf = CachePixbuf()
        self.bg_cache_pixbuf = CachePixbuf()
        self.side_cache_pixbuf = CachePixbuf()
        
        # Colors
        self.fg_left_dcolor = app_theme.get_color("progressBarLeft")
        self.fg_right_dcolor = app_theme.get_color("progressBarRight")
        
        self.set_size_request(-1, self.bg_dpixbuf.get_pixbuf().get_height())
        
        self.connect("expose-event", self.expose_h_scalebar)
        self.connect("button-press-event", self.press_volume_progressbar)
        
    def expose_h_scalebar(self, widget, event):    
        cr = widget.window.cairo_create()
        rect = widget.allocation
        
        # Init pixbuf.
        fg_pixbuf = self.fg_dpixbuf.get_pixbuf()
        bg_pixbuf = self.bg_dpixbuf.get_pixbuf()
        point_normal_pixbuf = self.point_normal_dpixbuf.get_pixbuf()
        # point_hover_pixbuf = self.point_hover_dpixbuf.get_pixbuf()
        # point_press_pixbuf = self.point_press_dpixbuf.get_pixbuf()
        
        # Init value.
        upper = self.get_adjustment().get_upper()
        lower = self.get_adjustment().get_lower()
        total_length = max(upper - lower, 1)
        
        point_width = point_normal_pixbuf.get_width()
        point_height = point_normal_pixbuf.get_height()
        x, y, w, h = rect.x + point_width / 2, rect.y, rect.width - point_width, rect.height
        
        line_height = bg_pixbuf.get_height()

        line_y = y + (point_height - line_height) / 2
        value = int((self.get_value() - lower) / total_length * w)
        
        
        # Draw background.
        self.fg_cache_pixbuf.scale(
            bg_pixbuf, w + point_width, line_height)
        draw_pixbuf(
            cr,
            self.fg_cache_pixbuf.get_cache(),
            rect.x, line_y)
        
        self.bg_cache_pixbuf.scale(
            fg_pixbuf, point_width / 2, line_height)
        draw_pixbuf(
            cr,
            self.bg_cache_pixbuf.get_cache(),
            rect.x, line_y)

        
        if value > 0:
            pat = cairo.LinearGradient(0, 0, value + point_width, 0)
            pat.add_color_stop_rgb(0.7, *color_hex_to_cairo(self.fg_left_dcolor.get_color()))
            pat.add_color_stop_rgb(1.0, *color_hex_to_cairo(self.fg_right_dcolor.get_color()))
            cr.set_operator(cairo.OPERATOR_OVER)
            cr.set_source(pat)
            cr.rectangle(rect.x, line_y, value + point_width, line_height)
            cr.fill()
            
            with cairo_disable_antialias(cr):
                cr.set_line_width(1)
                cr.set_source_rgba(1, 1, 1, 0.5)
                cr.move_to(rect.x, line_y + 1)
                cr.rel_line_to(value + point_width, 0)
                cr.stroke()
                
                cr.set_source_rgba(1, 1, 1, 0.3)
                cr.move_to(rect.x, line_y + line_height)
                cr.rel_line_to(value + point_width, 0)
                cr.stroke()
                
            # self.side_cache_pixbuf.scale(
            #     fg_pixbuf, value + point_width, line_height)
            # draw_pixbuf(
            #     cr, 
            #     self.side_cache_pixbuf.get_cache(),
            #     rect.x, line_y)
            
        if value > 0:    
            draw_pixbuf(cr, point_normal_pixbuf, x + value - point_width / 2 + 2, y)    
        else:    
            draw_pixbuf(cr, point_normal_pixbuf, x + value - point_width / 2 - 1, y)
        
        return True
    
    
    def press_volume_progressbar(self, widget, event):
        # Init.
        if is_left_button(event):
            rect = widget.allocation
            lower = self.get_adjustment().get_lower()
            upper = self.get_adjustment().get_upper()
            point_width = self.point_normal_dpixbuf.get_pixbuf().get_width()
            
            self.set_value(lower + ((event.x - point_width / 2)) / (rect.width - point_width) * (upper - lower))
            self.queue_draw()
            
        return False    
Beispiel #10
0
class VScalebar(gtk.Button):
    '''
    Volume button.
    '''
    __gtype_name__ = "VScalebar"
    __gsignals__ = {"value-changed" : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (float,)),
        }
    
    def __init__(self, value=100, lower=0, upper=100, step=5, default_height=100):
        gtk.Button.__init__(self)
        
        # Init default data.
        self.__value = value
        self.__lower = lower
        self.__upper = upper
        self.__step  = step
        self.default_height = default_height
        self.current_y = 0
        
        # Init DPixbuf.
        self.bg_bottom_dpixbuf = app_theme.get_pixbuf("volume/bg_bottom.png")
        self.bg_middle_dpixbuf = app_theme.get_pixbuf("volume/bg_middle.png")
        self.bg_top_dpixbuf = app_theme.get_pixbuf("volume/bg_top.png")
        self.point_dpixbuf = app_theme.get_pixbuf("volume/point.png")
        
        # Init sizes.
        self.fg_width = self.bg_width = self.bg_middle_dpixbuf.get_pixbuf().get_width()
        self.bg_top_height = self.bg_top_dpixbuf.get_pixbuf().get_height()
        self.bg_bottom_height = self.bg_bottom_dpixbuf.get_pixbuf().get_height()
        self.point_width = self.point_dpixbuf.get_pixbuf().get_width()
        self.point_height = self.point_dpixbuf.get_pixbuf().get_height()
        self.bg_x_offset = (self.point_width - self.bg_width) / 2
        self.set_size_request(self.point_width, self.default_height)
        self.real_height = self.default_height - self.point_height        
        
        # Init CachePixbuf.
        self.__bg_cache_pixbuf = CachePixbuf()
        
        # Init events.
        self.add_events(gtk.gdk.ALL_EVENTS_MASK)
        self.connect("button-press-event", self.on_button_press)
        self.connect("motion-notify-event", self.on_motion_notify)
        self.connect("button-release-event", self.on_button_release)
        self.connect("expose-event", self.on_expose_event)
        self.connect("scroll-event", self.on_scroll_event)
        
        # Init flags
        self.__button_press_flag = False
        
    def value_to_height(self, value):    
        return self.__upper / float(self.real_height)* value
    
    def height_to_value(self, height):
        return height / float(self.real_height) * self.__upper 
    
    def on_scroll_event(self, widget, event):
        if event.direction == gtk.gdk.SCROLL_UP:
            self.increase_value()
        elif event.direction == gtk.gdk.SCROLL_DOWN:
            self.decrease_value()
            
    def on_expose_event(self, widget, event):    
        cr = widget.window.cairo_create()
        rect = widget.allocation
        x, y, w, h = rect.x + self.bg_x_offset, rect.y + self.point_height / 2, rect.width, rect.height - self.point_height

        fg_x = bg_x = rect.x + self.bg_x_offset        
        # Draw background.
        draw_pixbuf(cr, self.bg_top_dpixbuf.get_pixbuf(), bg_x, y)
        
        middle_height = h - self.bg_top_height - self.bg_bottom_height
        self.__bg_cache_pixbuf.scale(self.bg_middle_dpixbuf.get_pixbuf(), 
                                     self.bg_width, middle_height)
        draw_pixbuf(cr, self.__bg_cache_pixbuf.get_cache(), bg_x, y + self.bg_top_height)
        draw_pixbuf(cr, self.bg_bottom_dpixbuf.get_pixbuf(), bg_x, y + h - self.bg_top_height)
        
        # Draw foreground.
        cr.set_source_rgb(*color_hex_to_cairo("#2868c7"))
        cr.rectangle(fg_x, y + self.current_y, self.fg_width, h - self.current_y)
        cr.fill()
        
        # # Draw point.
        draw_pixbuf(cr, self.point_dpixbuf.get_pixbuf(), rect.x, rect.y + self.current_y)
        return True
    
    def on_button_press(self, widget, event):
        if is_left_button(event):
            rect = widget.allocation
            if event.y < self.point_height / 2:
                motion_y = self.point_height / 2
            elif event.y > rect.height - self.point_height:
                motion_y = rect.height - self.point_height
            else:    
                motion_y = event.y
                
            if self.current_y != motion_y:    
                self.current_y = motion_y
                self.emit("value-changed", self.get_value())
                
                self.queue_draw()            
            self.__button_press_flag = True        
    
    def on_motion_notify(self, widget, event):
        if self.__button_press_flag:
            rect = widget.allocation
            if event.y < 0:
                motion_y = 0
            elif event.y > rect.height - self.point_height:
                motion_y = rect.height - self.point_height
            else:    
                motion_y = event.y
                
            if self.current_y != motion_y:    
                self.current_y = motion_y
                self.emit("value-changed", self.get_value())
                self.queue_draw()
    
    def on_button_release(self, widget, event):
        self.__button_press_flag = False
        
    def get_value(self):
        self.__value = self.height_to_value(self.real_height - self.current_y)
        return round(self.__value, 1)
    
    def set_value(self, value):
        self.current_y = self.real_height - self.value_to_height(value)
        self.queue_draw()
        
    def set_range(self, lower, upper):    
        self.__lower = lower
        self.__upper = upper
        
    def increase_value(self):    
        temp_y = self.current_y
        temp_y += self.value_to_height(self.__step)
        if temp_y > self.real_height:
            temp_y = self.real_height
        if temp_y != self.current_y:    
            self.current_y = temp_y
            self.emit("value-changed", self.get_value())
            self.queue_draw()
            
    def decrease_value(self):        
        temp_y = self.current_y
        temp_y -= self.value_to_height(self.__step)
        if temp_y < 0:
            temp_y = 0
        if temp_y != self.current_y:    
            self.current_y = temp_y
            self.emit("value-changed", self.get_value())
            self.queue_draw()
Beispiel #11
0
class PromptButton(gtk.Button):
    def __init__(self, pixbuf=None, text=None, max_width=360):

        # Init.
        gtk.Button.__init__(self)

        self.padding_x = 5
        self.max_width = max_width
        self.prompt_pixbuf = pixbuf
        self.prompt_text = text
        self.font_size = 9
        self.widget_h = 26

        self.bg_left = app_theme.get_pixbuf(
            "combo/prompt_left.png").get_pixbuf()
        self.bg_middle = app_theme.get_pixbuf(
            "combo/prompt_middle.png").get_pixbuf()
        self.bg_right = app_theme.get_pixbuf(
            "combo/prompt_right.png").get_pixbuf()
        self.cache_bg_pixbuf = CachePixbuf()
        self.update_size()
        self.connect("expose-event", self.on_expose_event)

    def update_size(self):
        if not self.prompt_pixbuf: return
        pixbuf_w = self.prompt_pixbuf.get_width()
        text_w, text_h = get_content_size(self.prompt_text, self.font_size)
        widget_w = pixbuf_w + text_w + self.padding_x * 3
        if widget_w > self.max_width:
            widget_w = self.max_width
        self.set_size_request(widget_w, self.widget_h)
        self.queue_draw()

    def on_expose_event(self, widget, event):
        if not self.prompt_pixbuf: return
        cr = widget.window.cairo_create()
        rect = widget.allocation
        pixbuf_y = rect.y + (rect.height - self.prompt_pixbuf.get_height()) / 2
        draw_pixbuf(cr, self.bg_left, rect.x, rect.y)
        bg_left_w = self.bg_left.get_width()
        self.cache_bg_pixbuf.scale(self.bg_middle, rect.width - bg_left_w * 2,
                                   self.bg_middle.get_height())
        draw_pixbuf(cr, self.cache_bg_pixbuf.get_cache(), rect.x + bg_left_w,
                    rect.y)
        draw_pixbuf(cr, self.bg_right, rect.x + rect.width - bg_left_w, rect.y)

        draw_pixbuf(cr, self.prompt_pixbuf, rect.x + self.padding_x, pixbuf_y)

        # draw text.
        text_rect = gtk.gdk.Rectangle(
            rect.x + self.prompt_pixbuf.get_width() + self.padding_x * 2,
            rect.y,
            rect.width - self.prompt_pixbuf.get_width() - self.padding_x * 3,
            rect.height)
        render_text(cr, self.prompt_text, text_rect,
                    app_theme.get_color("labelText").get_color(), 8)

        return True

    def set_infos(self, infos):
        temp_pixbuf, self.prompt_text = infos
        if temp_pixbuf:
            Tooltip.text(self, self.prompt_text)
            self.prompt_pixbuf = temp_pixbuf.scale_simple(
                16, 16, gtk.gdk.INTERP_BILINEAR)
            self.update_size()
class ProgressBar(gtk.Button):
    
    __gsignals__ = { 
        "value-changed" : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)),
                     }
    
    def __init__(self, value=100, lower=0, upper=100, step=5):
        gtk.Button.__init__(self)
        
        # Init data.
        self.__value = value
        self.__lower = lower
        self.__upper = upper
        self.__step = step
        self.drag_flag = False
        self.move_flag = False
        
        # Init DPixbufs.
        self.bg_dpixbuf = app_theme.get_pixbuf("scalebar/bg.png")
        
        self.point_dpixbuf = app_theme.get_pixbuf("scalebar/point_normal.png")
        self.point_width = self.point_dpixbuf.get_pixbuf().get_width()        
        
        # Init Dcolors.
        self.fg_left_dcolor = app_theme.get_color("progressBarLeft")
        self.fg_right_dcolor = app_theme.get_color("progressBarRight")
        
        # self.progressbar_tip = progressBarTip()
        
        # Init Sizes.
        self._value = lower
        self.padding_x = 0
        self.padding_y = 0
        self.progress_x = 0
        self.point_offset = 0

        self.fg_offset = self.bg_offset = 0
        self.default_height = self.bg_dpixbuf.get_pixbuf().get_height()
        
        # Init CachePixbufs
        self.bg_cache_pixbuf = CachePixbuf()
        self.fg_cache_pixbuf = CachePixbuf()
        
        
        self.set_size_request(-1, self.default_height)        
        
        # Init Events.
        self.add_events(gtk.gdk.ALL_EVENTS_MASK)
        self.connect("expose-event", self.on_expose_event)
        self.connect("button-press-event", self.on_button_press_event)
        self.connect("motion-notify-event", self.on_motion_notify_event)
        self.connect("button-release-event", self.on_button_release_event)
        # self.connect("enter-notify-event", self.on_enter_notify_event)
        # self.connect("leave-notify-event", self.on_leave_notify_event)
        
        
    def set_range(self, lower, upper):    
        self.__lower = lower
        self.__upper = upper
        
        self.queue_draw()
        
    @property        
    def progress_width(self):        
        return self.allocation.width - getattr(self, "point_width", 0)
    
    @property
    def virtual_width(self):
        return self.allocation.width
            
    def value_to_width(self, value):    
        return value / float(self.__upper) * self.progress_width
    
    def width_to_value(self, width):
        return width / float(self.progress_width) * self.__upper 
    
    @property
    def current_progress_width(self):
        return int(self.value_to_width(self.value))
    
    def get_size(self):
        rect = self.allocation
        return (rect.width, rect.height)    
    
    def emit_value_changed(self):        
        self.emit("value-changed", self.value)
    
    def update_progress_width(self, event, emit=False):
        progress_width = int(event.x - self.point_width)
        
        if progress_width < 0:
            progress_width = 0

        elif progress_width > self.progress_width:    
            progress_width = self.progress_width
            
        self.set_value(self.width_to_value(progress_width), emit)            
            
        self.queue_draw()
        
    def on_expose_event(self, widget, event):
        cr = widget.window.cairo_create()
        rect = widget.allocation
        
        self.draw_progress_bar(cr, rect)
        return True
    
    def on_enter_notify_event(self, widget, event):
        self.show_progressbar_tip(event)
        
    def on_leave_notify_event(self, widget, event):    
        self.hide_progressbar_tip()
    
    def adjust_event_coords(self, event):    
        _, y = get_widget_root_coordinate(self, pos_type=WIDGET_POS_TOP_LEFT)
        x, _ = event.get_root_coords()
        return x, y
    
    def show_progressbar_tip(self, event):
        self.progressbar_tip.move_to(*self.adjust_event_coords(event))
        self.progressbar_tip.show_all()
        
    def hide_progressbar_tip(self):    
        # self.progressbar_tip.hide_all()
        pass
        
    def draw_progress_bar(self, cr, rect):                    
        
        # Draw progressbar background.
        bg_height = self.bg_dpixbuf.get_pixbuf().get_height()
        self.bg_cache_pixbuf.scale(self.bg_dpixbuf.get_pixbuf(), self.virtual_width,
                                   bg_height)

        # bg_y = rect.y + (rect.height - bg_height) / 2
        draw_pixbuf(cr, self.bg_cache_pixbuf.get_cache(), rect.x + self.bg_offset, rect.y)
        
        # Draw progressbar foreground.
        if self.current_progress_width > 0:
            fg_height = self.default_height
            fg_y = rect.y
            lg_width = int(self.current_progress_width)
            pat = cairo.LinearGradient(rect.x + self.fg_offset, fg_y, rect.x + self.fg_offset + lg_width, fg_y)
            pat.add_color_stop_rgb(0.7, *color_hex_to_cairo(self.fg_left_dcolor.get_color()))
            pat.add_color_stop_rgb(1.0, *color_hex_to_cairo(self.fg_right_dcolor.get_color()))
            cr.set_operator(cairo.OPERATOR_OVER)
            cr.set_source(pat)
            cr.rectangle(rect.x + self.fg_offset, fg_y, lg_width, fg_height)
            cr.fill()
            
            with cairo_disable_antialias(cr):
                cr.set_line_width(1)
                cr.set_source_rgba(1, 1, 1, 0.5)
                cr.move_to(rect.x, fg_y + 1)                
                cr.rel_line_to(lg_width, 0)
                cr.stroke()
        
        # Draw point.
        point_y = rect.y + (rect.height - self.point_dpixbuf.get_pixbuf().get_height()) / 2
        
            
        draw_pixbuf(cr, self.point_dpixbuf.get_pixbuf(), 
                    rect.x + self.current_progress_width, 
                    point_y)
            
    def on_button_press_event(self, widget, event):
        self.update_progress_width(event, emit=True)        
        self.drag_flag = True
        self.queue_draw()
    
    def on_motion_notify_event(self, widget, event):
        # self.show_progressbar_tip(event)
        
        if self.drag_flag:
            self.update_progress_width(event, emit=False)
        self.queue_draw()

    def on_button_release_event(self, widget, event):
        self.drag_flag = False
        self.queue_draw()
        
    def get_value(self):    
        return self._value
    
    def set_value(self, value, emit=False):
        self._value = value
        if emit:
            self.emit_value_changed()
        self.queue_draw()
        
    value = property(get_value, set_value)
class HScalebar(gtk.HScale):
    
    def __init__(self, 
                 fg_dpixbuf=app_theme.get_pixbuf("scalebar/fg.png"),
                 bg_dpixbuf=app_theme.get_pixbuf("scalebar/bg.png"),
                 point_normal_dpixbuf = app_theme.get_pixbuf("scalebar/point_normal.png"),
                 point_hover_dpixbuf = app_theme.get_pixbuf("scalebar/point_hover.png"),
                 point_press_dpixbuf = app_theme.get_pixbuf("scalebar/point_press.png"),
                 ):
        
        super(HScalebar, self).__init__()
        self.set_draw_value(False)
        self.set_range(0, 100)
        self.fg_dpixbuf = fg_dpixbuf
        self.bg_dpixbuf = bg_dpixbuf
        self.point_normal_dpixbuf = point_normal_dpixbuf
        self.point_hover_dpixbuf = point_hover_dpixbuf
        self.point_press_dpixbuf = point_press_dpixbuf
        self.bottom_side = 0
        self.fg_cache_pixbuf = CachePixbuf()
        self.bg_cache_pixbuf = CachePixbuf()
        self.side_cache_pixbuf = CachePixbuf()
        
        self.set_size_request(-1, self.point_normal_dpixbuf.get_pixbuf().get_height())
        
        self.connect("expose-event", self.expose_h_scalebar)
        self.connect("button-press-event", self.press_volume_progressbar)
        
    def expose_h_scalebar(self, widget, event):    
        cr = widget.window.cairo_create()
        rect = widget.allocation
        
        # Init pixbuf.
        fg_pixbuf = self.fg_dpixbuf.get_pixbuf()
        bg_pixbuf = self.bg_dpixbuf.get_pixbuf()
        point_normal_pixbuf = self.point_normal_dpixbuf.get_pixbuf()
        # point_hover_pixbuf = self.point_hover_dpixbuf.get_pixbuf()
        # point_press_pixbuf = self.point_press_dpixbuf.get_pixbuf()
        
        # Init value.
        upper = self.get_adjustment().get_upper()
        lower = self.get_adjustment().get_lower()
        total_length = max(upper - lower, 1)
        
        point_width = point_normal_pixbuf.get_width()
        point_height = point_normal_pixbuf.get_height()
        x, y, w, h = rect.x + point_width / 2, rect.y, rect.width - point_width, rect.height
        
        line_height = bg_pixbuf.get_height()

        line_y = y + (point_height - line_height) / 2
        value = int((self.get_value() - lower) / total_length * w)
        
        
        # Draw background.
        self.fg_cache_pixbuf.scale(
            bg_pixbuf, w + point_width, line_height)
        draw_pixbuf(
            cr,
            self.fg_cache_pixbuf.get_cache(),
            rect.x, line_y)
        
        self.bg_cache_pixbuf.scale(
            fg_pixbuf, point_width / 2, line_height)
        draw_pixbuf(
            cr,
            self.bg_cache_pixbuf.get_cache(),
            rect.x, line_y)

        
        if value > 0:
            self.side_cache_pixbuf.scale(
                fg_pixbuf, value + point_width, line_height)
            draw_pixbuf(
                cr, 
                self.side_cache_pixbuf.get_cache(),
                rect.x, line_y)
            
        if value > 0:    
            draw_pixbuf(cr, point_normal_pixbuf, x + value - point_width / 2 + 2, y)    
        else:    
            draw_pixbuf(cr, point_normal_pixbuf, x + value - point_width / 2 - 1, y)
        
        return True
    
    
    def press_volume_progressbar(self, widget, event):
        # Init.
        if is_left_button(event):
            rect = widget.allocation
            lower = self.get_adjustment().get_lower()
            upper = self.get_adjustment().get_upper()
            point_width = self.point_normal_dpixbuf.get_pixbuf().get_width()
            
            self.set_value(lower + ((event.x - point_width / 2)) / (rect.width - point_width) * (upper - lower))
            self.queue_draw()
            
        return False    
Beispiel #14
0
class RadioListItem(TreeItem):
    def __init__(self, channel_info):
        TreeItem.__init__(self)
        self.index = 0
        self.column_index = 0
        self.side_padding = 5
        self.normal_item_height = 55
        self.highlight_item_height = 80
        self.item_height = self.normal_item_height
        self.item_width = LIST_WIDTH
        self.is_highlight = False
        self.channel_info = channel_info
        self.icon_width = self.icon_height = 45
        cover_path = DoubanCover.get_cover(channel_info, try_web=False)
        if cover_path:
            self.normal_pixbuf = gtk.gdk.pixbuf_new_from_file(cover_path)
        else:
            self.normal_pixbuf = app_theme.get_pixbuf(
                "radio/default_cover.png").get_pixbuf()
        self.update_size()

        self.animation_cache_pixbuf = CachePixbuf()
        self.animation_timeout = 100  # s
        self.animation_id = None
        self.active_size = 45

    def render_animation(self, cr, rect):
        self.animation_cache_pixbuf.scale(self.normal_pixbuf, self.active_size,
                                          self.active_size)
        animation_pixbuf = self.animation_cache_pixbuf.get_cache()
        icon_x = rect.x + (rect.width - self.active_size) / 2
        icon_y = rect.y + (rect.height - self.active_size) / 2
        draw_pixbuf(cr, animation_pixbuf, icon_x, icon_y)

    def update_animation(self):
        if self.is_hover:
            self.active_size += 2
            if self.active_size >= 55:
                self.active_size = 55
                return False
        else:
            self.active_size -= 2
            if self.active_size < 45:
                self.active_size = 45
                return False
        self.emit_redraw_request()
        return True

    def start_animation(self):
        gobject.timeout_add(self.animation_timeout, self.update_animation)

    @property
    def channel_id(self):
        return self.channel_info.get("id", "")

    def emit_redraw_request(self):
        if self.redraw_request_callback:
            self.redraw_request_callback(self)

    def update_size(self):
        self.channel_name = utils.xmlescape(self.channel_info.get("name", ""))
        __, self.name_h = get_content_size(self.channel_name, text_size=9)

        self.detail_info = "%s首歌曲 %s制作" % (
            self.channel_info.get("song_num"),
            utils.xmlescape(
                self.channel_info.get("creator", {}).get("name", "")))
        __, self.detail_h = get_content_size(self.detail_info, text_size=8)

        intro = utils.xmlescape(self.channel_info.get("intro", "").strip())
        hotsongs = utils.xmlescape(" ".join(
            self.channel_info.get("hot_songs")))
        self.channel_intro = intro or hotsongs
        __, self.intro_h = get_content_size(self.channel_intro, text_size=8)

    def render_content(self, cr, rect):
        if self.is_highlight:
            draw_single_mask(cr, rect.x + 1, rect.y, rect.width, rect.height,
                             "globalItemHighlight")
        elif self.is_select:
            draw_single_mask(cr, rect.x + 1, rect.y, rect.width, rect.height,
                             "globalItemSelect")
        elif self.is_hover:
            draw_single_mask(cr, rect.x + 1, rect.y, rect.width, rect.height,
                             "globalItemHover")

        if self.is_highlight:
            text_color = "#ffffff"
        else:
            text_color = app_theme.get_color("labelText").get_color()

        icon_pixbuf = self.normal_pixbuf
        icon_y = rect.y + (rect.height - self.icon_height) / 2
        padding_x = 10
        padding_y = 10

        animation_rect = gtk.gdk.Rectangle(rect.x + padding_x, icon_y,
                                           self.icon_width, self.icon_height)
        cr.save()
        cr.arc(animation_rect.x + animation_rect.width / 2,
               animation_rect.y + animation_rect.height / 2,
               animation_rect.width / 2, 0, 2 * math.pi)
        # cr.rectangle(animation_rect.x, animation_rect.y, animation_rect.width, animation_rect.height)
        cr.clip()
        # self.render_animation(cr, animation_rect)
        draw_pixbuf(cr, self.normal_pixbuf, rect.x + padding_x, icon_y)
        cr.restore()

        draw_text(cr,
                  self.channel_name,
                  rect.x + icon_pixbuf.get_width() + padding_x * 2,
                  rect.y + padding_y,
                  rect.width - icon_pixbuf.get_width() - padding_x * 3,
                  self.name_h,
                  text_color=text_color,
                  alignment=pango.ALIGN_LEFT,
                  text_size=10)

        if self.is_highlight:
            draw_text(cr,
                      self.channel_intro,
                      rect.x + icon_pixbuf.get_width() + padding_x * 2,
                      rect.y + padding_y * 2 + self.name_h,
                      rect.width - icon_pixbuf.get_width() - padding_x * 3,
                      self.intro_h,
                      text_color=text_color,
                      alignment=pango.ALIGN_LEFT,
                      text_size=8)

        draw_text(cr,
                  self.detail_info,
                  rect.x + icon_pixbuf.get_width() + padding_x * 2,
                  rect.y + (rect.height - self.detail_h - padding_y),
                  rect.width - icon_pixbuf.get_width() - padding_x * 3,
                  self.detail_h,
                  text_color=text_color,
                  alignment=pango.ALIGN_LEFT,
                  text_size=8)

    def get_height(self):
        if self.is_highlight:
            return self.highlight_item_height
        else:
            return self.normal_item_height

    def get_column_widths(self):
        return (self.item_width, )

    def unhover(self, column, offset_x, offset_y):
        self.is_hover = False
        # self.start_animation()
        self.emit_redraw_request()

    def hover(self, column, offset_x, offset_y):
        self.is_hover = True
        # self.start_animation()
        self.emit_redraw_request()

    def unselect(self):
        self.is_select = False
        self.emit_redraw_request()

    def select(self):
        self.is_select = True
        self.emit_redraw_request()

    def highlight(self):
        self.is_highlight = True
        self.is_select = False
        self.emit_redraw_request()

    def unhighlight(self):
        self.is_highlight = False
        self.is_select = False
        self.emit_redraw_request()

    def get_column_renders(self):
        return (self.render_content, )

    def __hash__(self):
        return hash(self.channel_info.get("id"))

    def __repr__(self):
        return "<RadioItem %s>" % self.channel_info.get("id")

    def __cmp__(self, other_item):
        if not other_item:
            return -1
        try:
            return cmp(self.channel_info, other_item.channel_info)
        except AttributeError:
            return -1

    def __eq__(self, other_item):
        try:
            return self.channel_info.get("id") == other_item.channel_info.get(
                "id")
        except:
            return False
class VolumeButton(gtk.Button):

    __gsignals__ = {
        "volume-state-changed":
        (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,
                                                      gobject.TYPE_PYOBJECT)),
    }

    def __init__(self,
                 value=100,
                 lower=0,
                 upper=100,
                 step=5,
                 progress_width=45,
                 auto_hide=True,
                 mini_mode=False):
        gtk.Button.__init__(self)

        # Init data.
        self.__value = value
        self.__lower = lower
        self.__upper = upper
        self.__step = step
        self.progress_width = progress_width
        self.mute_flag = False
        self.state_press_flag = False
        self.drag_flag = False
        self.drag_out_area = False
        self.hide_progress_flag = True
        self.current_progress_width = self.value_to_width(self.__value)
        self.icon_state = STATE_NORMAL
        self.auto_hide = auto_hide

        # Init DPixbufs.
        if mini_mode:
            self.volume_prefix = "mini_volume"
        else:
            self.volume_prefix = "volume"
        self.bg_dpixbuf = app_theme.get_pixbuf("%s/bg.png" %
                                               self.volume_prefix)
        self.fg_dpixbuf = app_theme.get_pixbuf("%s/fg.png" %
                                               self.volume_prefix)
        self.point_dpixbuf = app_theme.get_pixbuf("%s/point.png" %
                                                  self.volume_prefix)
        self.update_state_dpixbufs(self.get_state_name(self.__value))

        # Init Dcolors.
        self.fg_left_dcolor = app_theme.get_color("progressBarLeft")
        self.fg_right_dcolor = app_theme.get_color("progressBarRight")

        # Init Sizes.
        self.padding_x = 0
        self.padding_y = 0
        self.progress_x = 0
        self.state_icon_rect = gtk.gdk.Rectangle(
            self.padding_x, self.padding_y,
            self.normal_dpixbuf.get_pixbuf().get_width() - 2,
            self.normal_dpixbuf.get_pixbuf().get_height())

        self.point_width = self.point_dpixbuf.get_pixbuf().get_width()
        self.base_width = self.padding_x * 2 + self.normal_dpixbuf.get_pixbuf(
        ).get_width()
        self.expand_width = self.base_width + self.progress_width + self.progress_x + self.point_width
        self.default_height = self.padding_y * 2 + self.normal_dpixbuf.get_pixbuf(
        ).get_height()
        self.point_offset = self.state_icon_rect.x + self.state_icon_rect.width + self.progress_x - 2
        self.fg_offset = self.bg_offset = self.point_offset + self.point_width / 2

        # Init CachePixbufs
        self.bg_cache_pixbuf = CachePixbuf()
        self.fg_cache_pixbuf = CachePixbuf()

        # Init Events.
        self.add_events(gtk.gdk.ALL_EVENTS_MASK)
        self.connect("expose-event", self.on_expose_event)
        self.connect("scroll-event", self.on_scroll_event)
        self.connect("enter-notify-event", self.on_enter_notify_event)
        self.connect("leave-notify-event", self.on_leave_notify_event)
        self.connect("button-press-event", self.on_button_press_event)
        self.connect("motion-notify-event", self.on_motion_notify_event)
        self.connect("button-release-event", self.on_button_release_event)

        if self.auto_hide:
            if self.hide_progress_flag:
                self.set_size_request(self.base_width, self.default_height)
            else:
                self.set_size_request(self.expand_width, self.default_height)
        else:
            self.set_size_request(self.expand_width, self.default_height)

    def value_to_width(self, value):
        return value / float(self.__upper) * self.progress_width

    def get_size(self):
        if self.auto_hide:
            if self.hide_progress_flag:
                return (self.base_width, self.default_height)
        return (self.expand_width, self.default_height)

    def width_to_value(self, width):
        return width / float(self.progress_width) * self.__upper

    def update_state_by_value(self, emit=True):
        value = self.width_to_value(int(self.current_progress_width))
        state_name = self.get_state_name(value)
        self.update_state_dpixbufs(state_name, queue_draw=True)
        if emit:
            self.emit("volume-state-changed", self.get_value(), self.mute_flag)

    def update_progress_width(self, event, emit=False):
        self.current_progress_width = int(event.x - self.fg_offset)
        if self.current_progress_width < 0:
            self.current_progress_width = 0
        elif self.current_progress_width > self.progress_width:
            self.current_progress_width = self.progress_width
        self.update_state_by_value(emit=emit)
        self.queue_draw()

    def update_state_dpixbufs(self, name, queue_draw=False):
        self.normal_dpixbuf = app_theme.get_pixbuf("%s/%s_normal.png" %
                                                   (self.volume_prefix, name))
        self.hover_dpixbuf = app_theme.get_pixbuf("%s/%s_hover.png" %
                                                  (self.volume_prefix, name))
        self.press_dpixbuf = app_theme.get_pixbuf("%s/%s_press.png" %
                                                  (self.volume_prefix, name))

        if queue_draw:
            self.queue_draw()

    def get_state_name(self, value):
        if value == 0:
            state_name = "zero"
        elif 0 < value <= self.__upper * (1.0 / 3):
            state_name = "low"
        elif self.__upper * (1.0 / 3) < value <= self.__upper * (2.0 / 3):
            state_name = "medium"
        else:
            state_name = "high"
        return state_name

    def on_expose_event(self, widget, event):
        cr = widget.window.cairo_create()
        rect = widget.allocation

        self.draw_volume(cr, rect)
        return True

    def draw_volume(self, cr, rect):
        # Draw state icon.
        if self.icon_state == STATE_HOVER:
            pixbuf = self.hover_dpixbuf.get_pixbuf()
        elif self.icon_state == STATE_PRESS:
            pixbuf = self.press_dpixbuf.get_pixbuf()
        else:
            pixbuf = self.normal_dpixbuf.get_pixbuf()
        draw_pixbuf(cr, pixbuf, rect.x + self.padding_x,
                    rect.y + self.padding_y)

        if self.auto_hide:
            if not self.hide_progress_flag:
                self.draw_progress_bar(cr, rect)
        else:
            self.draw_progress_bar(cr, rect)

    def draw_progress_bar(self, cr, rect):

        # Draw progressbar background.
        bg_height = self.bg_dpixbuf.get_pixbuf().get_height()
        self.bg_cache_pixbuf.scale(self.bg_dpixbuf.get_pixbuf(),
                                   self.progress_width, bg_height)

        bg_y = rect.y + (rect.height - bg_height) / 2
        draw_pixbuf(cr, self.bg_cache_pixbuf.get_cache(),
                    rect.x + self.bg_offset, bg_y)

        # Draw progressbar foreground.
        if self.current_progress_width > 0:
            fg_height = self.fg_dpixbuf.get_pixbuf().get_height()
            # self.fg_cache_pixbuf.scale(self.fg_dpixbuf.get_pixbuf(),
            #                            int(self.current_progress_width),
            #                            fg_height)

            fg_y = rect.y + (rect.height - fg_height) / 2
            # draw_pixbuf(cr, self.fg_cache_pixbuf.get_cache(),  rect.x + self.fg_offset, fg_y)

            lg_width = int(self.current_progress_width)
            pat = cairo.LinearGradient(rect.x + self.fg_offset, fg_y,
                                       rect.x + self.fg_offset + lg_width,
                                       fg_y)
            pat.add_color_stop_rgb(
                0.6, *color_hex_to_cairo(self.fg_left_dcolor.get_color()))
            pat.add_color_stop_rgb(
                1.0, *color_hex_to_cairo(self.fg_right_dcolor.get_color()))
            cr.set_operator(cairo.OPERATOR_OVER)
            cr.set_source(pat)
            cr.rectangle(rect.x + self.fg_offset, fg_y, lg_width, fg_height)
            cr.fill()

            with cairo_disable_antialias(cr):
                cr.set_line_width(1)
                cr.set_source_rgba(1, 1, 1, 0.3)
                cr.rectangle(rect.x + self.fg_offset, fg_y, lg_width,
                             fg_height)
                cr.stroke()

        # Draw point.
        point_y = rect.y + (rect.height -
                            self.point_dpixbuf.get_pixbuf().get_height()) / 2
        draw_pixbuf(cr, self.point_dpixbuf.get_pixbuf(),
                    rect.x + self.point_offset + self.current_progress_width,
                    point_y)

    def on_enter_notify_event(self, widget, event):
        if self.auto_hide:
            self.hide_progress_flag = False
            self.set_size_request(self.expand_width, self.default_height)
            self.queue_draw()

    def hide_progressbar(self):
        self.hide_progress_flag = True
        self.set_size_request(self.base_width, self.default_height)
        self.icon_state = STATE_NORMAL
        set_cursor(self, None)
        self.queue_draw()

    def on_leave_notify_event(self, widget, event):
        if self.drag_flag:
            self.drag_out_area = True
        else:
            if self.auto_hide:
                self.hide_progressbar()

        set_cursor(widget, None)

    def pointer_in_state_icon(self, event):
        if self.state_icon_rect.x <= event.x <= self.state_icon_rect.x + self.state_icon_rect.width  and \
                self.state_icon_rect.y <= event.y <= self.state_icon_rect.y + self.state_icon_rect.height:
            return True
        return False

    def on_button_press_event(self, widget, event):
        if self.pointer_in_state_icon(event):
            self.state_press_flag = True
            self.icon_state = STATE_PRESS
            self.drag_flag = False
        else:
            self.update_progress_width(event, emit=True)
            self.state_press_flag = False
            self.drag_flag = True
            self.mute_flag = False

        self.queue_draw()

    def on_motion_notify_event(self, widget, event):
        if self.pointer_in_state_icon(event):
            self.icon_state = STATE_HOVER
            set_cursor(widget, None)
        else:
            self.icon_state = STATE_NORMAL
            set_cursor(widget, gtk.gdk.HAND2)

        if self.drag_flag:
            self.update_progress_width(event, emit=True)
        self.queue_draw()

    def on_button_release_event(self, widget, event):
        if self.drag_out_area:
            if self.auto_hide:
                self.hide_progressbar()
        self.drag_out_area = False

        if self.state_press_flag:
            if self.mute_flag:
                self.update_state_by_value(emit=False)
                self.mute_flag = False
            else:
                self.update_state_dpixbufs("mute")
                self.mute_flag = True

        self.emit("volume-state-changed", self.get_value(), self.mute_flag)

        self.icon_state = STATE_NORMAL
        self.state_press_flag = False
        self.drag_flag = False
        self.queue_draw()

    def get_value(self):
        return self.width_to_value(self.current_progress_width)

    def set_value(self, value, emit=True):
        self.current_progress_width = self.value_to_width(value)
        self.update_state_by_value(emit=emit)
        self.queue_draw()

    def set_mute(self):
        self.update_state_dpixbufs("mute")
        self.mute_flag = True
        self.queue_draw()

    def unset_mute(self):
        self.mute_flag = False
        self.queue_draw()

    def on_scroll_event(self, widget, event):
        self.mute_flag = False
        if event.direction == gtk.gdk.SCROLL_UP:
            self.increase_value()
        elif event.direction == gtk.gdk.SCROLL_DOWN:
            self.decrease_value()

    def increase_value(self):
        self.current_progress_width += self.value_to_width(self.__step)
        if self.current_progress_width > self.progress_width:
            self.current_progress_width = self.progress_width
        self.update_state_by_value()
        self.queue_draw()

    def decrease_value(self):
        self.current_progress_width -= self.value_to_width(self.__step)
        if self.current_progress_width < 0:
            self.current_progress_width = 0
        self.update_state_by_value()
        self.queue_draw()
Beispiel #16
0
class StartButton(gtk.Button):
    def __init__(self,                 
                 start_button_normal=app_theme.get_pixbuf("bottom_buttons/play_button_normal.png"),
                 start_button_hover=app_theme.get_pixbuf("bottom_buttons/play_button_hover.png"),
                 start_button_press=app_theme.get_pixbuf("bottom_buttons/play_button_press.png"),
                 pause_button_normal=app_theme.get_pixbuf("bottom_buttons/pause_button_normal.png"),
                 pause_button_hover=app_theme.get_pixbuf("bottom_buttons/pause_button_hover.png"),
                 pause_button_press=app_theme.get_pixbuf("bottom_buttons/pause_button_press.png"),
                 image_y_padding=-2):
        
        gtk.Button.__init__(self)
        self.image_y_padding = image_y_padding
        self.start_bool = True
        self.stop_bool = False
        self.start_button_normal = start_button_normal
        self.start_button_hover = start_button_hover
        self.start_button_press = start_button_press
        
        self.pause_button_normal = pause_button_normal
        self.pause_button_hover = pause_button_hover
        self.pause_button_press = pause_button_press
        
        self.connect("expose-event", self.expose_button)
        self.connect("clicked", self.clicked_button)
        
        self.cache_pixbuf = CachePixbuf()
        
    def clicked_button(self, widget):
        #self.set_start_bool(not self.start_bool)
        pass
                
    def set_start_bool(self, start_bool):    
        if not self.stop_bool:
            self.start_bool = start_bool            
            self.queue_draw()
            
    def set_stop_bool(self, stop_bool):
        self.stop_bool = stop_bool
            
    def expose_button(self, widget, event):
        cr = widget.window.cairo_create()
        rect = widget.allocation
        x,y,w,h = rect.x, rect.y, rect.width, rect.height
                    
        if widget.state == gtk.STATE_NORMAL:
            if self.start_bool:                
                image = self.start_button_normal.get_pixbuf()
            else:
                image = self.pause_button_normal.get_pixbuf()                
        elif widget.state == gtk.STATE_PRELIGHT:
            if self.start_bool:
                image = self.start_button_hover.get_pixbuf()
            else:    
                image = self.pause_button_hover.get_pixbuf()
        elif widget.state == gtk.STATE_ACTIVE:
            if self.start_bool:
                image = self.start_button_press.get_pixbuf()
            else:    
                image = self.pause_button_press.get_pixbuf()

        widget.set_size_request(image.get_width(), image.get_height())
        self.cache_pixbuf.scale(image, image.get_width(), image.get_height())        
        draw_pixbuf(cr, self.cache_pixbuf.get_cache(), widget.allocation.x, widget.allocation.y - self.image_y_padding)
        
        # Set widget size.
        propagate_expose(widget, event)
        return True
Beispiel #17
0
class IconEditArea(gtk.Layout):
    __gsignals__ = {
        "pixbuf-changed":
        (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT, ))
    }

    AREA_WIDTH = 300
    AREA_HEIGHT = 300
    DRAG_WIDTH = 10
    MIN_SIZE = 150

    POS_OUT = 0
    POS_IN_MOVE = 1
    POS_IN_DRAG = 2

    MODE_CAMERA = 0
    MODE_CAMERA_EDIT = 1
    MODE_EDIT = 2

    def __init__(self):
        super(IconEditArea, self).__init__()

        self.edit_area = gtk.EventBox()
        self.camera_area_vbox = gtk.VBox(False)
        self.camera_area = Webcam()
        self.camera_area_up = gtk.EventBox()
        self.camera_area_down = gtk.EventBox()
        self.camera_area_init_flag = False
        self.button_hbox = gtk.HBox(False)
        self.button_hbox_height = 40
        self.__widget_y = 92

        self.edit_area.set_size_request(self.AREA_WIDTH, self.AREA_HEIGHT)
        #self.camera_area.set_size_request(self.AREA_WIDTH, self.AREA_HEIGHT)
        self.camera_area_vbox.set_size_request(self.AREA_WIDTH,
                                               self.AREA_HEIGHT)
        self.camera_area.set_size_request(self.AREA_WIDTH, 225)
        #self.camera_area_up.set_size_request(self.AREA_WIDTH, 37)
        #self.camera_area_down.set_size_request(self.AREA_WIDTH, 37)
        self.button_hbox.set_size_request(self.AREA_WIDTH,
                                          self.button_hbox_height)

        self.button_zoom_in = ImageButton(
            app_theme.get_pixbuf("account/zoom_in.png"),
            app_theme.get_pixbuf("account/zoom_in.png"),
            app_theme.get_pixbuf("account/zoom_in.png"), _("zoom in"))
        self.button_zoom_out = ImageButton(
            app_theme.get_pixbuf("account/zoom_out.png"),
            app_theme.get_pixbuf("account/zoom_out.png"),
            app_theme.get_pixbuf("account/zoom_out.png"), _("zoom out"))
        self.button_camera = ImageButton(
            app_theme.get_pixbuf("account/camera.png"),
            app_theme.get_pixbuf("account/camera.png"),
            app_theme.get_pixbuf("account/camera.png"), _("Take a photo"))
        self.button_camera_again = ImageButton(
            app_theme.get_pixbuf("account/camera_again.png"),
            app_theme.get_pixbuf("account/camera_again.png"),
            app_theme.get_pixbuf("account/camera_again.png"), _("Try again"))

        self.button_zoom_in_align = tools.make_align(self.button_zoom_in,
                                                     xalign=0.5,
                                                     yalign=0.5)
        self.button_zoom_out_align = tools.make_align(self.button_zoom_out,
                                                      xalign=0.5,
                                                      yalign=0.5)
        self.button_camera_align = tools.make_align(self.button_camera,
                                                    xalign=0.5,
                                                    yalign=0.5)
        self.button_camera_again_align = tools.make_align(
            self.button_camera_again, xalign=0.5, yalign=0.5)

        self.button_zoom_in.connect("clicked", self.on_zoom_in_clicked_cb)
        self.button_zoom_out.connect("clicked", self.on_zoom_out_clicked_cb)
        self.button_camera.connect("clicked", self.on_camera_clicked_cb)
        self.button_camera_again.connect("clicked",
                                         self.on_camera_again_clicked_cb)

        self.box = gtk.VBox(False)
        self.box.pack_start(self.edit_area, False, False)
        #self.box.pack_start(self.button_hbox, False, False)
        #self.box.pack_start(tools.make_align(yalign=0.0, yscale=1.0))
        self.set_size(self.AREA_WIDTH, self.AREA_HEIGHT)
        self.set_size_request(self.AREA_WIDTH, self.AREA_HEIGHT)
        self.connect("expose-event", self.draw_frame_border)
        self.put(self.box, 0, 0)
        #self.put(self.button_hbox, 0, self.AREA_HEIGHT-self.button_hbox_height)

        self.edit_area.set_can_focus(True)
        self.edit_area.set_visible_window(False)
        self.edit_area.add_events(gtk.gdk.ALL_EVENTS_MASK)
        self.edit_area.connect("button-press-event", self.__on_button_press_cb)
        self.edit_area.connect("button-release-event",
                               self.__on_button_release_cb)
        self.edit_area.connect("motion-notify-event",
                               self.__on_motion_notify_cb)
        #self.edit_area.connect("leave-notify-event", self.__on_leave_notify_cb)
        self.edit_area.connect("expose-event", self.__expose_edit)

        self.camera_area_down.add_events(gtk.gdk.POINTER_MOTION_MASK)
        #self.camera_area.connect("motion-notify-event", self.__on_camera_motion_notify_cb)
        self.camera_area_down.connect("motion-notify-event",
                                      self.__on_camera_motion_notify_cb)
        self.camera_area_up.connect("expose-event", self.__on_camera_expose_cb)
        self.camera_area_down.connect("expose-event",
                                      self.__on_camera_expose_cb)
        self.camera_area_vbox.pack_start(self.camera_area_up)
        self.camera_area_vbox.pack_start(self.camera_area, False, False)
        self.camera_area_vbox.pack_start(self.camera_area_down)

        #panel_size = self.button_camera.get_size_request()
        #self.panel = Panel(panel_size[0], panel_size[1], gtk.WINDOW_POPUP)
        self.panel = Panel(self.AREA_WIDTH, self.button_hbox_height,
                           gtk.WINDOW_POPUP)
        self.panel_layout = gtk.Fixed()
        #self.panel_layout.put(self.button_camera_align, (self.AREA_WIDTH-panel_size[0])/2, 0)
        self.panel_layout.put(self.button_hbox, 0, 0)
        self.panel.add(self.panel_layout)
        self.panel.hide_panel()
        self.panel.connect("expose-event", self.__draw_panel_background)
        self.panel.connect("size-allocate", lambda w, e: w.queue_draw())

        #self.panel.connect("enter-notify-event", self.__on_camera_enter_notify_cb)
        self.panel.connect("leave-notify-event",
                           self.__on_camera_leave_notify_cb)
        self.camera_focus_flag = True

        self.__refresh_time_id = None
        self.__button_time_id = None
        self.current_mode = self.MODE_EDIT
        self.origin_pixbuf = None
        self.origin_pixbuf_width = 0
        self.origin_pixbuf_height = 0
        self.cache_pixbuf = CachePixbuf()
        self.border_color = "#000000"

        # cursor
        self.cursor = {
            self.POS_IN_DRAG: gtk.gdk.Cursor(gtk.gdk.BOTTOM_RIGHT_CORNER),
            self.POS_IN_MOVE: gtk.gdk.Cursor(gtk.gdk.FLEUR),
            self.POS_OUT: None
        }
        self.cursor_current = None

        self.press_point_coord = (0, 0)
        self.position = self.POS_OUT
        self.drag_flag = False
        self.move_flag = False
        #
        self.__show_button_flag = True
        self.__button_moving_flag = False
        #self.__refresh_flag = False

        # the pixbuf shown area
        self.pixbuf_offset_x = 0
        self.pixbuf_offset_y = 0
        self.pixbuf_offset_cmp_x = 0
        self.pixbuf_offset_cmp_y = 0
        self.pixbuf_x = 0
        self.pixbuf_y = 0
        self.pixbuf_w = self.AREA_WIDTH
        self.pixbuf_h = self.AREA_HEIGHT
        # the select box area
        self.edit_coord_x = 0
        self.edit_coord_y = 0
        self.edit_coord_w = self.AREA_WIDTH
        self.edit_coord_h = self.AREA_HEIGHT
        self.edit_coord_backup_x = 0
        self.edit_coord_backup_y = 0
        self.edit_coord_backup_w = self.AREA_WIDTH
        self.edit_coord_backup_h = self.AREA_HEIGHT

        self.drag_point_x = 0
        self.drag_point_y = 0
        self.__update_drag_point_coord()

    def draw_frame_border(self, widget, event):
        cr = widget.window.cairo_create()
        with cairo_disable_antialias(cr):
            cr.set_line_width(1)
            x, y, w, h = widget.allocation
            cr.set_source_rgb(*color_hex_to_cairo(TREEVIEW_BORDER_COLOR))
            cr.rectangle(x - 1, y - 1, w + 2, h + 2)
            cr.stroke()

    def on_camera_again_clicked_cb(self, button):
        self.set_camera_mode()

    def on_camera_clicked_cb(self, button):
        self.current_mode = self.MODE_CAMERA_EDIT
        drawable = self.camera_area.window
        colormap = drawable.get_colormap()
        pixbuf = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, 0, 8,
                                *drawable.get_size())
        pixbuf = pixbuf.get_from_drawable(drawable, colormap, 0, 0, 0, 0,
                                          *drawable.get_size())
        self.__edit_picture(pixbuf)
        container_remove_all(self.button_hbox)
        self.button_hbox.pack_start(self.button_zoom_in_align)
        self.button_hbox.pack_start(self.button_zoom_out_align)
        self.button_hbox.pack_start(self.button_camera_again_align)
        self.button_hbox.show_all()

    def on_zoom_in_clicked_cb(self, button):
        if self.pixbuf_w >= self.origin_pixbuf_width or self.pixbuf_h >= self.origin_pixbuf_height:
            print "has max size"
            button.set_sensitive(False)
            return
        width = int(self.pixbuf_w * 1.1)
        height = int(self.pixbuf_h * 1.1)
        if width >= self.origin_pixbuf_width:
            width = self.origin_pixbuf_width
        if height >= self.origin_pixbuf_height:
            height = self.origin_pixbuf_height
        self.cache_pixbuf.scale(self.origin_pixbuf, width, height)
        # count show area
        self.pixbuf_w = width
        self.pixbuf_h = height
        self.pixbuf_x = (self.AREA_WIDTH - width) / 2
        self.pixbuf_y = (self.AREA_HEIGHT - height) / 2
        if self.pixbuf_x < 0:
            self.pixbuf_offset_x -= self.pixbuf_x
            if self.pixbuf_offset_x + self.AREA_WIDTH > self.pixbuf_w:
                self.pixbuf_offset_x = self.pixbuf_w - self.AREA_WIDTH
            self.pixbuf_x = 0
        if self.pixbuf_y < 0:
            self.pixbuf_offset_y -= self.pixbuf_y
            if self.pixbuf_offset_y + self.AREA_HEIGHT > self.pixbuf_h:
                self.pixbuf_offset_y = self.pixbuf_h - self.AREA_HEIGHT
            self.pixbuf_y = 0
        self.__update_drag_point_coord()
        self.emit_changed()
        if self.pixbuf_w >= self.origin_pixbuf_width or self.pixbuf_h >= self.origin_pixbuf_height:
            button.set_sensitive(False)
        if not (self.pixbuf_w <= self.edit_coord_w or self.pixbuf_h <= self.edit_coord_h) \
                and not self.button_zoom_out.get_sensitive():
            self.button_zoom_out.set_sensitive(True)

    def on_zoom_out_clicked_cb(self, button):
        if self.edit_coord_w < self.MIN_SIZE or self.edit_coord_h < self.MIN_SIZE:
            self.edit_coord_w = self.edit_coord_h = self.MIN_SIZE
        if self.pixbuf_w <= self.edit_coord_w or self.pixbuf_h <= self.edit_coord_h:
            print "has min size"
            button.set_sensitive(False)
            return
        width = int(self.pixbuf_w * 0.9)
        height = int(self.pixbuf_h * 0.9)
        if height >= width and width <= self.edit_coord_w:
            height = int(float(height) / width * self.edit_coord_w)
            width = int(self.edit_coord_w)
        elif height < self.edit_coord_h:
            width = int(float(width) / height * self.edit_coord_h)
            height = int(self.edit_coord_h)
        self.cache_pixbuf.scale(self.origin_pixbuf, width, height)
        # count show area
        self.pixbuf_w = width
        self.pixbuf_h = height
        self.pixbuf_x = (self.AREA_WIDTH - width) / 2
        self.pixbuf_y = (self.AREA_HEIGHT - height) / 2
        # count pixbuf offset
        if self.pixbuf_x < 0:
            self.pixbuf_offset_x -= self.pixbuf_x
            if self.pixbuf_offset_x + self.AREA_WIDTH > self.pixbuf_w:
                self.pixbuf_offset_x = self.pixbuf_w - self.AREA_WIDTH
            self.pixbuf_x = 0
        if self.pixbuf_y < 0:
            self.pixbuf_offset_y -= self.pixbuf_y
            if self.pixbuf_offset_y + self.AREA_HEIGHT > self.pixbuf_h:
                self.pixbuf_offset_y = self.pixbuf_h - self.AREA_HEIGHT
            self.pixbuf_y = 0
        if self.pixbuf_x + self.pixbuf_w < self.AREA_WIDTH:
            self.pixbuf_offset_x = 0
        if self.pixbuf_y + self.pixbuf_h < self.AREA_HEIGHT:
            self.pixbuf_offset_y = 0
        # count edit area
        if self.edit_coord_x < self.pixbuf_x:
            self.edit_coord_x = self.pixbuf_x
        if self.edit_coord_y < self.pixbuf_y:
            self.edit_coord_y = self.pixbuf_y
        right_pos = min(self.pixbuf_x + self.pixbuf_w, self.AREA_WIDTH)
        bottom_pos = min(self.pixbuf_y + self.pixbuf_h, self.AREA_HEIGHT)
        if self.edit_coord_x + self.edit_coord_w > right_pos:
            self.edit_coord_x = right_pos - self.edit_coord_w
        if self.edit_coord_y + self.edit_coord_h > bottom_pos:
            self.edit_coord_y = bottom_pos - self.edit_coord_h
        self.__update_drag_point_coord()
        self.emit_changed()
        if self.pixbuf_w <= self.edit_coord_w or self.pixbuf_h <= self.edit_coord_h:
            button.set_sensitive(False)
        if not (self.pixbuf_w >= self.origin_pixbuf_width or self.pixbuf_h >= self.origin_pixbuf_height) \
                and not self.button_zoom_in.get_sensitive():
            self.button_zoom_in.set_sensitive(True)

    def __expose_edit(self, widget, event):
        pixbuf = self.cache_pixbuf.get_cache()
        if not pixbuf:
            return
        cr = widget.window.cairo_create()
        cr.set_source_pixbuf(pixbuf, self.pixbuf_x - self.pixbuf_offset_x,
                             self.pixbuf_y - self.pixbuf_offset_y)
        cr.paint()
        self.__draw_mask(cr, widget.allocation)
        self.__draw_frame(cr, widget.allocation)
        return True

    def __draw_frame(self, cr, allocation):
        with cairo_disable_antialias(cr):
            cr.set_line_width(1)
            cr.save()
            cr.set_dash((9, 3))
            cr.set_source_rgb(*color_hex_to_cairo(self.border_color))
            x = self.edit_coord_x
            y = self.edit_coord_y
            w = self.edit_coord_w
            h = self.edit_coord_h
            if x == 0:
                x = 1
            if y == 0:
                y = 1
            if x + w > self.AREA_WIDTH:
                w = self.AREA_WIDTH - x
            if y + h > self.AREA_HEIGHT:
                h = self.AREA_HEIGHT - y
            cr.rectangle(x, y, w, h)
            cr.stroke()

            cr.set_dash((3, 9))
            cr.set_source_rgb(1, 1, 1)
            cr.rectangle(x, y, w, h)
            cr.stroke()
            cr.restore()

            cr.set_source_rgb(*color_hex_to_cairo(self.border_color))
            cr.rectangle(self.drag_point_x, self.drag_point_y, self.DRAG_WIDTH,
                         self.DRAG_WIDTH)
            cr.stroke()

    def __draw_mask(self, cr, allocation):
        x, y, w, h = allocation
        x = 0
        y = 0
        # Draw left.
        if self.edit_coord_x > 0:
            cr.set_source_rgba(0, 0, 0, 0.5)
            cr.rectangle(x, y, self.edit_coord_x, h)
            cr.fill()

        # Draw top.
        if self.edit_coord_y > 0:
            cr.set_source_rgba(0, 0, 0, 0.5)
            cr.rectangle(x + self.edit_coord_x, y, w - self.edit_coord_x,
                         self.edit_coord_y)
            cr.fill()

        # Draw bottom.
        if self.edit_coord_y + self.edit_coord_h < h:
            cr.set_source_rgba(0, 0, 0, 0.5)
            cr.rectangle(x + self.edit_coord_x,
                         y + self.edit_coord_y + self.edit_coord_h,
                         w - self.edit_coord_x,
                         h - self.edit_coord_y - self.edit_coord_h)
            cr.fill()

        # Draw right.
        if self.edit_coord_x + self.edit_coord_w < w:
            cr.set_source_rgba(0, 0, 0, 0.5)
            cr.rectangle(x + self.edit_coord_x + self.edit_coord_w,
                         y + self.edit_coord_y,
                         w - self.edit_coord_x - self.edit_coord_w,
                         self.edit_coord_h)
            cr.fill()

    def set_pixbuf(self, pixbuf):
        if not pixbuf:
            self.cache_pixbuf.cache_pixbuf = None
            self.edit_area.queue_draw()
            self.emit_changed()
            self.button_zoom_in.set_sensitive(False)
            self.button_zoom_out.set_sensitive(False)
            return
        self.origin_pixbuf = pixbuf
        self.origin_pixbuf_width = w = pixbuf.get_width()
        self.origin_pixbuf_height = h = pixbuf.get_height()
        if h >= w:
            w = int(float(w) / h * self.AREA_HEIGHT)
            h = self.AREA_HEIGHT
            if w < self.MIN_SIZE:
                h = int(float(h) / w * self.MIN_SIZE)
                w = self.MIN_SIZE
            self.edit_coord_w = self.edit_coord_h = w
        else:
            h = int(float(h) / w * self.AREA_WIDTH)
            w = self.AREA_WIDTH
            if h < self.MIN_SIZE:
                w = int(float(w) / h * self.MIN_SIZE)
                h = self.MIN_SIZE
            self.edit_coord_w = self.edit_coord_h = h
        # count the offset coord
        self.pixbuf_offset_x = 0
        self.pixbuf_offset_y = 0
        self.pixbuf_x = 0
        self.pixbuf_y = 0
        self.pixbuf_w = w
        self.pixbuf_h = h
        if w < self.AREA_WIDTH:
            self.pixbuf_x = (self.AREA_WIDTH - w) / 2
        if h < self.AREA_HEIGHT:
            self.pixbuf_y = (self.AREA_HEIGHT - h) / 2
        # update select box coord
        self.edit_coord_x = self.pixbuf_x
        self.edit_coord_y = self.pixbuf_y
        self.cache_pixbuf.scale(pixbuf, w, h)
        ######
        self.edit_coord_w = self.edit_coord_h = self.MIN_SIZE
        self.edit_coord_x = self.edit_coord_y = (self.AREA_WIDTH -
                                                 self.MIN_SIZE) / 2
        ######
        self.drag_point_x = self.edit_coord_x + self.edit_coord_w - self.DRAG_WIDTH
        self.drag_point_y = self.edit_coord_y + self.edit_coord_h - self.DRAG_WIDTH
        self.edit_area.queue_draw()
        self.emit_changed()
        self.__update_button_sensitive()

    def emit_changed(self):
        pix = self.cache_pixbuf.get_cache()
        if pix:
            pix = pix.subpixbuf(
                int(self.edit_coord_x - self.pixbuf_x + self.pixbuf_offset_x),
                int(self.edit_coord_y - self.pixbuf_y + self.pixbuf_offset_y),
                int(self.edit_coord_w), int(self.edit_coord_h))
        self.emit("pixbuf-changed", pix)

    def get_pixbuf(self):
        return self.cache_pixbuf.get_cache()

    def set_cursor(self):
        if not self.edit_area.window:
            return
        if self.cursor_current != self.cursor[self.position]:
            self.cursor_current = self.cursor[self.position]
            self.edit_area.window.set_cursor(self.cursor_current)

    def __on_button_press_cb(self, widget, event):
        self.__update_position(event.x, event.y)
        if self.position == self.POS_IN_DRAG:
            self.drag_flag = True
        elif self.position == self.POS_IN_MOVE:
            self.move_flag = True
        self.press_point_coord = (event.x, event.y)
        self.edit_coord_backup_x = self.edit_coord_x
        self.edit_coord_backup_y = self.edit_coord_y
        self.edit_coord_backup_w = self.edit_coord_w
        self.edit_coord_backup_h = self.edit_coord_h

    def __on_button_release_cb(self, widget, event):
        self.drag_flag = False
        self.move_flag = False

    def __on_motion_notify_cb(self, widget, event):
        # if application window has not grab focus, return function
        if not self.camera_focus_flag:
            return
        x, y, w, h = widget.allocation
        if not self.drag_flag and not self.move_flag and \
                not self.panel.get_visible() and \
                y+self.AREA_HEIGHT-self.button_hbox_height<event.y<y+self.AREA_HEIGHT:
            self.slide_button_show(event)
            return
        pixbuf = self.cache_pixbuf.get_cache()
        if not pixbuf:
            return
        if not self.drag_flag and not self.move_flag:
            self.__update_position(event.x, event.y)
            self.set_cursor()
        right_pos = min(self.pixbuf_x + self.pixbuf_w, self.AREA_WIDTH)
        bottom_pos = min(self.pixbuf_y + self.pixbuf_h, self.AREA_HEIGHT)
        if self.move_flag:
            self.edit_coord_x = self.edit_coord_backup_x + event.x - self.press_point_coord[
                0]
            self.edit_coord_y = self.edit_coord_backup_y + event.y - self.press_point_coord[
                1]

            # check left
            if self.edit_coord_x < self.pixbuf_x:
                # move the pixbuf into canvas
                if self.pixbuf_w > self.AREA_WIDTH:
                    if self.pixbuf_offset_x > 0:
                        self.pixbuf_offset_x -= self.pixbuf_x - self.edit_coord_x
                    if self.pixbuf_offset_x < 0:
                        self.pixbuf_offset_x = 0
                self.edit_coord_x = self.pixbuf_x
            # check top
            if self.edit_coord_y < self.pixbuf_y:
                # move the pixbuf into canvas
                if self.pixbuf_h > self.AREA_HEIGHT:
                    if self.pixbuf_offset_y > 0:
                        self.pixbuf_offset_y -= self.pixbuf_y - self.edit_coord_y
                    if self.pixbuf_offset_y < 0:
                        self.pixbuf_offset_y = 0
                self.edit_coord_y = self.pixbuf_y
            # check right
            if self.edit_coord_x + self.edit_coord_w > right_pos:
                # move the pixbuf into canvas
                if self.pixbuf_w > self.AREA_WIDTH:
                    if self.pixbuf_offset_x + self.AREA_WIDTH < self.pixbuf_w:
                        self.pixbuf_offset_x += (
                            self.edit_coord_x +
                            self.edit_coord_w) - self.AREA_WIDTH
                    if self.pixbuf_offset_x + self.AREA_WIDTH > self.pixbuf_w:
                        self.pixbuf_offset_x = self.pixbuf_w - self.AREA_WIDTH
                self.edit_coord_x = right_pos - self.edit_coord_w
            # check bottom
            if self.edit_coord_y + self.edit_coord_h > bottom_pos:
                # move the pixbuf into canvas
                if self.pixbuf_h > self.AREA_HEIGHT:
                    if self.pixbuf_offset_y + self.AREA_HEIGHT < self.pixbuf_h:
                        self.pixbuf_offset_y += (
                            self.edit_coord_y +
                            self.edit_coord_h) - self.AREA_HEIGHT
                    if self.pixbuf_offset_y + self.AREA_HEIGHT > self.pixbuf_h:
                        self.pixbuf_offset_y = self.pixbuf_h - self.AREA_HEIGHT
                self.edit_coord_y = bottom_pos - self.edit_coord_h
        elif self.drag_flag:
            drag_offset = max(event.x - self.press_point_coord[0],
                              event.y - self.press_point_coord[1])
            self.edit_coord_h = self.edit_coord_w = self.edit_coord_backup_w + drag_offset
            if self.edit_coord_h < self.MIN_SIZE or self.edit_coord_w < self.MIN_SIZE:
                self.edit_coord_h = self.edit_coord_w = self.MIN_SIZE

            if self.edit_coord_x + self.edit_coord_w > right_pos:
                self.edit_coord_h = self.edit_coord_w = right_pos - self.edit_coord_x
            if self.edit_coord_y + self.edit_coord_h > bottom_pos:
                self.edit_coord_h = self.edit_coord_w = bottom_pos - self.edit_coord_y
            # check zoom_out button sensitive
            # if edit_area's size more than pixbuf size, then disable zoom_out button
            # else enable zoom_out button
            if not (self.pixbuf_w <= self.edit_coord_w
                    or self.pixbuf_h <= self.edit_coord_h):
                if not self.button_zoom_out.get_sensitive():
                    self.button_zoom_out.set_sensitive(True)
            else:
                if self.button_zoom_out.get_sensitive():
                    self.button_zoom_out.set_sensitive(False)
        self.__update_drag_point_coord()

    def __on_camera_motion_notify_cb(self, widget, event):
        if not self.camera_focus_flag:
            return
        x, y, w, h = widget.allocation
        #if not self.panel.get_visible() and \
        #y+self.AREA_HEIGHT-self.button_hbox_height<event.y<y+self.AREA_HEIGHT:
        if not self.panel.get_visible():
            if self.__refresh_time_id:
                gtk.timeout_remove(self.__refresh_time_id)
            if self.__button_time_id:
                gtk.timeout_remove(self.__button_time_id)
            self.__button_time_id = gobject.timeout_add(
                30, self.__slide_camera_button_show)
            #self.panel_layout.move(self.button_hbox, 0, self.button_hbox_height)
            x = event.x_root - event.x
            y = event.y_root - event.y - widget.allocation.y + self.AREA_HEIGHT - self.button_hbox_height
            self.set_win_pos(
                event.x_root - event.x - self.allocation.x, event.y_root -
                event.y - widget.allocation.y - self.allocation.y)
            self.panel.move(int(x), int(y) + self.button_hbox_height)
            self.panel.show_panel()

    def __draw_panel_background(self, widget, event):
        cr = widget.window.cairo_create()
        x, y, w, h = widget.allocation
        cr.set_source_rgb(0, 0, 0)
        cr.set_operator(OPERATOR_SOURCE)
        cr.paint()

        cr.set_source_rgba(0, 0, 0, 0.5)
        cr.rectangle(x, y, w, h)
        cr.paint()
        propagate_expose(widget, event)
        return True

    def __on_camera_expose_cb(self, widget, event):
        cr = widget.window.cairo_create()
        cr.set_source_rgb(0, 0, 0)
        cr.rectangle(0, 0, widget.allocation.width, widget.allocation.height)
        cr.fill()
        return True

    def __on_camera_enter_notify_cb(self, widget, event):
        pass

    def __on_camera_leave_notify_cb(self, widget, event):
        x, y, w, h = widget.allocation
        if (event.y_root == event.x_root == 0.0) or (x < event.x < x + w
                                                     and y < event.y < y + h):
            return
        if self.__button_time_id:
            gtk.timeout_remove(self.__button_time_id)
        self.__button_time_id = gobject.timeout_add(
            30, self.__slide_camera_button_hide)

    def __update_drag_point_coord(self):
        new_x = self.edit_coord_x + self.edit_coord_w - self.DRAG_WIDTH
        new_y = self.edit_coord_y + self.edit_coord_h - self.DRAG_WIDTH
        if self.drag_point_x != new_x or self.drag_point_y != new_y or\
                self.pixbuf_offset_cmp_x != self.pixbuf_offset_x or\
                self.pixbuf_offset_cmp_y != self.pixbuf_offset_y:
            self.drag_point_x = new_x
            self.drag_point_y = new_y
            self.pixbuf_offset_cmp_x = self.pixbuf_offset_x
            self.pixbuf_offset_cmp_y = self.pixbuf_offset_y
            self.emit_changed()
        self.edit_area.queue_draw()

    def __update_position(self, x, y):
        if self.drag_point_x <= x <= self.drag_point_x + self.DRAG_WIDTH and\
                self.drag_point_y <= y <= self.drag_point_y + self.DRAG_WIDTH:
            self.position = self.POS_IN_DRAG
        elif self.edit_coord_x <= x <= self.edit_coord_x + self.edit_coord_w and\
                self.edit_coord_y <= y <= self.edit_coord_y + self.edit_coord_h:
            self.position = self.POS_IN_MOVE
        else:
            self.position = self.POS_OUT

    def set_camera_mode(self):
        self.current_mode = self.MODE_CAMERA
        self.__camera_picture()
        self.__refresh_camera_button()

    def __camera_picture(self):
        self.set_pixbuf(None)
        if self.edit_area in self.box.get_children():
            self.box.remove(self.edit_area)
        if not self.camera_area_vbox in self.box.get_children():
            self.box.pack_start(self.camera_area_vbox, False, False)
            self.box.reorder_child(self.camera_area_vbox, 0)
        container_remove_all(self.button_hbox)
        self.button_hbox.pack_start(self.button_camera_align)
        self.button_hbox.show_all()
        self.show_all()
        try:
            if not self.camera_area.video_player:
                self.camera_area.create_video_pipeline()
            else:
                self.camera_start()
        except Exception, e:
            print e
class IconEditArea(gtk.Layout):
    __gsignals__ = {
        "pixbuf-changed": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,))}

    AREA_WIDTH = 300
    AREA_HEIGHT = 300
    DRAG_WIDTH = 10
    MIN_SIZE = 150

    POS_OUT = 0
    POS_IN_MOVE = 1
    POS_IN_DRAG = 2

    MODE_CAMERA = 0
    MODE_CAMERA_EDIT = 1
    MODE_EDIT = 2

    def __init__(self):
        super(IconEditArea, self).__init__()

        self.edit_area = gtk.EventBox()
        self.camera_area_vbox = gtk.VBox(False)
        self.camera_area = Webcam()
        self.camera_area_up = gtk.EventBox()
        self.camera_area_down = gtk.EventBox()
        self.camera_area_init_flag = False
        self.button_hbox = gtk.HBox(False)
        self.button_hbox_height = 40
        self.__widget_y = 92

        self.edit_area.set_size_request(self.AREA_WIDTH, self.AREA_HEIGHT)
        #self.camera_area.set_size_request(self.AREA_WIDTH, self.AREA_HEIGHT)
        self.camera_area_vbox.set_size_request(self.AREA_WIDTH, self.AREA_HEIGHT)
        self.camera_area.set_size_request(self.AREA_WIDTH, 225)
        #self.camera_area_up.set_size_request(self.AREA_WIDTH, 37)
        #self.camera_area_down.set_size_request(self.AREA_WIDTH, 37)
        self.button_hbox.set_size_request(self.AREA_WIDTH, self.button_hbox_height)

        self.button_zoom_in = ImageButton(
            app_theme.get_pixbuf("account/zoom_in.png"),
            app_theme.get_pixbuf("account/zoom_in.png"),
            app_theme.get_pixbuf("account/zoom_in.png"),
            _("zoom in"))
        self.button_zoom_out = ImageButton(
            app_theme.get_pixbuf("account/zoom_out.png"),
            app_theme.get_pixbuf("account/zoom_out.png"),
            app_theme.get_pixbuf("account/zoom_out.png"),
            _("zoom out"))
        self.button_camera = ImageButton(
            app_theme.get_pixbuf("account/camera.png"),
            app_theme.get_pixbuf("account/camera.png"),
            app_theme.get_pixbuf("account/camera.png"),
            _("Take a photo"))
        self.button_camera_again = ImageButton(
            app_theme.get_pixbuf("account/camera_again.png"),
            app_theme.get_pixbuf("account/camera_again.png"),
            app_theme.get_pixbuf("account/camera_again.png"),
            _("Try again"))

        self.button_zoom_in_align = tools.make_align(self.button_zoom_in, xalign=0.5, yalign=0.5)
        self.button_zoom_out_align = tools.make_align(self.button_zoom_out, xalign=0.5, yalign=0.5)
        self.button_camera_align = tools.make_align(self.button_camera, xalign=0.5, yalign=0.5)
        self.button_camera_again_align = tools.make_align(self.button_camera_again, xalign=0.5, yalign=0.5)

        self.button_zoom_in.connect("clicked", self.on_zoom_in_clicked_cb)
        self.button_zoom_out.connect("clicked", self.on_zoom_out_clicked_cb)
        self.button_camera.connect("clicked", self.on_camera_clicked_cb)
        self.button_camera_again.connect("clicked", self.on_camera_again_clicked_cb)

        self.box = gtk.VBox(False)
        self.box.pack_start(self.edit_area, False, False)
        #self.box.pack_start(self.button_hbox, False, False)
        #self.box.pack_start(tools.make_align(yalign=0.0, yscale=1.0))
        self.set_size(self.AREA_WIDTH, self.AREA_HEIGHT)
        self.set_size_request(self.AREA_WIDTH, self.AREA_HEIGHT)
        self.connect("expose-event", self.draw_frame_border)
        self.put(self.box, 0, 0)
        #self.put(self.button_hbox, 0, self.AREA_HEIGHT-self.button_hbox_height)

        self.edit_area.set_can_focus(True)
        self.edit_area.set_visible_window(False)
        self.edit_area.add_events(gtk.gdk.ALL_EVENTS_MASK)        
        self.edit_area.connect("button-press-event", self.__on_button_press_cb)
        self.edit_area.connect("button-release-event", self.__on_button_release_cb)
        self.edit_area.connect("motion-notify-event", self.__on_motion_notify_cb)
        #self.edit_area.connect("leave-notify-event", self.__on_leave_notify_cb)
        self.edit_area.connect("expose-event", self.__expose_edit)

        self.camera_area_down.add_events(gtk.gdk.POINTER_MOTION_MASK)
        #self.camera_area.connect("motion-notify-event", self.__on_camera_motion_notify_cb)
        self.camera_area_down.connect("motion-notify-event", self.__on_camera_motion_notify_cb)
        self.camera_area_up.connect("expose-event", self.__on_camera_expose_cb)
        self.camera_area_down.connect("expose-event", self.__on_camera_expose_cb)
        self.camera_area_vbox.pack_start(self.camera_area_up)
        self.camera_area_vbox.pack_start(self.camera_area, False, False)
        self.camera_area_vbox.pack_start(self.camera_area_down)

        #panel_size = self.button_camera.get_size_request()
        #self.panel = Panel(panel_size[0], panel_size[1], gtk.WINDOW_POPUP)
        self.panel = Panel(self.AREA_WIDTH, self.button_hbox_height, gtk.WINDOW_POPUP)
        self.panel_layout = gtk.Fixed()
        #self.panel_layout.put(self.button_camera_align, (self.AREA_WIDTH-panel_size[0])/2, 0)
        self.panel_layout.put(self.button_hbox, 0, 0)
        self.panel.add(self.panel_layout)
        self.panel.hide_panel()
        self.panel.connect("expose-event", self.__draw_panel_background)
        self.panel.connect("size-allocate", lambda w,e: w.queue_draw())

        #self.panel.connect("enter-notify-event", self.__on_camera_enter_notify_cb)
        self.panel.connect("leave-notify-event", self.__on_camera_leave_notify_cb)
        self.camera_focus_flag = True

        self.__refresh_time_id = None
        self.__button_time_id = None
        self.current_mode = self.MODE_EDIT
        self.origin_pixbuf = None
        self.origin_pixbuf_width = 0
        self.origin_pixbuf_height = 0
        self.cache_pixbuf = CachePixbuf()
        self.border_color = "#000000"

        # cursor
        self.cursor = {
            self.POS_IN_DRAG : gtk.gdk.Cursor(gtk.gdk.BOTTOM_RIGHT_CORNER),
            self.POS_IN_MOVE : gtk.gdk.Cursor(gtk.gdk.FLEUR),
            self.POS_OUT : None}
        self.cursor_current = None

        self.press_point_coord = (0, 0)
        self.position = self.POS_OUT
        self.drag_flag = False
        self.move_flag = False
        #
        self.__show_button_flag = True
        self.__button_moving_flag = False
        #self.__refresh_flag = False

        # the pixbuf shown area
        self.pixbuf_offset_x = 0
        self.pixbuf_offset_y = 0
        self.pixbuf_offset_cmp_x = 0
        self.pixbuf_offset_cmp_y = 0
        self.pixbuf_x = 0
        self.pixbuf_y = 0
        self.pixbuf_w = self.AREA_WIDTH
        self.pixbuf_h = self.AREA_HEIGHT
        # the select box area
        self.edit_coord_x = 0
        self.edit_coord_y = 0
        self.edit_coord_w = self.AREA_WIDTH
        self.edit_coord_h = self.AREA_HEIGHT
        self.edit_coord_backup_x = 0
        self.edit_coord_backup_y = 0
        self.edit_coord_backup_w = self.AREA_WIDTH
        self.edit_coord_backup_h = self.AREA_HEIGHT

        self.drag_point_x = 0
        self.drag_point_y = 0
        self.__update_drag_point_coord()

    def draw_frame_border(self, widget, event):
        cr = widget.window.cairo_create()
        with cairo_disable_antialias(cr):
            cr.set_line_width(1)
            x, y, w, h = widget.allocation
            cr.set_source_rgb(*color_hex_to_cairo(TREEVIEW_BORDER_COLOR))
            cr.rectangle(x-1, y-1, w+2, h+2)
            cr.stroke()

    def on_camera_again_clicked_cb(self, button):
        self.set_camera_mode()

    def on_camera_clicked_cb(self, button):
        self.current_mode = self.MODE_CAMERA_EDIT
        drawable = self.camera_area.window
        colormap = drawable.get_colormap()
        pixbuf = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, 0, 8, *drawable.get_size())
        pixbuf = pixbuf.get_from_drawable(drawable, colormap, 0, 0, 0, 0, *drawable.get_size()) 
        self.__edit_picture(pixbuf)
        container_remove_all(self.button_hbox)
        self.button_hbox.pack_start(self.button_zoom_in_align)
        self.button_hbox.pack_start(self.button_zoom_out_align)
        self.button_hbox.pack_start(self.button_camera_again_align)
        self.button_hbox.show_all()

    def on_zoom_in_clicked_cb(self, button):
        if self.pixbuf_w >= self.origin_pixbuf_width or self.pixbuf_h >= self.origin_pixbuf_height:
            print "has max size"
            button.set_sensitive(False)
            return
        width = int(self.pixbuf_w * 1.1)
        height = int(self.pixbuf_h * 1.1)
        if width >= self.origin_pixbuf_width:
            width = self.origin_pixbuf_width
        if height >= self.origin_pixbuf_height:
            height = self.origin_pixbuf_height
        self.cache_pixbuf.scale(self.origin_pixbuf, width, height)
        # count show area
        self.pixbuf_w = width
        self.pixbuf_h = height
        self.pixbuf_x = (self.AREA_WIDTH - width) / 2
        self.pixbuf_y = (self.AREA_HEIGHT - height) / 2
        if self.pixbuf_x < 0:
            self.pixbuf_offset_x -= self.pixbuf_x
            if self.pixbuf_offset_x + self.AREA_WIDTH > self.pixbuf_w:
                self.pixbuf_offset_x = self.pixbuf_w - self.AREA_WIDTH
            self.pixbuf_x = 0
        if self.pixbuf_y < 0:
            self.pixbuf_offset_y -= self.pixbuf_y
            if self.pixbuf_offset_y + self.AREA_HEIGHT > self.pixbuf_h:
                self.pixbuf_offset_y = self.pixbuf_h - self.AREA_HEIGHT
            self.pixbuf_y = 0
        self.__update_drag_point_coord()
        self.emit_changed()
        if self.pixbuf_w >= self.origin_pixbuf_width or self.pixbuf_h >= self.origin_pixbuf_height:
            button.set_sensitive(False)
        if not (self.pixbuf_w <= self.edit_coord_w or self.pixbuf_h <= self.edit_coord_h) \
                and not self.button_zoom_out.get_sensitive():
            self.button_zoom_out.set_sensitive(True)

    def on_zoom_out_clicked_cb(self, button):
        if self.edit_coord_w < self.MIN_SIZE or self.edit_coord_h < self.MIN_SIZE:
            self.edit_coord_w = self.edit_coord_h = self.MIN_SIZE
        if self.pixbuf_w <= self.edit_coord_w or self.pixbuf_h <= self.edit_coord_h:
            print "has min size"
            button.set_sensitive(False)
            return
        width = int(self.pixbuf_w * 0.9)
        height = int(self.pixbuf_h * 0.9)
        if height >= width and width <= self.edit_coord_w:
            height = int(float(height) / width * self.edit_coord_w)
            width = int(self.edit_coord_w)
        elif height < self.edit_coord_h:
            width = int(float(width) / height * self.edit_coord_h)
            height = int(self.edit_coord_h)
        self.cache_pixbuf.scale(self.origin_pixbuf, width, height)
        # count show area
        self.pixbuf_w = width
        self.pixbuf_h = height
        self.pixbuf_x = (self.AREA_WIDTH - width) / 2
        self.pixbuf_y = (self.AREA_HEIGHT - height) / 2
        # count pixbuf offset
        if self.pixbuf_x < 0:
            self.pixbuf_offset_x -= self.pixbuf_x
            if self.pixbuf_offset_x + self.AREA_WIDTH > self.pixbuf_w:
                self.pixbuf_offset_x = self.pixbuf_w - self.AREA_WIDTH
            self.pixbuf_x = 0
        if self.pixbuf_y < 0:
            self.pixbuf_offset_y -= self.pixbuf_y
            if self.pixbuf_offset_y + self.AREA_HEIGHT > self.pixbuf_h:
                self.pixbuf_offset_y = self.pixbuf_h - self.AREA_HEIGHT
            self.pixbuf_y = 0
        if self.pixbuf_x + self.pixbuf_w < self.AREA_WIDTH:
            self.pixbuf_offset_x = 0
        if self.pixbuf_y + self.pixbuf_h < self.AREA_HEIGHT:
            self.pixbuf_offset_y = 0
        # count edit area
        if self.edit_coord_x < self.pixbuf_x:
            self.edit_coord_x = self.pixbuf_x
        if self.edit_coord_y < self.pixbuf_y:
            self.edit_coord_y = self.pixbuf_y
        right_pos = min(self.pixbuf_x+self.pixbuf_w, self.AREA_WIDTH)
        bottom_pos = min(self.pixbuf_y+self.pixbuf_h, self.AREA_HEIGHT)
        if self.edit_coord_x + self.edit_coord_w > right_pos:
            self.edit_coord_x = right_pos - self.edit_coord_w
        if self.edit_coord_y + self.edit_coord_h > bottom_pos:
            self.edit_coord_y = bottom_pos - self.edit_coord_h
        self.__update_drag_point_coord()
        self.emit_changed()
        if self.pixbuf_w <= self.edit_coord_w or self.pixbuf_h <= self.edit_coord_h:
            button.set_sensitive(False)
        if not (self.pixbuf_w >= self.origin_pixbuf_width or self.pixbuf_h >= self.origin_pixbuf_height) \
                and not self.button_zoom_in.get_sensitive():
            self.button_zoom_in.set_sensitive(True)

    def __expose_edit(self, widget, event):
        pixbuf = self.cache_pixbuf.get_cache()
        if not pixbuf:
            return
        cr = widget.window.cairo_create()
        cr.set_source_pixbuf(pixbuf, self.pixbuf_x-self.pixbuf_offset_x, self.pixbuf_y-self.pixbuf_offset_y)
        cr.paint()
        self.__draw_mask(cr, widget.allocation)
        self.__draw_frame(cr, widget.allocation)
        return True

    def __draw_frame(self, cr, allocation):
        with cairo_disable_antialias(cr):
            cr.set_line_width(1)
            cr.save()
            cr.set_dash((9, 3))
            cr.set_source_rgb(*color_hex_to_cairo(self.border_color))
            x = self.edit_coord_x
            y = self.edit_coord_y
            w = self.edit_coord_w
            h = self.edit_coord_h
            if x == 0:
                x = 1
            if y == 0:
                y = 1
            if x + w > self.AREA_WIDTH:
                w = self.AREA_WIDTH- x
            if y + h > self.AREA_HEIGHT:
                h = self.AREA_HEIGHT- y
            cr.rectangle(x, y, w, h)
            cr.stroke()

            cr.set_dash((3, 9))
            cr.set_source_rgb(1, 1, 1)
            cr.rectangle(x, y, w, h)
            cr.stroke()
            cr.restore()

            cr.set_source_rgb(*color_hex_to_cairo(self.border_color))
            cr.rectangle(self.drag_point_x, self.drag_point_y, self.DRAG_WIDTH, self.DRAG_WIDTH)
            cr.stroke()

    def __draw_mask(self, cr, allocation):
        x, y, w, h = allocation
        x = 0
        y = 0
        # Draw left.
        if self.edit_coord_x > 0:
            cr.set_source_rgba(0, 0, 0, 0.5)
            cr.rectangle(x, y, self.edit_coord_x, h)
            cr.fill()

        # Draw top.
        if self.edit_coord_y > 0:
            cr.set_source_rgba(0, 0, 0, 0.5)
            cr.rectangle(x+self.edit_coord_x, y, w-self.edit_coord_x, self.edit_coord_y)
            cr.fill()

        # Draw bottom.
        if self.edit_coord_y + self.edit_coord_h < h:
            cr.set_source_rgba(0, 0, 0, 0.5)
            cr.rectangle(x+self.edit_coord_x, y+self.edit_coord_y+self.edit_coord_h,
                         w-self.edit_coord_x, h-self.edit_coord_y-self.edit_coord_h)
            cr.fill()

        # Draw right.
        if self.edit_coord_x + self.edit_coord_w < w:
            cr.set_source_rgba(0, 0, 0, 0.5)
            cr.rectangle(x+self.edit_coord_x+self.edit_coord_w, y+self.edit_coord_y,
                         w-self.edit_coord_x-self.edit_coord_w, self.edit_coord_h)
            cr.fill()

    def set_pixbuf(self, pixbuf):
        if not pixbuf:
            self.cache_pixbuf.cache_pixbuf = None
            self.edit_area.queue_draw()
            self.emit_changed()
            self.button_zoom_in.set_sensitive(False)
            self.button_zoom_out.set_sensitive(False)
            return
        self.origin_pixbuf = pixbuf
        self.origin_pixbuf_width = w = pixbuf.get_width()
        self.origin_pixbuf_height = h = pixbuf.get_height()
        if h >= w:
            w = int(float(w) / h * self.AREA_HEIGHT)
            h = self.AREA_HEIGHT
            if w < self.MIN_SIZE:
                h = int(float(h) / w * self.MIN_SIZE)
                w = self.MIN_SIZE
            self.edit_coord_w = self.edit_coord_h = w
        else:
            h = int(float(h) / w * self.AREA_WIDTH)
            w = self.AREA_WIDTH
            if h < self.MIN_SIZE:
                w = int(float(w) / h * self.MIN_SIZE)
                h = self.MIN_SIZE
            self.edit_coord_w = self.edit_coord_h = h
        # count the offset coord
        self.pixbuf_offset_x = 0
        self.pixbuf_offset_y = 0
        self.pixbuf_x = 0
        self.pixbuf_y = 0
        self.pixbuf_w = w
        self.pixbuf_h = h
        if w < self.AREA_WIDTH:
            self.pixbuf_x = (self.AREA_WIDTH - w) / 2
        if h < self.AREA_HEIGHT :
            self.pixbuf_y = (self.AREA_HEIGHT - h) / 2
        # update select box coord
        self.edit_coord_x = self.pixbuf_x
        self.edit_coord_y = self.pixbuf_y
        self.cache_pixbuf.scale(pixbuf, w, h)
        ######
        self.edit_coord_w = self.edit_coord_h = self.MIN_SIZE
        self.edit_coord_x = self.edit_coord_y = (self.AREA_WIDTH - self.MIN_SIZE) / 2
        ######
        self.drag_point_x = self.edit_coord_x + self.edit_coord_w - self.DRAG_WIDTH
        self.drag_point_y = self.edit_coord_y + self.edit_coord_h - self.DRAG_WIDTH
        self.edit_area.queue_draw()
        self.emit_changed()
        self.__update_button_sensitive()

    def emit_changed(self):
        pix = self.cache_pixbuf.get_cache()
        if pix:
            pix = pix.subpixbuf(int(self.edit_coord_x-self.pixbuf_x+self.pixbuf_offset_x),
                                int(self.edit_coord_y-self.pixbuf_y+self.pixbuf_offset_y),
                                int(self.edit_coord_w),
                                int(self.edit_coord_h))
        self.emit("pixbuf-changed", pix)

    def get_pixbuf(self):
        return self.cache_pixbuf.get_cache()

    def set_cursor(self):
        if not self.edit_area.window:
            return
        if self.cursor_current != self.cursor[self.position]:
            self.cursor_current = self.cursor[self.position]
            self.edit_area.window.set_cursor(self.cursor_current)

    def __on_button_press_cb(self, widget, event):
        self.__update_position(event.x, event.y)
        if self.position == self.POS_IN_DRAG:
            self.drag_flag = True
        elif self.position == self.POS_IN_MOVE:
            self.move_flag = True
        self.press_point_coord = (event.x, event.y)
        self.edit_coord_backup_x = self.edit_coord_x
        self.edit_coord_backup_y = self.edit_coord_y
        self.edit_coord_backup_w = self.edit_coord_w
        self.edit_coord_backup_h = self.edit_coord_h

    def __on_button_release_cb(self, widget, event):
        self.drag_flag = False
        self.move_flag = False

    def __on_motion_notify_cb(self, widget, event):
        # if application window has not grab focus, return function
        if not self.camera_focus_flag:
            return
        x, y, w, h = widget.allocation
        if not self.drag_flag and not self.move_flag and \
                not self.panel.get_visible() and \
                y+self.AREA_HEIGHT-self.button_hbox_height<event.y<y+self.AREA_HEIGHT:
            self.slide_button_show(event)
            return
        pixbuf = self.cache_pixbuf.get_cache()
        if not pixbuf:
            return
        if not self.drag_flag and not self.move_flag:
            self.__update_position(event.x, event.y)
            self.set_cursor()
        right_pos = min(self.pixbuf_x+self.pixbuf_w, self.AREA_WIDTH)
        bottom_pos = min(self.pixbuf_y+self.pixbuf_h, self.AREA_HEIGHT)
        if self.move_flag:
            self.edit_coord_x = self.edit_coord_backup_x + event.x - self.press_point_coord[0]
            self.edit_coord_y = self.edit_coord_backup_y + event.y - self.press_point_coord[1]

            # check left
            if self.edit_coord_x < self.pixbuf_x:
                # move the pixbuf into canvas
                if self.pixbuf_w > self.AREA_WIDTH:
                    if self.pixbuf_offset_x > 0:
                        self.pixbuf_offset_x -= self.pixbuf_x - self.edit_coord_x
                    if self.pixbuf_offset_x < 0:
                        self.pixbuf_offset_x = 0
                self.edit_coord_x = self.pixbuf_x
            # check top
            if self.edit_coord_y < self.pixbuf_y:
                # move the pixbuf into canvas
                if self.pixbuf_h > self.AREA_HEIGHT:
                    if self.pixbuf_offset_y > 0:
                        self.pixbuf_offset_y -= self.pixbuf_y - self.edit_coord_y
                    if self.pixbuf_offset_y < 0:
                        self.pixbuf_offset_y = 0
                self.edit_coord_y = self.pixbuf_y
            # check right
            if self.edit_coord_x + self.edit_coord_w > right_pos:
                # move the pixbuf into canvas
                if self.pixbuf_w > self.AREA_WIDTH:
                    if self.pixbuf_offset_x + self.AREA_WIDTH < self.pixbuf_w:
                        self.pixbuf_offset_x += (self.edit_coord_x + self.edit_coord_w) - self.AREA_WIDTH
                    if self.pixbuf_offset_x + self.AREA_WIDTH > self.pixbuf_w:
                        self.pixbuf_offset_x = self.pixbuf_w - self.AREA_WIDTH
                self.edit_coord_x = right_pos - self.edit_coord_w
            # check bottom
            if self.edit_coord_y + self.edit_coord_h > bottom_pos:
                # move the pixbuf into canvas
                if self.pixbuf_h > self.AREA_HEIGHT:
                    if self.pixbuf_offset_y + self.AREA_HEIGHT < self.pixbuf_h:
                        self.pixbuf_offset_y += (self.edit_coord_y + self.edit_coord_h) - self.AREA_HEIGHT
                    if self.pixbuf_offset_y + self.AREA_HEIGHT > self.pixbuf_h:
                        self.pixbuf_offset_y = self.pixbuf_h - self.AREA_HEIGHT
                self.edit_coord_y = bottom_pos - self.edit_coord_h
        elif self.drag_flag:
            drag_offset = max(event.x - self.press_point_coord[0],
                              event.y - self.press_point_coord[1])
            self.edit_coord_h = self.edit_coord_w = self.edit_coord_backup_w + drag_offset
            if self.edit_coord_h < self.MIN_SIZE or self.edit_coord_w < self.MIN_SIZE:
                self.edit_coord_h = self.edit_coord_w = self.MIN_SIZE

            if self.edit_coord_x + self.edit_coord_w > right_pos:
                self.edit_coord_h = self.edit_coord_w = right_pos - self.edit_coord_x
            if self.edit_coord_y + self.edit_coord_h > bottom_pos:
                self.edit_coord_h = self.edit_coord_w = bottom_pos - self.edit_coord_y
            # check zoom_out button sensitive
            # if edit_area's size more than pixbuf size, then disable zoom_out button
            # else enable zoom_out button
            if not (self.pixbuf_w <= self.edit_coord_w or self.pixbuf_h <= self.edit_coord_h):
                if not self.button_zoom_out.get_sensitive():
                    self.button_zoom_out.set_sensitive(True)
            else:
                if self.button_zoom_out.get_sensitive():
                    self.button_zoom_out.set_sensitive(False)
        self.__update_drag_point_coord()

    def __on_camera_motion_notify_cb(self, widget, event):
        if not self.camera_focus_flag:
            return
        x, y, w, h = widget.allocation
        #if not self.panel.get_visible() and \
                #y+self.AREA_HEIGHT-self.button_hbox_height<event.y<y+self.AREA_HEIGHT:
        if not self.panel.get_visible():
            if self.__refresh_time_id:
                gtk.timeout_remove(self.__refresh_time_id)
            if self.__button_time_id:
                gtk.timeout_remove(self.__button_time_id)
            self.__button_time_id = gobject.timeout_add(30, self.__slide_camera_button_show)
            #self.panel_layout.move(self.button_hbox, 0, self.button_hbox_height)
            x = event.x_root - event.x
            y = event.y_root - event.y - widget.allocation.y + self.AREA_HEIGHT - self.button_hbox_height
            self.set_win_pos(event.x_root - event.x - self.allocation.x,
                             event.y_root - event.y - widget.allocation.y - self.allocation.y)
            self.panel.move(int(x), int(y) + self.button_hbox_height)
            self.panel.show_panel()

    def __draw_panel_background(self, widget, event):
        cr = widget.window.cairo_create()
        x, y, w, h = widget.allocation
        cr.set_source_rgb(0, 0, 0)
        cr.set_operator(OPERATOR_SOURCE)
        cr.paint()

        cr.set_source_rgba(0, 0, 0, 0.5)
        cr.rectangle(x, y, w, h)
        cr.paint()
        propagate_expose(widget, event)
        return True

    def __on_camera_expose_cb(self, widget, event):
        cr = widget.window.cairo_create()
        cr.set_source_rgb(0, 0, 0)
        cr.rectangle(0, 0, widget.allocation.width, widget.allocation.height)
        cr.fill()
        return True

    def __on_camera_enter_notify_cb(self, widget, event):
        pass

    def __on_camera_leave_notify_cb(self, widget, event):
        x, y, w, h = widget.allocation
        if (event.y_root == event.x_root == 0.0) or (x < event.x < x+w and y < event.y < y+h):
            return
        if self.__button_time_id:
            gtk.timeout_remove(self.__button_time_id)
        self.__button_time_id = gobject.timeout_add(30, self.__slide_camera_button_hide)

    def __update_drag_point_coord(self):
        new_x = self.edit_coord_x + self.edit_coord_w - self.DRAG_WIDTH
        new_y = self.edit_coord_y + self.edit_coord_h - self.DRAG_WIDTH
        if self.drag_point_x != new_x or self.drag_point_y != new_y or\
                self.pixbuf_offset_cmp_x != self.pixbuf_offset_x or\
                self.pixbuf_offset_cmp_y != self.pixbuf_offset_y:
            self.drag_point_x = new_x
            self.drag_point_y = new_y
            self.pixbuf_offset_cmp_x = self.pixbuf_offset_x
            self.pixbuf_offset_cmp_y = self.pixbuf_offset_y
            self.emit_changed()
        self.edit_area.queue_draw()

    def __update_position(self, x, y):
        if self.drag_point_x <= x <= self.drag_point_x + self.DRAG_WIDTH and\
                self.drag_point_y <= y <= self.drag_point_y + self.DRAG_WIDTH:
            self.position = self.POS_IN_DRAG
        elif self.edit_coord_x <= x <= self.edit_coord_x + self.edit_coord_w and\
                self.edit_coord_y <= y <= self.edit_coord_y + self.edit_coord_h:
            self.position = self.POS_IN_MOVE
        else:
            self.position = self.POS_OUT

    def set_camera_mode(self):
        self.current_mode = self.MODE_CAMERA
        self.__camera_picture()
        self.__refresh_camera_button()

    def __camera_picture(self):
        self.set_pixbuf(None)
        if self.edit_area in self.box.get_children():
            self.box.remove(self.edit_area)
        if not self.camera_area_vbox in self.box.get_children():
            self.box.pack_start(self.camera_area_vbox, False, False)
            self.box.reorder_child(self.camera_area_vbox, 0)
        container_remove_all(self.button_hbox)
        self.button_hbox.pack_start(self.button_camera_align)
        self.button_hbox.show_all()
        self.show_all()
        try:
            if not self.camera_area.video_player:
                self.camera_area.create_video_pipeline()
            else:
                self.camera_start()
        except Exception, e:
            print e
Beispiel #19
0
class ProgressBar(gtk.Button):

    __gsignals__ = {
        "value-changed": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
                          (gobject.TYPE_PYOBJECT, )),
    }

    def __init__(self, value=100, lower=0, upper=100, step=5):
        gtk.Button.__init__(self)

        # Init data.
        self.__value = value
        self.__lower = lower
        self.__upper = upper
        self.__step = step
        self.drag_flag = False
        self.move_flag = False

        # Init DPixbufs.
        self.bg_dpixbuf = app_theme.get_pixbuf("scalebar/bg.png")

        self.point_dpixbuf = app_theme.get_pixbuf("scalebar/point_normal.png")
        self.point_width = self.point_dpixbuf.get_pixbuf().get_width()

        # Init Dcolors.
        self.fg_left_dcolor = app_theme.get_color("progressBarLeft")
        self.fg_right_dcolor = app_theme.get_color("progressBarRight")

        # self.progressbar_tip = progressBarTip()

        # Init Sizes.
        self._value = lower
        self.padding_x = 0
        self.padding_y = 0
        self.progress_x = 0
        self.point_offset = 0

        self.fg_offset = self.bg_offset = 0
        self.default_height = self.bg_dpixbuf.get_pixbuf().get_height()

        # Init CachePixbufs
        self.bg_cache_pixbuf = CachePixbuf()
        self.fg_cache_pixbuf = CachePixbuf()

        self.set_size_request(-1, self.default_height)

        # Init Events.
        self.add_events(gtk.gdk.ALL_EVENTS_MASK)
        self.connect("expose-event", self.on_expose_event)
        self.connect("button-press-event", self.on_button_press_event)
        self.connect("motion-notify-event", self.on_motion_notify_event)
        self.connect("button-release-event", self.on_button_release_event)
        # self.connect("enter-notify-event", self.on_enter_notify_event)
        # self.connect("leave-notify-event", self.on_leave_notify_event)

    def set_range(self, lower, upper):
        self.__lower = lower
        self.__upper = upper

        self.queue_draw()

    @property
    def progress_width(self):
        return self.allocation.width - getattr(self, "point_width", 0)

    @property
    def virtual_width(self):
        return self.allocation.width

    def value_to_width(self, value):
        return value / float(self.__upper) * self.progress_width

    def width_to_value(self, width):
        return width / float(self.progress_width) * self.__upper

    @property
    def current_progress_width(self):
        return int(self.value_to_width(self.value))

    def get_size(self):
        rect = self.allocation
        return (rect.width, rect.height)

    def emit_value_changed(self):
        self.emit("value-changed", self.value)

    def update_progress_width(self, event, emit=False):
        progress_width = int(event.x - self.point_width)

        if progress_width < 0:
            progress_width = 0

        elif progress_width > self.progress_width:
            progress_width = self.progress_width

        self.set_value(self.width_to_value(progress_width), emit)

        self.queue_draw()

    def on_expose_event(self, widget, event):
        cr = widget.window.cairo_create()
        rect = widget.allocation

        self.draw_progress_bar(cr, rect)
        return True

    def on_enter_notify_event(self, widget, event):
        self.show_progressbar_tip(event)

    def on_leave_notify_event(self, widget, event):
        self.hide_progressbar_tip()

    def adjust_event_coords(self, event):
        _, y = get_widget_root_coordinate(self, pos_type=WIDGET_POS_TOP_LEFT)
        x, _ = event.get_root_coords()
        return x, y

    def show_progressbar_tip(self, event):
        self.progressbar_tip.move_to(*self.adjust_event_coords(event))
        self.progressbar_tip.show_all()

    def hide_progressbar_tip(self):
        # self.progressbar_tip.hide_all()
        pass

    def draw_progress_bar(self, cr, rect):

        # Draw progressbar background.
        bg_height = self.bg_dpixbuf.get_pixbuf().get_height()
        self.bg_cache_pixbuf.scale(self.bg_dpixbuf.get_pixbuf(),
                                   self.virtual_width, bg_height)

        # bg_y = rect.y + (rect.height - bg_height) / 2
        draw_pixbuf(cr, self.bg_cache_pixbuf.get_cache(),
                    rect.x + self.bg_offset, rect.y)

        # Draw progressbar foreground.
        if self.current_progress_width > 0:
            fg_height = self.default_height
            fg_y = rect.y
            lg_width = int(self.current_progress_width)
            pat = cairo.LinearGradient(rect.x + self.fg_offset, fg_y,
                                       rect.x + self.fg_offset + lg_width,
                                       fg_y)
            pat.add_color_stop_rgb(
                0.7, *color_hex_to_cairo(self.fg_left_dcolor.get_color()))
            pat.add_color_stop_rgb(
                1.0, *color_hex_to_cairo(self.fg_right_dcolor.get_color()))
            cr.set_operator(cairo.OPERATOR_OVER)
            cr.set_source(pat)
            cr.rectangle(rect.x + self.fg_offset, fg_y, lg_width, fg_height)
            cr.fill()

            with cairo_disable_antialias(cr):
                cr.set_line_width(1)
                cr.set_source_rgba(1, 1, 1, 0.5)
                cr.move_to(rect.x, fg_y + 1)
                cr.rel_line_to(lg_width, 0)
                cr.stroke()

        # Draw point.
        point_y = rect.y + (rect.height -
                            self.point_dpixbuf.get_pixbuf().get_height()) / 2

        draw_pixbuf(cr, self.point_dpixbuf.get_pixbuf(),
                    rect.x + self.current_progress_width, point_y)

    def on_button_press_event(self, widget, event):
        self.update_progress_width(event, emit=True)
        self.drag_flag = True
        self.queue_draw()

    def on_motion_notify_event(self, widget, event):
        # self.show_progressbar_tip(event)

        if self.drag_flag:
            self.update_progress_width(event, emit=False)
        self.queue_draw()

    def on_button_release_event(self, widget, event):
        self.drag_flag = False
        self.queue_draw()

    def get_value(self):
        return self._value

    def set_value(self, value, emit=False):
        self._value = value
        if emit:
            self.emit_value_changed()
        self.queue_draw()

    value = property(get_value, set_value)