예제 #1
0
 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)        
예제 #2
0
 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)
예제 #3
0
    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)
예제 #4
0
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