Ejemplo n.º 1
0
    def enter_notify_menu_item(self, widget):
        """
        Internal callback for `enter-notify-event` signal.
        """
        # Reset all items in same menu.
        for menu_item in self.get_menu_items_callback():
            if menu_item != self and menu_item.submenu_active:
                menu_item.submenu_active = False
                menu_item.item_box.queue_draw()

        (item_icons, item_content, item_node) = self.item[0:3]
        if isinstance(item_node, Menu):
            if widget.state != gtk.STATE_INSENSITIVE:
                menu_window = self.item_box.get_toplevel()
                (menu_window_x, menu_window_y) = get_widget_root_coordinate(menu_window, WIDGET_POS_RIGHT_CENTER)
                (item_x, item_y) = get_widget_root_coordinate(self.item_box)
                self.show_submenu_callback(
                    item_node,
                    (
                        menu_window_x - menu_window.shadow_radius,
                        item_y - widget.get_allocation().height - menu_window.shadow_radius,
                    ),
                    self.item_box.allocation.height + menu_window.shadow_radius,
                )

                self.submenu_active = True
        else:
            self.hide_submenu_callback()
Ejemplo n.º 2
0
    def enter_notify_menu_item(self, widget):
        '''
        Internal callback for `enter-notify-event` signal.
        '''
        # Reset all items in same menu.
        for menu_item in self.get_menu_items_callback():
            if menu_item != self and menu_item.submenu_active:
                menu_item.submenu_active = False
                menu_item.item_box.queue_draw()

        (item_icons, item_content, item_node) = self.item[0:3]
        if isinstance(item_node, Menu):
            if widget.state != gtk.STATE_INSENSITIVE:
                menu_window = self.item_box.get_toplevel()
                (menu_window_x, menu_window_y) = get_widget_root_coordinate(
                    menu_window, WIDGET_POS_RIGHT_CENTER)
                (item_x, item_y) = get_widget_root_coordinate(self.item_box)
                self.show_submenu_callback(
                    item_node, (menu_window_x - menu_window.shadow_radius,
                                item_y - widget.get_allocation().height -
                                menu_window.shadow_radius),
                    self.item_box.allocation.height +
                    menu_window.shadow_radius)

                self.submenu_active = True
        else:
            self.hide_submenu_callback()
Ejemplo n.º 3
0
 def click_drop_button(self, *args):
     '''Click drop button.'''
     if self.droplist.get_visible():
         self.droplist.hide()
     else:
         (align_x, align_y) = get_widget_root_coordinate(self.align, WIDGET_POS_BOTTOM_LEFT)
         self.droplist.show(
             (align_x - 1, align_y - 1),
             (0, -self.height + 1))
         
         self.droplist.item_select_index = self.select_index
         self.droplist.active_item()
         self.droplist.scroll_page_to_select_item()
         
     self.queue_draw()    
