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
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()
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
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 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
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()
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
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
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)