def __init__(self): gtk.Window.__init__(self, gtk.WINDOW_POPUP) self.set_property("allow-shrink", True) self.set_skip_taskbar_hint(True) self.set_decorated(False) self.set_skip_pager_hint(True) self.set_app_paintable(True) self.set_colormap(gtk.gdk.Screen().get_rgba_colormap()) self.render_lyrics = RenderContextNew() self.bg_pixbuf = app_theme.get_pixbuf("lyric/bg.png").get_pixbuf() self.line_padding = 0.0 self.dock_drag_state = DRAG_NONE self.padding_x = self.padding_y = 10 self.old_x = self.old_y = self.old_width = 0 self.mouse_x = self.mouse_y = 0 self.raw_x, self.raw_y = self.get_position() self.mouse_over = False self.mouse_over_lyrics = False self.fade_in_size = 20.0 self.max_line_count = 2 self.active_lyric_surfaces = [None, None] self.inactive_lyric_surfaces = [None, None] self.lyrics_text = [_("DMusic"), "for Linux Deepin"] self.lyric_rects = [gtk.gdk.Rectangle(0, 0, 0, 0), gtk.gdk.Rectangle(0, 0, 0, 0)] self.lyrics_xpos = [0, 0] self.line_alignment = LINE_ALIGNMENT[config.get("lyrics", "double_line_align")] self.line_percentage = [0.0, 0.0] self.current_line = 0 self.time_source = 0 for i in range(self.get_line_count()): self.update_lyric_surface(i) width = self.adjust_window_height() self.set_default_size(600, int( width)) # Add events. self.add_events(gtk.gdk.BUTTON_PRESS_MASK | gtk.gdk.BUTTON_RELEASE_MASK | gtk.gdk.POINTER_MOTION_MASK | gtk.gdk.ENTER_NOTIFY_MASK | gtk.gdk.LEAVE_NOTIFY_MASK) self.connect("button-press-event", self.button_press) # TRY self.connect("button-release-event", self.button_release) self.connect("motion-notify-event", self.motion_notify) self.connect("enter-notify-event", self.enter_notify) self.connect("leave-notify-event", self.leave_notify) self.connect("expose-event", self.expose_before) self.connect("realize", self.on_realize_event) config.connect("config-changed", self.update_render_color) self.time_source = gobject.timeout_add(200, self.check_mouse_leave)
def __init__(self): super(DesktopLyricsSetting, self).__init__() self.render_lyrics = RenderContextNew() main_align = gtk.Alignment() main_align.set(1, 1, 0, 0) main_align.set_padding(20, 0, 0, 0) main_align.add(self.create_style_table()) self.pack_start(main_align, False, False) self.preview = gtk.EventBox() self.preview.set_visible_window(False) self.preview.set_size_request(-1, 135) preview_align = gtk.Alignment() preview_align.set(0.0, 0.0, 1.0, 1.0) preview_align.set_padding(0, 10, 5, 5) preview_align.add(self.preview) # self.pack_start(preview_align, False, True) # Signals. self.preview.connect("expose-event", self.draw_lyrics) self.font_name_combo_box.connect("item-selected", self.update_preview_font_name) self.font_type_combo_box.connect("item-selected", self.update_preview_font_type) self.font_size_spin.connect("value-changed", self.update_preview_font_size) self.line_number_combo_box.connect("item-selected", self.update_preview_line_number) self.single_align_combo_box.connect("item-selected", self.update_preview_single_align) self.double_align_combo_box.connect("item-selected", self.update_preview_double_align) self.outline_spin.connect("value-changed", self.update_preview_outline_width) self.blur_color_button.connect("color-select", self.update_blur_color) self.predefine_color_combo_box.connect("item-selected", self.update_preview_predefine_color) self.inactive_upper_color_button.connect("color-select", self.update_inactive_upper_color) self.inactive_middle_color_button.connect("color-select", self.update_inactive_middle_color) self.inactive_bottom_color_button.connect("color-select", self.update_inactive_bottom_color) self.active_upper_color_button.connect("color-select", self.update_active_upper_color) self.active_middle_color_button.connect("color-select", self.update_active_middle_color) self.active_bottom_color_button.connect("color-select", self.update_active_bottom_color)
def __init__(self): gtk.Window.__init__(self, gtk.WINDOW_POPUP) self.set_property("allow-shrink", True) self.set_skip_taskbar_hint(True) self.set_decorated(False) self.set_skip_pager_hint(True) self.set_app_paintable(True) self.set_colormap(gtk.gdk.Screen().get_rgba_colormap()) self.render_lyrics = RenderContextNew() self.bg_pixbuf = app_theme.get_pixbuf("lyric/bg.png").get_pixbuf() self.line_padding = 0.0 self.dock_drag_state = DRAG_NONE self.padding_x = self.padding_y = 10 self.old_x = self.old_y = self.old_width = 0 self.mouse_x = self.mouse_y = 0 self.raw_x, self.raw_y = self.get_position() self.mouse_over = False self.mouse_over_lyrics = False self.fade_in_size = 20.0 self.max_line_count = 2 self.active_lyric_surfaces = [None, None] self.inactive_lyric_surfaces = [None, None] self.lyrics_text = [_("DMusic"), "for Linux Deepin"] self.lyric_rects = [gtk.gdk.Rectangle(0, 0, 0, 0), gtk.gdk.Rectangle(0, 0, 0, 0)] self.lyrics_xpos = [0, 0] self.line_alignment = LINE_ALIGNMENT[config.get("lyrics", "double_line_align")] self.line_percentage = [0.0, 0.0] self.current_line = 0 self.time_source = 0 for i in range(self.get_line_count()): self.update_lyric_surface(i) width = self.adjust_window_height() self.set_default_size(600, int(width)) # Add events. self.add_events( gtk.gdk.BUTTON_PRESS_MASK | gtk.gdk.BUTTON_RELEASE_MASK | gtk.gdk.POINTER_MOTION_MASK | gtk.gdk.ENTER_NOTIFY_MASK | gtk.gdk.LEAVE_NOTIFY_MASK ) self.connect("button-press-event", self.button_press) # TRY self.connect("button-release-event", self.button_release) self.connect("motion-notify-event", self.motion_notify) self.connect("enter-notify-event", self.enter_notify) self.connect("leave-notify-event", self.leave_notify) self.connect("expose-event", self.expose_before) self.connect("realize", self.on_realize_event) config.connect("config-changed", self.update_render_color) self.time_source = gobject.timeout_add(200, self.check_mouse_leave)
class DesktopLyrics(gtk.Window): __gsignals__ = { "moved" : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)), "resized" : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)), "hide-bg" : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()), "show-bg" : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()), } def __init__(self): gtk.Window.__init__(self, gtk.WINDOW_POPUP) self.set_property("allow-shrink", True) self.set_skip_taskbar_hint(True) self.set_decorated(False) self.set_skip_pager_hint(True) self.set_app_paintable(True) self.set_colormap(gtk.gdk.Screen().get_rgba_colormap()) self.render_lyrics = RenderContextNew() self.bg_pixbuf = app_theme.get_pixbuf("lyric/bg.png").get_pixbuf() self.line_padding = 0.0 self.dock_drag_state = DRAG_NONE self.padding_x = self.padding_y = 10 self.old_x = self.old_y = self.old_width = 0 self.mouse_x = self.mouse_y = 0 self.raw_x, self.raw_y = self.get_position() self.mouse_over = False self.mouse_over_lyrics = False self.fade_in_size = 20.0 self.max_line_count = 2 self.active_lyric_surfaces = [None, None] self.inactive_lyric_surfaces = [None, None] self.lyrics_text = [_("DMusic"), "for Linux Deepin"] self.lyric_rects = [gtk.gdk.Rectangle(0, 0, 0, 0), gtk.gdk.Rectangle(0, 0, 0, 0)] self.lyrics_xpos = [0, 0] self.line_alignment = LINE_ALIGNMENT[config.get("lyrics", "double_line_align")] self.line_percentage = [0.0, 0.0] self.current_line = 0 self.time_source = 0 for i in range(self.get_line_count()): self.update_lyric_surface(i) width = self.adjust_window_height() self.set_default_size(600, int( width)) # Add events. self.add_events(gtk.gdk.BUTTON_PRESS_MASK | gtk.gdk.BUTTON_RELEASE_MASK | gtk.gdk.POINTER_MOTION_MASK | gtk.gdk.ENTER_NOTIFY_MASK | gtk.gdk.LEAVE_NOTIFY_MASK) self.connect("button-press-event", self.button_press) # TRY self.connect("button-release-event", self.button_release) self.connect("motion-notify-event", self.motion_notify) self.connect("enter-notify-event", self.enter_notify) self.connect("leave-notify-event", self.leave_notify) self.connect("expose-event", self.expose_before) self.connect("realize", self.on_realize_event) config.connect("config-changed", self.update_render_color) self.time_source = gobject.timeout_add(200, self.check_mouse_leave) def update_render_color(self, obj, selection, option, value): color_option = ["inactive_color_upper", " inactive_color_middle", "inactive_color_bottom", "active_color_upper", "active_color_middle", "active_color_bottom"] if selection == "lyrics" and option in color_option: self.update_font() if selection == "lyrics" and option == "status": status = config.getboolean("lyrics", "status") if not status: if self.time_source != 0: gobject.source_remove(self.time_source) else: lrc_mode = config.getint("lyrics", "mode") if lrc_mode == 1: self.time_source = gobject.timeout_add(200, self.check_mouse_leave) if selection == "lyrics" and option == "mode": lrc_mode = config.getint("lyrics", "mode") if lrc_mode != 1: if self.time_source != 0: gobject.source_remove(self.time_source) else: status = config.getboolean("lyrics", "status") if status: self.time_source = gobject.timeout_add(200, self.check_mouse_leave) if selection == "lyrics" and option == "font_name": self.set_font_name(value) if selection == "lyrics" and option == "font_size": self.set_font_size(int(value)) if selection == "lyrics" and option == "font_type": self.set_font_type(value) if selection == "lyrics" and option == "line_count": if value == "1": self.line_alignment = LINE_ALIGNMENT[config.get("lyrics", "single_line_align")] elif value == "2": self.line_alignment = LINE_ALIGNMENT[config.get("lyrics", "double_line_align")] self.line_count = int(value) self.update_font() if selection == "lyrics" and option in ["single_line_align", "double_line_align"]: self.line_alignment = LINE_ALIGNMENT[config.get("lyrics", option)] self.update_font() if selection == "lyrics" and option in ["outline_width", "blur_color"]: self.update_font() def get_render_color(self, active=False): if active: return [color_hex_to_cairo(config.get("lyrics", "active_color_upper")), color_hex_to_cairo(config.get("lyrics", "active_color_middle")), color_hex_to_cairo(config.get("lyrics", "active_color_bottom"))] else: return [color_hex_to_cairo(config.get("lyrics", "inactive_color_upper")), color_hex_to_cairo(config.get("lyrics", "inactive_color_middle")), color_hex_to_cairo(config.get("lyrics", "inactive_color_bottom"))] def get_locked(self): return config.getboolean("lyrics", "locked") def set_locked(self, locked=True): if locked: config.set("lyrics", "locked", "true") self.set_input_shape_mask(True) self.emit("hide-bg") self.queue_draw() else: config.set("lyrics", "locked", "false") self.set_input_shape_mask(False) def on_realize_event(self, widget): if self.get_locked(): self.set_input_shape_mask(True) def update_font(self): for i in range(self.get_line_count()): self.update_lyric_surface(i) self.queue_draw() x, y = self.get_position() w, h = self.get_size() rect = gtk.gdk.Rectangle(int(x), int(y), int(w), int(h)) self.move_resize(self, rect, DRAG_NONE) def set_dock_mode(self, value): if config.getboolean("lyrics", "dock_mode"): config.set("lyrics", "dock_mode", "false") self.set_type_hint(gtk.WINDOW_TYPE_HINT_NORMAL) else: config.set("lyrics", "dock_mode", "true") self.set_type_hint(gtk.WINDOW_TYPE_HINT_DOCK) def get_dock_mode(self): return config.getboolean("lyrics", "dock_mode") def get_line_count(self): return config.getint("lyrics", "line_count") def set_line_count(self, value): if value in [1, 2]: config.set("lyrics", "line_count", str(value)) def get_karaoke_mode(self): return config.getboolean("lyrics", "karaoke_mode") def set_karaoke_mode(self): if not self.get_karaoke_mode(): config.set("lyrics", "karaoke_mode", "true") else: config.set("lyrics", "karaoke_mode", "false") self.line_percentage = [0.0, 0.0] for i in range(self.get_line_count()): self.update_lyric_surface(i) self.queue_draw() def get_blur_radius(self): return config.getint("lyrics", "blur_radius") def set_blur_radius(self, value): config.set("lyrics", "blur_radius", str(value)) def get_translucent_on_mouse_over(self): return config.getboolean("lyrics", "translucent_on_mouse_over") def set_translucent_on_mouse_over(self, value): if config.getboolean("lyrics", "translucent_on_mouse_over"): config.set("lyrics", "translucent_on_mouse_over", "false") else: config.set("lyrics", "translucent_on_mouse_over", "true") def __paint_rect(self, cr, source, src_x, src_y, src_w, src_h, des_x, des_y, des_w, des_h): ''' paint rect. ''' cr.save() sw = float(des_w) / float(src_w) sh = float(des_h) / float(src_h) cr.translate(des_x, des_y) cr.rectangle(0, 0, des_w, des_h) cr.scale(sw, sh) cr.clip() cr.set_source_pixbuf(source, -src_x, -src_y) cr.paint() cr.restore() def draw_bg_pixbuf(self, widget, cr): ''' Paint window bg. ''' w, h = widget.get_size() BORDER_WIDTH = self.padding_x if self.is_composited(): cr.set_operator(cairo.OPERATOR_OVER) sw = self.bg_pixbuf.get_width() sh = self.bg_pixbuf.get_height() self.__paint_rect(cr, self.bg_pixbuf, 0, 0, BORDER_WIDTH, BORDER_WIDTH, 0, 0, BORDER_WIDTH, BORDER_WIDTH) self.__paint_rect(cr, self.bg_pixbuf, 0, sh - BORDER_WIDTH, BORDER_WIDTH, BORDER_WIDTH, 0, h - BORDER_WIDTH, BORDER_WIDTH, BORDER_WIDTH) self.__paint_rect(cr, self.bg_pixbuf, sw - BORDER_WIDTH, 0, BORDER_WIDTH, BORDER_WIDTH, w - BORDER_WIDTH, 0, BORDER_WIDTH, BORDER_WIDTH) self.__paint_rect(cr, self.bg_pixbuf, sw - BORDER_WIDTH, sh - BORDER_WIDTH, BORDER_WIDTH, BORDER_WIDTH, w - BORDER_WIDTH, h - BORDER_WIDTH, BORDER_WIDTH, BORDER_WIDTH) self.__paint_rect(cr, self.bg_pixbuf, 0, BORDER_WIDTH, BORDER_WIDTH, sh - BORDER_WIDTH * 2, 0, BORDER_WIDTH, BORDER_WIDTH, h - BORDER_WIDTH * 2) self.__paint_rect(cr, self.bg_pixbuf, sw - BORDER_WIDTH, BORDER_WIDTH, BORDER_WIDTH, sh - BORDER_WIDTH * 2, w - BORDER_WIDTH, BORDER_WIDTH, BORDER_WIDTH, h - BORDER_WIDTH * 2) self.__paint_rect(cr, self.bg_pixbuf, BORDER_WIDTH, 0, sw - BORDER_WIDTH * 2, BORDER_WIDTH, BORDER_WIDTH, 0, w - BORDER_WIDTH * 2, BORDER_WIDTH) self.__paint_rect(cr, self.bg_pixbuf, BORDER_WIDTH, sh - BORDER_WIDTH, sw - BORDER_WIDTH * 2, BORDER_WIDTH, BORDER_WIDTH, h - BORDER_WIDTH, w - BORDER_WIDTH * 2, BORDER_WIDTH) self.__paint_rect(cr, self.bg_pixbuf, BORDER_WIDTH, BORDER_WIDTH, sw - BORDER_WIDTH * 2, sh - BORDER_WIDTH * 2, BORDER_WIDTH, BORDER_WIDTH, w - BORDER_WIDTH * 2, h - BORDER_WIDTH * 2) else: widget.get_style().paint_box(widget.window, gtk.STATE_NORMAL, gtk.SHADOW_IN, None, widget.get_default_widget(), "buttondefalut", 0, 0, w, h) def draw_window_background(self, widget, event): # Init cr = widget.window.cairo_create() rect = widget.allocation # Clear color to transparent window. if self.is_composited(): cr.set_source_rgba(1.0, 1.0, 1.0, 0.0) cr.set_operator(cairo.OPERATOR_SOURCE) cr.paint() else: cr.set_operator(cairo.OPERATOR_SOURCE) cr.set_source_rgb(0.9, 0.9, 0.9) cr.rectangle(0, 0, rect.width, rect.height) cr.fill() if self.mouse_over and not self.get_locked(): self.draw_bg_pixbuf(widget, cr) return True def adjust_lyrics_height(self): font_height = self.render_lyrics.get_font_height() height = font_height * self.get_line_count() + (self.get_line_count() - 1) * self.line_padding + self.render_lyrics.get_outline_width() if self.get_blur_radius(): height += self.get_blur_radius() * 2.0 return height def adjust_lyric_xpos(self, line, percentage): smooth = True w, h = self.get_lyrics_size() if self.active_lyric_surfaces[line] != None: width = self.active_lyric_surfaces[line].get_width() else: width = 0 if w >= width: xpos = (w - width) * self.line_alignment[line] else: if not self.is_composited(): # self.get_dock_mode() smooth = False if smooth: if percentage * width < w / 2.0: xpos = 0 elif (1.0 - percentage) * width < w / 2.0: xpos = w - width else: xpos = w / 2.0 - width * percentage else: if percentage * width < w: xpos = 0 else: half_count = (percentage * width - w) / w + 1 xpos = -half_count * w if xpos < w - width: xpos = w - width if xpos != self.lyrics_xpos[line]: self.lyrics_xpos[line] = xpos return xpos def adjust_lyric_ypos(self): return self.padding_x def adjust_window_height(self): return self.adjust_lyrics_height() + self.padding_x * 2 def get_lyrics_size(self): width = self.allocation.width - self.padding_x * 2 height = self.adjust_lyrics_height() return (width, height) def get_edge_on_point(self, widget, event): rect = widget.allocation width, height = rect.width, rect.height if event.y >= 0 and event.y <= height: if event.x >=0 and event.x < self.padding_x: return gtk.gdk.WINDOW_EDGE_WEST if event.x >= width - self.padding_x and event.x < width: return gtk.gdk.WINDOW_EDGE_EAST def get_min_width(self): return MIN_WIDTH def adjust_move_coordinate(self, widget, x, y): screen = widget.get_screen() w, h = widget.get_size() screen_w, screen_h = screen.get_width(), screen.get_height() if x + w > screen_w: x = screen_w - w if y + h > screen_h: y = screen_h - h return (int(x), int(y)) def move_resize(self, widget, rect, drag_state): old_x, old_y = widget.get_position() old_w, old_h = widget.get_size() screen = widget.get_screen() screen_w, screen_h = screen.get_width(), screen.get_height() min_width = self.get_min_width() if drag_state == DRAG_EAST: new_x = max(0, rect.x) new_width = max(min(rect.width, screen_w - new_x), min_width) elif drag_state == DRAG_WEST: new_width = max(min(rect.width, rect.x + rect.width), min_width) new_x = max(0, min(rect.x, self.old_x + self.old_width - new_width)) else: new_x = max(0, min(rect.x, screen_w - rect.width)) new_width = max(rect.width, MIN_WIDTH) if rect.y + rect.height > screen_h: min_h = self.adjust_window_height() new_height = max(min_h, screen_h - rect.y) new_y = max (0, screen_h - new_height) else: new_y = max(0, rect.y) new_height = self.adjust_window_height() self.raw_x, self.raw_y = new_x, new_y rect = gtk.gdk.Rectangle(int(new_x), int(new_y), int(new_width), int(new_height)) self.emit("resized", rect) widget.resize(int(new_width), int(new_height)) widget.move(int(new_x), int(new_y)) widget.queue_draw() def button_press(self, widget, event): '''Button press callback.''' if event.button == 1 and not self.get_locked(): edge = self.get_edge_on_point(widget, event) if not self.get_dock_mode(): if edge == gtk.gdk.WINDOW_EDGE_EAST or edge == gtk.gdk.WINDOW_EDGE_WEST: widget.begin_resize_drag(edge, event.button, int(event.x_root), int(event.y_root), event.time) else: widget.begin_move_drag(event.button, int(event.x_root), int(event.y_root), event.time) else: self.old_width, _ = widget.get_size() self.old_x, self.old_y = widget.get_position() self.mouse_x, self.mouse_y = event.x_root, event.y_root if edge == gtk.gdk.WINDOW_EDGE_EAST: self.dock_drag_state = DRAG_EAST elif edge == gtk.gdk.WINDOW_EDGE_WEST: self.dock_drag_state = DRAG_WEST else: self.dock_drag_state = DRAG_MOVE return False def motion_notify(self, widget, event): x = max(self.old_x + (event.x_root - self.mouse_x), 0) y = max(self.old_y + (event.y_root - self.mouse_y), 0) width, height = widget.get_size() if self.dock_drag_state == DRAG_MOVE: new_x, new_y = self.adjust_move_coordinate(widget, x, y) widget.move(new_x, new_y) emit_rect = gtk.gdk.Rectangle(int(new_x), int(new_y), int(width), int(height) ) self.emit("moved", emit_rect) elif self.dock_drag_state == DRAG_EAST: rect = gtk.gdk.Rectangle(int(self.old_x), int(self.old_y), int(self.old_width + (event.x_root - self.mouse_x)), int(height)) self.move_resize(widget, rect, DRAG_EAST) elif self.dock_drag_state == DRAG_WEST: rect = gtk.gdk.Rectangle(int(x), int(self.old_y), int(self.old_width + self.old_x - x), int(height)) self.move_resize(widget, rect, DRAG_WEST) elif self.dock_drag_state == DRAG_NONE: edge = self.get_edge_on_point(widget, event) if edge == gtk.gdk.WINDOW_EDGE_EAST: cursor = gtk.gdk.RIGHT_SIDE widget.window.set_cursor(gtk.gdk.Cursor(cursor)) elif edge == gtk.gdk.WINDOW_EDGE_WEST: cursor = gtk.gdk.LEFT_SIDE widget.window.set_cursor(gtk.gdk.Cursor(cursor)) else: widget.window.set_cursor(None) return False def button_release(self, widget, event): x, y = widget.get_position() self.dock_drag_state = DRAG_NONE return False def enter_notify(self, widget, event): self.mouse_over = True self.emit("show-bg") widget.queue_draw() def leave_notify(self, widget, event): pass def expose_before(self, widget, event): cr = widget.window.cairo_create() self.draw_window_background(widget, event) self.draw_lyrics(cr) return True def draw_lyric_surface(self, lyrics): if not lyrics: return width, height = self.render_lyrics.get_pixel_size(lyrics) surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, int(width), int(height)) cr = cairo.Context(surface) cr.set_source_rgba(1.0, 1.0, 1.0, 0.0) cr.set_operator(cairo.OPERATOR_SOURCE) cr.paint() self.render_lyrics.paint_text(cr, lyrics, 0, 0) return surface def update_lyric_rects(self): for i in range(self.get_line_count()): self.update_lyric_rect(i) def update_lyric_rect(self, line): w = h = 0 x, y = self.get_position() if self.active_lyric_surfaces[line] != None: w = self.active_lyric_surfaces[line].get_width() h = self.active_lyric_surfaces[line].get_height() font_height = self.render_lyrics.get_font_height() self.lyric_rects[line] = gtk.gdk.Rectangle( int(x + self.adjust_lyric_xpos(line, self.line_percentage[line])), int(y + font_height * line + (line + 1) * self.line_padding), int(w), int(h)) def update_lyric_surface(self, line): self.render_lyrics.set_linear_color(self.get_render_color()) self.inactive_lyric_surfaces[line] = self.draw_lyric_surface(self.lyrics_text[line]) self.render_lyrics.set_linear_color(self.get_render_color(True)) self.active_lyric_surfaces[line] = self.draw_lyric_surface(self.lyrics_text[line]) self.update_lyric_rect(line) def create_text_mask(self, line, text_xpos, alpha): width, _ = self.get_lyrics_size() text_width = self.active_lyric_surfaces[line].get_width() if self.fade_in_size * 2 > width: self.fade_in_size = width / 2 if self.is_composited(): pattern = cairo.LinearGradient(self.padding_x, 0.0, self.padding_x + width, 0.0) # Set fade in on left edge. if text_xpos < self.padding_x: pattern.add_color_stop_rgba(0.0, 1.0, 1.0, 1.0, 0.0) loffset = 0.0 if self.padding_x - text_xpos < self.fade_in_size: loffset = float(self.padding_x - text_xpos) / float(width) else: loffset = float(self.fade_in_size) / float(width) pattern.add_color_stop_rgba(loffset, 1.0, 1.0, 1.0, alpha) else: pattern.add_color_stop_rgba(0.0, 1.0, 1.0, 1.0, alpha) # Set fade out on the right edge if text_xpos + text_width > self.padding_x + width: roffset = 0.0 if text_xpos + text_width - (self.padding_x + width) < self.fade_in_size: roffset = 1.0 - (text_xpos + text_width - (self.padding_x + width)) / width else: roffset = 1.0 - float(self.fade_in_size) / width pattern.add_color_stop_rgba(roffset, 0.0, 0.0, 0.0, alpha) pattern.add_color_stop_rgba(1.0, 0.0, 0.0, 0.0, 0.0) else: pattern.add_color_stop_rgba(1.0, 0.0, 0.0, 0.0, alpha) return pattern return None def draw_lyrics(self, cr): alpha = 0.99 font_height = self.render_lyrics.get_font_height() if self.is_composited() and self.get_locked() and self.mouse_over_lyrics and self.get_translucent_on_mouse_over(): alpha = 0.3 w, h = self.get_lyrics_size() ypos = self.adjust_lyric_ypos() if self.get_line_count() == 1: start = self.current_line end = start + 1 else: start = 0 end = self.max_line_count cr.save() cr.rectangle(self.padding_x, self.padding_y, w, h) cr.clip() cr.set_operator(cairo.OPERATOR_OVER) try: for line in range(start, end): percentage = self.line_percentage[line] if self.active_lyric_surfaces[line] is not None and self.inactive_lyric_surfaces[line] is not None: width = self.active_lyric_surfaces[line].get_width() height = self.active_lyric_surfaces[line].get_height() xpos = self.adjust_lyric_xpos(line, percentage) xpos += self.padding_x text_mask = self.create_text_mask(line, xpos, alpha) cr.save() cr.rectangle(xpos, ypos, width * percentage, height) cr.clip() cr.set_source_surface(self.active_lyric_surfaces[line], xpos, ypos) if text_mask: cr.mask(text_mask) else: cr.paint_with_alpha(alpha) cr.restore() cr.save() cr.rectangle(xpos + width * percentage, ypos, width * (1.0 - percentage), height) cr.clip() cr.set_source_surface(self.inactive_lyric_surfaces[line], xpos, ypos) if text_mask: cr.mask(text_mask) else: cr.paint_with_alpha(alpha) cr.restore() ypos += font_height * ( 1 + self.line_padding) cr.restore() except: pass def set_input_shape_mask(self, disable_input): if self.get_property("visible"): if disable_input: region = gtk.gdk.Region() self.window.input_shape_combine_region(region, 0, 0) else: self.window.input_shape_combine_region(self.window.get_visible_region(), 0, 0) def point_in_rect(self, x, y, rect): return rect.x <= x < rect.x + rect.width and rect.y <= y < rect.y + rect.height def check_mouse_leave(self): root_window = gtk.gdk.get_default_root_window() screen_h , _ = root_window.get_size() rel_x, rel_y = root_window.get_pointer()[:2] x, y = self.get_position() mouse_over_lyrics = False width, height = self.get_size() if y < 40: height += 40 else: y -= 40 height += 40 rect = gtk.gdk.Rectangle(int(x), int(y), int(width), int(height)) if self.dock_drag_state == DRAG_NONE and not self.point_in_rect(rel_x, rel_y, rect): self.mouse_over = False self.emit("hide-bg") self.queue_draw() for lyric_rect in self.lyric_rects: if self.point_in_rect(rel_x, rel_y, lyric_rect): mouse_over_lyrics = True break if self.mouse_over_lyrics != mouse_over_lyrics: self.mouse_over_lyrics = mouse_over_lyrics self.queue_draw() return True def set_line_percentage(self, line, percentage): if not self.get_karaoke_mode(): return if line < 0 or line >= self.max_line_count: return if percentage == self.line_percentage[line]: return old_percentage = self.line_percentage[line] self.line_percentage[line] = percentage if self.is_composited() and percentage != old_percentage: old_x = self.adjust_lyric_xpos(line, old_percentage) new_x = self.adjust_lyric_xpos(line, percentage) if old_x != new_x: pass self.queue_draw() def set_current_line(self, line): if 0 <= line <= self.get_line_count(): self.current_line = line self.queue_draw() def set_current_percentage(self, percentage): self.set_line_percentage(self.current_line, percentage) def set_line_alignment(self, line, alignment): if line < 0 or line > self.get_line_count(): return if alignment < 0.0: alignment = 0.0 elif alignment > 1.0: alignment = 1.0 self.line_alignment[line] = alignment self.update_lyric_rect(line) self.queue_draw() def set_lyric(self, line, lyric): self.percentage = 0.0 self.lyrics_text[line] = lyric self.update_lyric_surface(line) self.queue_draw() def set_font_size(self, value): self.render_lyrics.set_font_size(value) self.update_font() def get_font_size(self): return self.render_lyrics.get_font_size() def set_font_name(self, font_name): self.render_lyrics.set_font_name(font_name) self.update_font() def set_font_type(self, font_type): self.render_lyrics.set_font_type(font_type) self.update_font()
class DesktopLyricsSetting(gtk.VBox): def __init__(self): super(DesktopLyricsSetting, self).__init__() self.render_lyrics = RenderContextNew() main_align = gtk.Alignment() main_align.set(1, 1, 0, 0) main_align.set_padding(20, 0, 0, 0) main_align.add(self.create_style_table()) self.pack_start(main_align, False, False) self.preview = gtk.EventBox() self.preview.set_visible_window(False) self.preview.set_size_request(-1, 135) preview_align = gtk.Alignment() preview_align.set(0.0, 0.0, 1.0, 1.0) preview_align.set_padding(0, 10, 5, 5) preview_align.add(self.preview) # self.pack_start(preview_align, False, True) # Signals. self.preview.connect("expose-event", self.draw_lyrics) self.font_name_combo_box.connect("item-selected", self.update_preview_font_name) self.font_type_combo_box.connect("item-selected", self.update_preview_font_type) self.font_size_spin.connect("value-changed", self.update_preview_font_size) self.line_number_combo_box.connect("item-selected", self.update_preview_line_number) self.single_align_combo_box.connect("item-selected", self.update_preview_single_align) self.double_align_combo_box.connect("item-selected", self.update_preview_double_align) self.outline_spin.connect("value-changed", self.update_preview_outline_width) self.blur_color_button.connect("color-select", self.update_blur_color) self.predefine_color_combo_box.connect("item-selected", self.update_preview_predefine_color) self.inactive_upper_color_button.connect("color-select", self.update_inactive_upper_color) self.inactive_middle_color_button.connect("color-select", self.update_inactive_middle_color) self.inactive_bottom_color_button.connect("color-select", self.update_inactive_bottom_color) self.active_upper_color_button.connect("color-select", self.update_active_upper_color) self.active_middle_color_button.connect("color-select", self.update_active_middle_color) self.active_bottom_color_button.connect("color-select", self.update_active_bottom_color) config.connect("config-changed", self.on_config_changed) def on_config_changed(self, obj, selection, option, value): if selection == "lyrics" and option == "line_count": value = int(value) - 1 index = self.line_number_combo_box.get_select_index() if index != value: self.line_number_combo_box.set_select_index(value) def get_render_color(self, active=False): if active: return [color_hex_to_cairo(config.get("lyrics", "active_color_upper")), color_hex_to_cairo(config.get("lyrics", "active_color_middle")), color_hex_to_cairo(config.get("lyrics", "active_color_bottom"))] else: return [color_hex_to_cairo(config.get("lyrics", "inactive_color_upper")), color_hex_to_cairo(config.get("lyrics", "inactive_color_middle")), color_hex_to_cairo(config.get("lyrics", "inactive_color_bottom"))] def draw_lyric_surface(self, lyrics, active=False): if not lyrics: return None self.render_lyrics.set_linear_color(self.get_render_color(active)) width, height = self.render_lyrics.get_pixel_size(lyrics) surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, int(width), int(height)) cr = cairo.Context(surface) cr.set_source_rgba(1.0, 1.0, 1.0, 0.0) cr.set_operator(cairo.OPERATOR_SOURCE) cr.paint() self.render_lyrics.paint_text(cr, lyrics, 0, 0) return surface def update_preview_font_name(self, widget, label, allocated_data, index): config.set("lyrics", "font_name", label) def update_preview_font_type(self, widget, label, allocated_data, index): config.set("lyrics", "font_type", allocated_data) def update_preview_font_size(self, widget, value): config.set("lyrics", "font_size", str(value)) def update_preview_line_number(self, widget, label, allocated_data, index): if allocated_data == 1: switch_tab(self.line_align_hbox, self.single_align_combo_box) else: switch_tab(self.line_align_hbox, self.double_align_combo_box) config.set("lyrics", "line_count", str(allocated_data)) def update_preview_single_align(self, widget, label, allocated_data, index): config.set("lyrics", "single_line_align", allocated_data) def update_preview_double_align(self, widget, label, allocated_data, index): config.set("lyrics", "double_line_align", allocated_data) def update_preview_outline_width(self, widget, value): config.set("lyrics", "outline_width", str(value)) def update_blur_color(self, widget, value): config.set("lyrics", "blur_color", str(value)) def update_preview_predefine_color(self, widget, label, allocated_data, index): values = PREDEFINE_COLORS[allocated_data] config.set("lyrics", "predefine_color", allocated_data) config.set("lyrics", "inactive_color_upper", values[0]) config.set("lyrics", "inactive_color_middle", values[1]) config.set("lyrics", "inactive_color_bottom", values[2]) config.set("lyrics", "active_color_upper", values[3]) config.set("lyrics", "active_color_middle", values[4]) config.set("lyrics", "active_color_bottom", values[5]) self.inactive_upper_color_button.set_color(values[0]) self.inactive_middle_color_button.set_color(values[1]) self.inactive_bottom_color_button.set_color(values[2]) self.active_upper_color_button.set_color(values[3]) self.active_middle_color_button.set_color(values[4]) self.active_bottom_color_button.set_color(values[5]) def update_inactive_upper_color(self, widget, color): config.set("lyrics", "inactive_color_upper", color) def update_inactive_middle_color(self, widget, color): config.set("lyrics", "inactive_color_middle", color) def update_inactive_bottom_color(self, widget, color): config.set("lyrics", "inactive_color_bottom", color) def update_active_upper_color(self, widget, color): config.set("lyrics", "active_color_upper", color) def update_active_middle_color(self, widget, color): config.set("lyrics", "active_color_middle", color) def update_active_bottom_color(self, widget, color): config.set("lyrics", "active_color_bottom", color) def draw_lyrics(self, widget, event): cr = widget.window.cairo_create() rect = widget.allocation # font_height = self.render_lyrics.get_font_height() xpos = rect.x + 5 ypos = rect.y + 5 cr.save() cr.rectangle(xpos, ypos, rect.width, rect.height) cr.clip() cr.set_operator(cairo.OPERATOR_OVER) # draw_active cr.save() cr.rectangle(xpos, ypos, rect.width * 0.5, rect.height) cr.clip() active_surface = self.draw_lyric_surface(PROGRAM_NAME_LONG, True) if active_surface: cr.set_source_surface(active_surface, xpos, ypos) cr.paint() cr.restore() # draw_inactive cr.save() cr.rectangle(xpos + rect.width * 0.5, ypos, rect.width*0.5, rect.height) cr.clip() inactive_surface = self.draw_lyric_surface(PROGRAM_NAME_LONG) if inactive_surface: cr.set_source_surface(inactive_surface, xpos, ypos) cr.paint() cr.restore() cr.restore() return False def create_single_line_box(self): single_align_items = OrderedDict() single_align_items["left"] = _("Left") single_align_items["centered"] = _("Centered") single_align_items["right"] = _("Right") try: single_index = single_align_items.keys().index(config.get("lyrics", "single_line_align")) except: single_index = 0 self.single_align_combo_box = ComboBox([(value, key) for key, value in single_align_items.items()], select_index=single_index) def create_double_line_box(self): double_align_items = OrderedDict() double_align_items["left"] = _("Left") double_align_items["centered"] = _("Centered") double_align_items["right"] = _("Right") double_align_items["justified"] = _("Justified") try: align_index = double_align_items.keys().index(config.get("lyrics", "double_line_align")) except: align_index = 0 self.double_align_combo_box = ComboBox([(value, key) for key, value in double_align_items.items()], select_index=align_index) def create_predefine_box(self): predefine_color_items = OrderedDict() predefine_color_items["vitality_yellow"] = _("Vitality yellow") predefine_color_items["fresh_green"] = _("Fresh green") predefine_color_items["playful_pink"] = _("Playful pink") predefine_color_items["cool_blue"] = _("Cool blue") save_predefine_color = config.get("lyrics", "predefine_color", "default") try: predefine_color_index = predefine_color_items.keys().index(save_predefine_color) except: predefine_color_index = 0 self.predefine_color_combo_box = ComboBox( [(value, key) for key, value in predefine_color_items.items()], select_index=predefine_color_index) predefine_color_label = Label("%s:" % _("Color scheme")) predefine_color_hbox = gtk.HBox(spacing=5) predefine_color_hbox.pack_start(predefine_color_label, False, False) predefine_color_hbox.pack_start(self.predefine_color_combo_box, False, False) return predefine_color_hbox def create_font_type_box(self): font_type_items = OrderedDict() font_type_items["Regular"] = _("Regular") font_type_items["Italic"] = _("Italic") font_type_items["Bold"] = _("Bold") font_type_items["Bold Italic"] = _("Bold Italic") try: font_type_index = font_type_items.keys().index(config.get("lyrics", "font_type", "Regular")) except: font_type_index = 0 self.font_type_combo_box = ComboBox([(value, key) for key, value in font_type_items.items()], select_index=font_type_index) font_type_label = Label("%s:" % _("Style")) return set_widget_resize(font_type_label, self.font_type_combo_box) def create_style_table(self): main_table = gtk.Table(12, 2) main_table.set_row_spacings(CONTENT_ROW_SPACING) self.create_single_line_box() self.create_double_line_box() style_title_label = Label(_("Lyrics style")) # font_name font_families = get_font_families() font_name = config.get("lyrics", "font_name") try: font_item_index = font_families.index(font_name) except: font_item_index = 0 font_name_hbox, self.font_name_combo_box = self.create_combo_widget(_("Font"), [(font_name, None) for font_name in font_families], font_item_index) font_type_hbox = self.create_font_type_box() font_size = int(config.get("lyrics", "font_size", 30)) font_size_hbox, self.font_size_spin = self.create_combo_spin(_("Size"), font_size, 16, 70, 1) line_number = config.getint("lyrics", "line_count") line_number_hbox, self.line_number_combo_box = self.create_combo_widget(_("Lines"), [(_("Single"), 1), (_("Double"), 2)], select_index=line_number - 1) self.line_align_hbox = gtk.HBox() line_align_label = Label("%s:" % _("Alignment")) if line_number == 2: self.line_align_hbox.add(self.double_align_combo_box) else: self.line_align_hbox.add(self.single_align_combo_box) part_align_hbox = set_widget_resize(line_align_label, self.line_align_hbox) outline_hbox, self.outline_spin = self.create_combo_spin(_("Outline"), int(config.get("lyrics", "outline_width", "3")), 0, 8, 1) # blur_color_button. blur_color_label = Label("%s:" % _("Stroke")) self.blur_color_button = ColorButton(config.get("lyrics", "blur_color", "#000000")) blur_color_hbox = set_widget_resize(blur_color_label, self.blur_color_button) predefine_color_hbox = self.create_predefine_box() inactive_color_label = Label("%s:" % _("Unplayed")) self.inactive_upper_color_button = ColorButton(config.get("lyrics", "inactive_color_upper")) self.inactive_middle_color_button = ColorButton(config.get("lyrics", "inactive_color_middle")) self.inactive_bottom_color_button = ColorButton(config.get("lyrics", "inactive_color_bottom")) inactive_color_subbox = gtk.HBox(spacing=10) inactive_color_subbox.pack_start(self.inactive_upper_color_button, False, False) inactive_color_subbox.pack_start(self.inactive_middle_color_button, False, False) inactive_color_subbox.pack_start(self.inactive_bottom_color_button, False, False) inactive_color_box = set_widget_resize(inactive_color_label, inactive_color_subbox, sizes2=(160, 22)) active_color_label = Label("%s:" % _("Played")) self.active_upper_color_button = ColorButton(config.get("lyrics", "active_color_upper")) self.active_middle_color_button = ColorButton(config.get("lyrics", "active_color_middle")) self.active_bottom_color_button = ColorButton(config.get("lyrics", "active_color_bottom")) active_color_subbox = gtk.HBox(spacing=10) active_color_subbox.pack_start(self.active_upper_color_button, False, False) active_color_subbox.pack_start(self.active_middle_color_button, False, False) active_color_subbox.pack_start(self.active_bottom_color_button, False, False) active_color_box = set_widget_resize(active_color_label, active_color_subbox, sizes2=(160, 22)) main_table.attach(style_title_label, 0, 2, 0, 1, yoptions=gtk.FILL, xpadding=8) main_table.attach(create_separator_box(), 0, 2, 1, 2, yoptions=gtk.FILL) main_table.attach(font_name_hbox, 0, 2, 2, 3) main_table.attach(font_type_hbox, 0, 2, 3, 4) main_table.attach(font_size_hbox, 0, 2, 4, 5) main_table.attach(line_number_hbox, 0, 2, 5, 6) main_table.attach(part_align_hbox, 0, 2, 6, 7) main_table.attach(outline_hbox, 0, 2, 7, 8) main_table.attach(blur_color_hbox, 0, 2, 8, 9) main_table.attach(predefine_color_hbox, 0, 2, 9, 10) main_table.attach(inactive_color_box, 0, 2, 10, 11) main_table.attach(active_color_box, 0, 2, 11, 12) return main_table def create_combo_widget(self, label_content, items, select_index=0): label = Label("%s:" % label_content) if len(items) > 10: height = 200 max_width = 300 else: height = None max_width = None combo_box = ComboBox(items, height, select_index=select_index, max_width=max_width) hbox = set_widget_resize(label, combo_box) return hbox, combo_box def create_combo_spin(self, label_content, init_value, low, upper, step): label = Label("%s:" % label_content) spinbox = SpinBox(init_value, low, upper, step) hbox = set_widget_resize(label, spinbox) return hbox, spinbox