Ejemplo n.º 4
0
class Menu(Window):
    '''
    Menu.

    @undocumented: realize_menu
    @undocumented: hide_menu
    @undocumented: get_menu_item_at_coordinate
    @undocumented: get_menu_items
    @undocumented: init_menu
    @undocumented: get_submenus
    @undocumented: get_menu_icon_info
    @undocumented: adjust_menu_position
    @undocumented: show_submenu
    @undocumented: hide_submenu
    @undocumented: get_root_menu
    '''
    def __init__(self,
                 items,
                 is_root_menu=False,
                 select_scale=False,
                 x_align=ALIGN_START,
                 y_align=ALIGN_START,
                 font_size=DEFAULT_FONT_SIZE,
                 padding_x=3,
                 padding_y=3,
                 item_padding_x=6,
                 item_padding_y=3,
                 shadow_visible=True,
                 menu_min_width=130,
                 menu_item_select_color=None):
        '''
        Initialize Menu class.

        @param items: A list of item, item format: ((item_normal_dpixbuf, item_hover_dpixbuf, item_disable_dpixbuf), item_name, item_node).
        @param is_root_menu: Default is False for submenu, you should set it as True if you build root menu.
        @param select_scale: Default is False, it will use parant's width if it set True.
        @param x_align: Horizontal alignment value.
        @param y_align: Vertical alignment value.
        @param font_size: Menu font size, default is DEFAULT_FONT_SIZE
        @param padding_x: Horizontal padding value, default is 3 pixel.
        @param padding_y: Vertical padding value, default is 3 pixel.
        @param item_padding_x: Horizontal item padding value, default is 6 pixel.
        @param item_padding_y: Vertical item padding value, default is 3 pixel.
        @param shadow_visible: Whether show window shadow, default is True.
        @param menu_min_width: Minimum width of menu.
        '''
        global root_menus

        # Init.
        Window.__init__(self,
                        shadow_visible=shadow_visible,
                        window_type=gtk.WINDOW_POPUP,
                        shadow_radius=6)
        self.set_can_focus(True)  # can focus to response key-press signal
        self.draw_mask = self.draw_menu_mask
        self.is_root_menu = is_root_menu
        self.select_scale = select_scale
        self.x_align = x_align
        self.y_align = y_align
        self.submenu = None
        self.root_menu = None
        self.offset_x = 0  # use for handle extreme situaiton, such as, menu show at side of screen
        self.offset_y = 0
        self.padding_x = padding_x
        self.padding_y = padding_y
        self.item_padding_x = item_padding_x
        self.item_padding_y = item_padding_y
        self.menu_min_width = menu_min_width
        self.menu_item_select_color = menu_item_select_color

        # Init menu window.
        self.set_skip_pager_hint(True)
        self.set_skip_taskbar_hint(True)
        self.set_keep_above(True)

        # Add menu item.
        self.item_box = gtk.VBox()
        self.item_align = gtk.Alignment()
        self.item_align.set_padding(padding_y, padding_y, padding_x, padding_x)
        self.item_align.add(self.item_box)
        self.window_frame.add(self.item_align)
        self.menu_items = []
        self.font_size = font_size

        if items:
            self.add_menu_items(items)

        self.connect("show", self.init_menu)
        self.connect("hide", self.hide_menu)
        self.connect("realize", self.realize_menu)

    def set_mutual_icons(self, index, icons):
        # deepin-media-player useing.
        # other no use.
        for item in self.menu_items:
            item.set_item_icons(None)
        #
        self.menu_items[index].set_item_icons(icons)

    def add_menu_items(self, items):
        (icon_width, icon_height, have_submenu, submenu_width,
         submenu_height) = self.get_menu_icon_info(items)

        for item in items:
            menu_item = MenuItem(item, self.font_size, self.select_scale,
                                 self.show_submenu, self.hide_submenu,
                                 self.get_root_menu, self.get_menu_items,
                                 icon_width, icon_height, have_submenu,
                                 submenu_width, submenu_height, self.padding_x,
                                 self.padding_y, self.item_padding_x,
                                 self.item_padding_y, self.menu_min_width,
                                 self.menu_item_select_color)
            self.menu_items.append(menu_item)
            self.item_box.pack_start(menu_item.item_box, False, False)

    def clear_menus(self):
        self.menu_items = []
        self.item_align.remove(self.item_box)
        self.item_box = gtk.VBox()
        self.item_align.add(self.item_box)
        self.resize(1, 1)

    def hide_menu(self, widget):
        '''
        Internal callback for `hide` signal.
        '''
        # Avoid menu (popup window) show at (0, 0) when next show.
        self.move(-1000000, -1000000)

    def realize_menu(self, widget):
        '''
        Internal callback for `realize` signal.
        '''
        # Avoid menu (popup window) show at (0, 0) first.
        self.move(-1000000, -1000000)

        # Never draw background.
        self.window.set_back_pixmap(None, False)

    def draw_menu_mask(self, cr, x, y, w, h):
        '''
        Draw mask interface.

        @param cr: Cairo context.
        @param x: X coordinate of draw area.
        @param y: Y coordinate of draw area.
        @param w: Width of draw area.
        @param h: Height of draw area.
        '''
        # Draw background.
        cr.set_source_rgba(*alpha_color_hex_to_cairo(
            ui_theme.get_alpha_color("menu_mask").get_color_info()))
        cr.rectangle(x, y, w, h)
        cr.fill()

        # Draw left side.
        draw_hlinear(cr, x + 1, y + 1,
                     16 + self.padding_x + self.padding_x * 2, h - 2,
                     ui_theme.get_shadow_color("menu_side").get_color_info())

    def get_menu_item_at_coordinate(self, (x, y)):
        '''
        Internal function to get menu item at coordinate, return None if haven't any menu item at given coordinate.
        '''
        match_menu_item = None
        for menu_item in self.menu_items:
            item_rect = menu_item.item_box.get_allocation()
            (item_x,
             item_y) = get_widget_root_coordinate(menu_item.item_box,
                                                  WIDGET_POS_TOP_LEFT)
            if is_in_rect((x, y),
                          (item_x, item_y, item_rect.width, item_rect.height)):
                match_menu_item = menu_item
                break

        return match_menu_item
Ejemplo n.º 5
0
class Droplist(gtk.Window):
    '''
    Droplist.

    @undocumented: create_item
    @undocumented: expose_item_align
    @undocumented: droplist_key_press
    @undocumented: droplist_key_release
    @undocumented: expose_droplist_frame
    @undocumented: init_droplist
    @undocumented: adjust_droplist_position
    '''

    __gsignals__ = {
        "item-selected": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (
            str,
            gobject.TYPE_PYOBJECT,
            int,
        )),
        "key-release": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (
            str,
            gobject.TYPE_PYOBJECT,
            int,
        )),
    }

    def __init__(self,
                 items,
                 x_align=ALIGN_START,
                 y_align=ALIGN_START,
                 font_size=DEFAULT_FONT_SIZE,
                 opacity=1.0,
                 padding_x=0,
                 padding_y=0,
                 item_padding_left=6,
                 item_padding_right=32,
                 item_padding_y=3,
                 max_width=None,
                 fixed_width=None,
                 max_height=None):
        '''
        Initialize Droplist class.

        @param items: A list of item, item format: (item_content, item_value).
        @param x_align: Horticultural alignment.
        @param y_align: Vertical alignment.
        @param font_size: Font size of droplist, default is DEFAULT_FONT_SIZE
        @param opacity: Opacity of droplist window, default is 1.0.
        @param padding_x: Padding x, default is 0.
        @param padding_y: Padding y, default is 0.
        @param item_padding_left: Padding at left of item, default is 6.
        @param item_padding_right: Padding at right of item, default is 32.
        @param item_padding_y: Padding of item vertically, default is 3.
        @param max_width: Maximum width of droplist, default is None.
        @param fixed_width: Fixed width of droplist, default is None.
        @param max_height: Maximum height of droplist, default is None.
        '''
        # Init.
        gtk.Window.__init__(self, gtk.WINDOW_POPUP)
        self.items = items
        self.set_can_focus(True)  # can focus to response key-press signal
        self.add_events(gtk.gdk.ALL_EVENTS_MASK)
        self.set_decorated(False)
        self.set_colormap(gtk.gdk.Screen().get_rgba_colormap())
        global root_droplists
        self.font_size = font_size
        self.x_align = x_align
        self.y_align = y_align
        self.subdroplist = None
        self.root_droplist = None
        self.offset_x = 0  # use for handle extreme situaiton, such as, droplist show at side of screen
        self.offset_y = 0
        self.padding_x = padding_x
        self.padding_y = padding_y
        self.item_padding_left = item_padding_left
        self.item_padding_right = item_padding_right
        self.item_padding_y = item_padding_y
        self.max_width = max_width
        self.max_height = max_height
        self.fixed_width = fixed_width
        self.item_select_index = 0

        # Init droplist window.
        self.set_opacity(opacity)
        self.set_skip_taskbar_hint(True)
        self.set_keep_above(True)
        self.connect_after("show", self.init_droplist)

        self.droplist_frame = gtk.Alignment()
        self.droplist_frame.set(0.5, 0.5, 1.0, 1.0)
        self.droplist_frame.set_padding(1, 1, 1, 1)

        # Add droplist item.
        self.item_box = gtk.VBox()
        self.item_align = gtk.Alignment()
        self.item_align.set_padding(padding_y, padding_y, padding_x, padding_x)
        self.item_align.add(self.item_box)
        self.item_scrolled_window = DroplistScrolledWindow(0, 0)
        self.item_scrolled_window.set_policy(gtk.POLICY_NEVER,
                                             gtk.POLICY_AUTOMATIC)
        self.add(self.droplist_frame)
        self.droplist_frame.add(self.item_scrolled_window)
        self.item_scrolled_window.add_child(self.item_align)
        self.droplist_items = []

        if items:
            for (index, item) in enumerate(items):
                droplist_item = self.create_item(index, item)
                self.droplist_items.append(droplist_item)
                self.item_box.pack_start(droplist_item.item_box, False, False)

        self.connect_after("show", lambda w: self.adjust_droplist_position())
        self.droplist_frame.connect("expose-event", self.expose_droplist_frame)
        self.item_align.connect("expose-event", self.expose_item_align)
        self.connect("key-press-event", self.droplist_key_press)
        self.connect("key-release-event", self.droplist_key_release)

        self.keymap = {
            "Home": self.select_first_item,
            "End": self.select_last_item,
            "Page_Up": self.scroll_page_up,
            "Page_Down": self.scroll_page_down,
            "Return": self.press_select_item,
            "Up": self.select_prev_item,
            "Down": self.select_next_item,
            "Escape": self.hide
        }

        self.select_first_item()
        self.grab_focus()

    def create_item(self, index, item):
        return DroplistItem(self, index, item, self.font_size, self.padding_x,
                            self.padding_y, self.item_padding_left,
                            self.item_padding_right, self.item_padding_y,
                            self.max_width, self.fixed_width)

    def get_droplist_width(self):
        '''
        Get droplist width.

        @return: Return width of droplist.
        '''
        if self.fixed_width != None:
            return self.padding_x * 2 + self.fixed_width
        else:
            item_content_width = max(
                map(
                    lambda item: get_content_size(item.item[0], self.font_size)
                    [0],
                    filter(lambda item: isinstance(item.item_box, gtk.Button),
                           self.droplist_items)))

            if self.max_width != None:
                return self.padding_x * 2 + min(
                    self.max_width, self.item_padding_left +
                    self.item_padding_right + int(item_content_width))
            else:
                return self.padding_x * 2 + self.item_padding_left + self.item_padding_right + int(
                    item_content_width)

    def expose_item_align(self, widget, event):
        '''
        Internal function to handle `expose-event` signal.

        @param widget: Droplist widget.
        @param event: Expose event.
        '''
        # Init.
        cr = widget.window.cairo_create()
        rect = widget.allocation
        x, y, w, h = rect.x, rect.y, rect.width, rect.height

        # Draw background.
        cr.set_source_rgba(*alpha_color_hex_to_cairo(
            ui_theme.get_alpha_color("droplist_mask").get_color_info()))
        cr.rectangle(x, y, w, h)
        cr.fill()

    def get_first_index(self):
        '''
        Get index of first item.

        @return: Return index of first item, or return None if haven't item in droplist.
        '''
        item_indexs = filter(
            lambda (index, item): isinstance(item.item_box, gtk.Button),
            enumerate(self.droplist_items))
        if len(item_indexs) > 0:
            return item_indexs[0][0]
        else:
            return None

    def get_last_index(self):
        '''
        Get index of last item.

        @return: Return index of last item, or return None if haven't item in droplist.
        '''
        item_indexs = filter(
            lambda (index, item): isinstance(item.item_box, gtk.Button),
            enumerate(self.droplist_items))
        if len(item_indexs) > 0:
            return item_indexs[-1][0]
        else:
            return None

    def get_prev_index(self):
        '''
        Get index of previous item.

        @return: Return index of previous item, or return None if haven't item in droplist.
        '''
        item_indexs = filter(
            lambda (index, item): isinstance(item.item_box, gtk.Button),
            enumerate(self.droplist_items))
        if len(item_indexs) > 0:
            index_list = map(lambda (index, item): index, item_indexs)
            if self.item_select_index in index_list:
                current_index = index_list.index(self.item_select_index)
                if current_index > 0:
                    return index_list[current_index - 1]
                else:
                    return self.item_select_index
            else:
                return None
        else:
            return None

    def get_next_index(self):
        '''
        Get index of next item.

        @return: Return index of next item, or return None if haven't item in droplist.
        '''
        item_indexs = filter(
            lambda (index, item): isinstance(item.item_box, gtk.Button),
            enumerate(self.droplist_items))
        if len(item_indexs) > 0:
            index_list = map(lambda (index, item): index, item_indexs)
            if self.item_select_index in index_list:
                current_index = index_list.index(self.item_select_index)
                if current_index < len(index_list) - 1:
                    return index_list[current_index + 1]
                else:
                    return self.item_select_index
            else:
                return None
        else:
            return None

    def get_select_item_rect(self, item_index=None):
        '''
        Get item rectangle with given index.

        @param item_index: If item_index is None, use select index.

        @return: Return (x, y, w, h) rectangle for match item.
        '''
        if item_index == None:
            item_index = self.item_select_index
        item_offset_y = sum(
            map(lambda item: item.item_box_height,
                self.droplist_items)[0:item_index])
        item_rect = self.droplist_items[item_index].item_box.get_allocation()
        return (0, item_offset_y, item_rect.width, item_rect.height)

    def active_item(self, item_index=None):
        '''
        Select item with given index.

        @param item_index: If item_index is None, use select index.
        '''
        global droplist_active_item

        if item_index == None:
            item_index = self.item_select_index

        if droplist_active_item:
            droplist_active_item.item_box.set_state(gtk.STATE_NORMAL)

        item = self.droplist_items[item_index]
        item.item_box.set_state(gtk.STATE_PRELIGHT)
        droplist_active_item = item

    def select_first_item(self):
        '''
        Select first item.
        '''
        if len(self.droplist_items) > 0:
            first_index = self.get_first_index()
            if first_index != None:
                self.item_select_index = first_index
                self.active_item()

                # Scroll to top.
                vadjust = self.item_scrolled_window.get_vadjustment()
                vadjust.set_value(vadjust.get_lower())

    def select_last_item(self):
        '''
        Select last item.
        '''
        if len(self.droplist_items) > 0:
            last_index = self.get_last_index()
            if last_index != None:
                self.item_select_index = last_index
                self.active_item()

                # Scroll to bottom.
                vadjust = self.item_scrolled_window.get_vadjustment()
                vadjust.set_value(vadjust.get_upper() -
                                  vadjust.get_page_size())

    def select_prev_item(self):
        '''
        Select previous item.
        '''
        if len(self.droplist_items) > 0:
            prev_index = self.get_prev_index()
            if prev_index != None:
                global droplist_active_item

                if droplist_active_item:
                    if self.item_select_index > 0:
                        self.item_select_index = prev_index
                        self.active_item()

                        # Make item in visible area.
                        (item_x, item_y, item_width,
                         item_height) = self.get_select_item_rect()
                        vadjust = self.item_scrolled_window.get_vadjustment()
                        if item_y < vadjust.get_value():
                            vadjust.set_value(item_y)
                else:
                    self.select_first_item()

    def select_next_item(self):
        '''
        Select next item.
        '''
        if len(self.droplist_items) > 0:
            next_index = self.get_next_index()
            if next_index != None:
                global droplist_active_item

                if droplist_active_item:
                    if self.item_select_index < len(self.droplist_items) - 1:
                        self.item_select_index = next_index
                        self.active_item()

                        # Make item in visible area.
                        (item_x, item_y, item_width,
                         item_height) = self.get_select_item_rect()
                        vadjust = self.item_scrolled_window.get_vadjustment()
                        if self.padding_y + item_y + item_height > vadjust.get_value(
                        ) + vadjust.get_page_size():
                            vadjust.set_value(self.padding_y * 2 + item_y +
                                              item_height -
                                              vadjust.get_page_size())
                else:
                    self.select_first_item()

    def scroll_page_to_select_item(self):
        '''
        Scroll page to select item.
        '''
        (item_x, item_y, item_width, item_height) = self.get_select_item_rect()
        vadjust = self.item_scrolled_window.get_vadjustment()
        vadjust.set_value(
            min(max(vadjust.get_lower(), item_y - self.padding_y * 2),
                vadjust.get_upper() - vadjust.get_page_size()))

    def scroll_page_up(self):
        '''
        Scroll page up.
        '''
        if len(self.droplist_items) > 0:
            # Scroll page up.
            vadjust = self.item_scrolled_window.get_vadjustment()
            vadjust.set_value(
                max(vadjust.get_lower(),
                    vadjust.get_value() - vadjust.get_page_size()))

            # Select nearest item.
            item_infos = map(
                lambda (index, item):
                (index, self.get_select_item_rect(index)),
                enumerate(self.droplist_items))
            for (index, (item_x, item_y, item_width,
                         item_height)) in item_infos:
                if item_y + self.padding_y > vadjust.get_value():
                    self.item_select_index = index
                    self.active_item()
                    break

    def scroll_page_down(self):
        '''
        Scroll page down.
        '''
        if len(self.droplist_items) > 0:
            # Scroll page up.
            vadjust = self.item_scrolled_window.get_vadjustment()
            vadjust.set_value(
                min(vadjust.get_upper() - vadjust.get_page_size(),
                    vadjust.get_value() + vadjust.get_page_size()))

            # Select nearest item.
            item_infos = map(
                lambda (index, item):
                (index, self.get_select_item_rect(index)),
                enumerate(self.droplist_items))
            item_infos.reverse()
            for (index, (item_x, item_y, item_width,
                         item_height)) in item_infos:
                if item_y + item_height + self.padding_y < vadjust.get_value(
                ) + vadjust.get_page_size():
                    self.item_select_index = index
                    self.active_item()
                    break

    def press_select_item(self):
        '''
        Press select item.
        '''
        if len(self.droplist_items) > 0:
            if 0 <= self.item_select_index < len(self.droplist_items):
                self.droplist_items[
                    self.item_select_index].wrap_droplist_clicked_action()

    def droplist_key_press(self, widget, event):
        '''
        Internal function for `key-press-event` signal.

        @param widget: Droplist widget.
        @param event: Key press event.
        '''
        key_name = get_keyevent_name(event)
        if self.keymap.has_key(key_name):
            self.keymap[key_name]()

        return True

    def droplist_key_release(self, widget, event):
        '''
        Internal function for `key-release-event` signal.

        @param widget: Droplist widget.
        @param event: Key release event.
        '''
        self.emit("key-release", self.items[self.item_select_index][0],
                  self.items[self.item_select_index][1],
                  self.item_select_index)

    def expose_droplist_frame(self, widget, event):
        '''
        Callback for `expose-event` siangl of droplist frame.

        @param widget: Droplist widget.
        @param event: Expose event.
        '''
        cr = widget.window.cairo_create()
        rect = widget.allocation

        with cairo_disable_antialias(cr):
            cr.set_line_width(1)
            cr.set_source_rgb(*color_hex_to_cairo(
                ui_theme.get_color("droplist_frame").get_color()))
            cr.rectangle(rect.x, rect.y, rect.width, rect.height)
            cr.fill()

    def get_droplist_item_at_coordinate(self, (x, y)):
        '''
        Get droplist item at coordinate, return None if haven't any droplist item at given coordinate.

        @param x: X coordiante.
        @param y: Y coordiante.

        @return: Return match item with given coordinate, return None if haven't any item match coordinate.
        '''
        match_droplist_item = None

        item_heights = map(lambda item: item.item_box_height,
                           self.droplist_items)
        item_offsets = map(lambda (index, height): sum(item_heights[0:index]),
                           enumerate(item_heights))

        vadjust = self.item_scrolled_window.get_vadjustment()
        (scrolled_window_x, scrolled_window_y) = get_widget_root_coordinate(
            self.item_scrolled_window, WIDGET_POS_TOP_LEFT)
        for (index, droplist_item) in enumerate(self.droplist_items):
            item_rect = droplist_item.item_box.get_allocation()
            if is_in_rect(
                (x, y),
                (scrolled_window_x, scrolled_window_y + item_offsets[index] -
                 (vadjust.get_value() - vadjust.get_lower()), item_rect.width,
                 item_rect.height)):
                match_droplist_item = droplist_item
                break

        return match_droplist_item