示例#1
0
 def setup_widgets(self):
     self.builder = Gtk.Builder()
     self.builder.add_from_file(os.path.join(self.app.gladepath,
                                             self.GLADE))
     lblItemIconName = self.builder.get_object("lblItemIconName")
     vbChangeItemIcon = self.builder.get_object("vbChangeItemIcon")
     self.window = self.builder.get_object("Dialog")
     self.menu_icon = MenuIcon(None, True)
     vbChangeItemIcon.remove(lblItemIconName)
     vbChangeItemIcon.pack_start(self.menu_icon, False, True, 0)
     vbChangeItemIcon.pack_start(lblItemIconName, True, True, 0)
     self.builder.connect_signals(self)
     headerbar(self.builder.get_object("header"))
示例#2
0
    def generate_widget(self, item):
        """
		In QuickMenu, everything but submenus and simple
		menuitems is ignored.
		"""
        if self._button_index >= len(self.BUTTONS):
            return None
        if isinstance(item, (MenuItem, Submenu)):
            widget = Gtk.Button.new_with_label(item.label)
            widget.set_relief(Gtk.ReliefStyle.NONE)
            if hasattr(widget.get_children()[0], "set_xalign"):
                widget.get_children()[0].set_xalign(0)
            else:
                widget.get_children()[0].set_halign(Gtk.Align.START)
            if isinstance(item, Submenu):
                item.callback = self.show_submenu
                label1 = widget.get_children()[0]
                label2 = Gtk.Label(_(">>"))
                label2.set_property("margin-left", 30)
                box = Gtk.Box(Gtk.Orientation.HORIZONTAL)
                widget.remove(label1)
                box.pack_start(label1, True, True, 1)
                box.pack_start(label2, False, True, 1)
                widget.add(box)
                widget.set_name("osd-menu-item")
            elif item.id is None:
                # Ignored as well
                return None
            else:
                widget.set_name("osd-menu-item")

            item.button = self.BUTTONS[self._button_index]
            self._button_index += 1

            icon_file, has_colors = find_icon("buttons/%s" % item.button,
                                              False)
            icon = MenuIcon(icon_file, has_colors)
            label = widget.get_children()[0]
            for c in [] + widget.get_children():
                widget.remove(c)
            self._icons.append(icon)
            box = Gtk.Box()
            box.pack_start(icon, False, True, 0)
            box.pack_start(label, True, True, 10)
            widget.add(box)
            return widget
        return None
 def generate_widget(self, item):
     if isinstance(item, Separator):
         # Ignored here
         return None
     elif item.id is None:
         # Dummies are ignored as well
         return None
     else:
         icon_file, has_colors = find_icon(item.icon, False)
         if icon_file:
             # Gridmenu hides label when icon is displayed
             widget = Gtk.Button()
             widget.set_relief(Gtk.ReliefStyle.NONE)
             widget.set_name("osd-menu-item-big-icon")
             if isinstance(item, Submenu):
                 item.callback = self.show_submenu
             icon = MenuIcon(icon_file, has_colors)
             widget.add(icon)
             return widget
         else:
             return Menu.generate_widget(self, item)
示例#4
0
class MenuEditor(Editor):
    GLADE = "menu_editor.glade"
    TYPE_INTERNAL = 1
    TYPE_GLOBAL = 2

    OPEN = set()  # Set of menus that are being edited.

    def __init__(self, app, callback):
        self.app = app
        self.next_auto_id = 1
        self.callback = callback
        self.selected_icon = None
        self.original_id = None
        self.original_type = MenuEditor.TYPE_INTERNAL
        Editor.install_error_css()
        self.setup_widgets()

    def setup_widgets(self):
        self.builder = Gtk.Builder()
        self.builder.add_from_file(os.path.join(self.app.gladepath,
                                                self.GLADE))
        lblItemIconName = self.builder.get_object("lblItemIconName")
        vbChangeItemIcon = self.builder.get_object("vbChangeItemIcon")
        self.window = self.builder.get_object("Dialog")
        self.menu_icon = MenuIcon(None, True)
        vbChangeItemIcon.remove(lblItemIconName)
        vbChangeItemIcon.pack_start(self.menu_icon, False, True, 0)
        vbChangeItemIcon.pack_start(lblItemIconName, True, True, 0)
        self.builder.connect_signals(self)
        headerbar(self.builder.get_object("header"))

    def allow_menus(self, allow_globals, allow_in_profile):
        """
		Sets which type of menu should be selectable.
		By default, both are enabled.
		"""
        if not allow_globals:
            self.builder.get_object("rbInProfile").set_active(True)
            self.builder.get_object("rbGlobal").set_sensitive(False)
            self.builder.get_object("rbInProfile").set_sensitive(True)
        elif not allow_in_profile:
            self.builder.get_object("rbGlobal").set_active(True)
            self.builder.get_object("rbGlobal").set_sensitive(True)
            self.builder.get_object("rbInProfile").set_sensitive(False)
        else:
            self.builder.get_object("rbGlobal").set_sensitive(True)
            self.builder.get_object("rbInProfile").set_sensitive(True)

    def on_action_chosen(self, id, a, mark_changed=True):
        model = self.builder.get_object("tvItems").get_model()
        for i in model:
            item = i[0].item
            if item.id == id:
                if isinstance(item, Separator):
                    item.label = a.get_name()
                elif isinstance(item, Submenu):
                    i[0].item = item = Submenu(
                        a.get_current_page().get_selected_menu(), a.get_name())
                    item.icon = self.selected_icon
                elif isinstance(item, RecentListMenuGenerator):
                    i[0].item = item = RecentListMenuGenerator(
                        rows=a.get_current_page().get_row_count())
                elif isinstance(item, MenuItem):
                    item.action = a
                    item.label = item.action.describe(Action.AC_OSD)
                    item.icon = self.selected_icon
                else:
                    raise TypeError("Edited %s" % (item.__class__.__name__))
                i[1] = item.describe()
                break

    def on_btSave_clicked(self, *a):
        """ Handler for Save button """
        self._remove_original()
        if self.builder.get_object("rbInProfile").get_active():
            self._save_to_profile(
                self.builder.get_object("entName").get_text())
        else:
            self._save_to_file(self.builder.get_object("entName").get_text())
        self.close()

    def on_tvItems_cursor_changed(self, *a):
        """
		Handles moving cursor in Item List.
		Basically just sets Edit Item and Remove Item buttons sensitivity.
		"""
        tvItems = self.builder.get_object("tvItems")
        btEdit = self.builder.get_object("btEdit")
        btRemoveItem = self.builder.get_object("btRemoveItem")

        model, iter = tvItems.get_selection().get_selected()
        if iter is None:
            btRemoveItem.set_sensitive(False)
            btEdit.set_sensitive(False)
        else:
            btRemoveItem.set_sensitive(True)
            o = model.get_value(iter, 0)
            if isinstance(o.item, (MenuItem, RecentListMenuGenerator)):
                btEdit.set_sensitive(True)
            else:
                btEdit.set_sensitive(False)

    def btEdit_clicked_cb(self, *a):
        """ Handler for "Edit Item" button """
        tvItems = self.builder.get_object("tvItems")
        model, iter = tvItems.get_selection().get_selected()
        item = model.get_value(iter, 0).item
        self.selected_icon = None
        # Setup editor
        e = ActionEditor(self.app, self.on_action_chosen)
        if isinstance(item, Separator):
            e.set_title(_("Edit Separator"))
            e.hide_editor()
            e.set_menu_item(item, _("Separator Name"))
        elif isinstance(item, Submenu):
            e.set_title(_("Edit Submenu"))
            e.hide_action_str()
            e.hide_clear()
            (e.force_page(e.load_component("menu_only"), True).allow_menus(
                True, False).set_selected_menu(item.filename))
            e.set_menu_item(item, _("Menu Label"))
            self.selected_icon = item.icon
            self.setup_menu_icon(e)
            self.update_menu_icon()
        elif isinstance(item, MenuItem):
            e = ActionEditor(self.app, self.on_action_chosen)
            e.set_title(_("Edit Menu Action"))
            e.set_input(item.id, item.action, mode=Action.AC_MENU)
            self.selected_icon = item.icon
            self.setup_menu_icon(e)
            self.update_menu_icon()
        elif isinstance(item, RecentListMenuGenerator):
            e.set_title(_("Edit Recent List"))
            e.hide_action_str()
            e.hide_clear()
            e.hide_name()
            (e.force_page(e.load_component("recent_list"),
                          True).set_row_count(item.rows))
            e.set_menu_item(item)
        else:
            # Cannot edit this
            return
        # Display editor
        e.show(self.window)

    def _add_menuitem(self, item):
        """ Adds MenuItem or MenuGenerator object """
        tvItems = self.builder.get_object("tvItems")
        model = tvItems.get_model()
        o = GObject.GObject()
        if not item.id:
            item.id = "_auto_id_%s" % (self.next_auto_id, )
            self.next_auto_id += 1
        o.item = item
        iter = model.append((o, o.item.describe()))
        tvItems.get_selection().select_iter(iter)
        self.on_tvItems_cursor_changed()

    def on_btAddItem_clicked(self, *a):
        """ Handler for "Add Action" button and menu item """
        item = MenuItem(None, NoAction().describe(Action.AC_OSD), NoAction())
        self._add_menuitem(item)
        self.btEdit_clicked_cb()

    def on_mnuAddSeparator_clicked(self, *a):
        """ Handler for "Add Separator" menu item """
        self._add_menuitem(Separator())

    def on_mnuAddSubmenu_clicked(self, *a):
        """ Handler for "Add Separator" menu item """
        self._add_menuitem(Submenu(""))

    def on_mnuAddProfList_clicked(self, *a):
        """ Handler for "Add List of All Profiles" menu item """
        self._add_menuitem(ProfileListMenuGenerator())

    def on_mnuAddRecentList_clicked(self, *a):
        """ Handler for "Add List of Recent Profiles" menu item """
        self._add_menuitem(RecentListMenuGenerator())

    def on_mnuAddGamesList_activate(self, *a):
        """ Handler for "Add List of Games" menu item """
        self._add_menuitem(GameListMenuGenerator())

    def on_btRemoveItem_clicked(self, *a):
        """ Handler for "Delete Item" button """
        tvItems = self.builder.get_object("tvItems")
        model, iter = tvItems.get_selection().get_selected()
        if iter is not None:
            model.remove(iter)
        self.on_tvItems_cursor_changed()

    def on_entName_changed(self, *a):
        id = self.builder.get_object("entName").get_text()
        if len(id.strip()) == 0:
            self._bad_id_no_id()
            return
        if "." in id or "/" in id:
            self._bad_id_chars()
            return
        if self.builder.get_object("rbInProfile").get_active():
            # Menu stored in profile
            if id != self.original_id and id in self.app.current.menus:
                self._bad_id_duplicate()
                return
        else:
            # Menu stored as file
            if id != self.original_id:
                path = os.path.join(get_menus_path(), "%s.menu" % (id, ))
                if os.path.exists(path):
                    self._bad_id_duplicate()
                    return
        self._good_id()
        return

    def _good_id(self, *a):
        self.builder.get_object("rvInvalidID").set_reveal_child(False)
        self.builder.get_object("btSave").set_sensitive(True)

    def _bad_id_no_id(self, *a):
        self.builder.get_object("btSave").set_sensitive(False)

    def _bad_id_duplicate(self, *a):
        self.builder.get_object("lblNope").set_label(
            _('Invalid Menu ID: Menu with same ID already exists.'))
        self.builder.get_object("rvInvalidID").set_reveal_child(True)
        self.builder.get_object("btSave").set_sensitive(False)

    def _bad_id_chars(self, *a):
        self.builder.get_object("lblNope").set_label(
            _('Invalid Menu ID: Please, don\'t use dots (.) or slashes (/).'))
        self.builder.get_object("rvInvalidID").set_reveal_child(True)
        self.builder.get_object("btSave").set_sensitive(False)

    def set_new_menu(self):
        """
		Setups editor for creating new menu.
		"""
        self.set_title(_("New Menu"))
        rbInProfile = self.builder.get_object("rbInProfile")
        entName = self.builder.get_object("entName")

        rbInProfile.set_active(True)
        self.original_id = None
        self.original_type = MenuEditor.TYPE_INTERNAL
        entName.set_text("")

    def set_menu(self, id):
        """
		Setups editor for menu with specified ID.
		ID may be id of menu in profile or, if it contains ".", filename.
		"""
        self.set_title(_("Menu Editor"))
        rbGlobal = self.builder.get_object("rbGlobal")
        rbInProfile = self.builder.get_object("rbInProfile")
        entName = self.builder.get_object("entName")

        MenuEditor.OPEN.add(id)
        if "." in id:
            id = id.split(".")[0]
            rbGlobal.set_active(True)
            self.original_type = MenuEditor.TYPE_GLOBAL
            items = self._load_items_from_file(id)
        else:
            rbInProfile.set_active(True)
            self.original_type = MenuEditor.TYPE_INTERNAL
            items = self._load_items_from_profile(id)
        self.original_id = id
        entName.set_text(id)

        model = self.builder.get_object("tvItems").get_model()
        model.clear()
        if items is None:
            self.set_new_menu()
        else:
            for i in items:
                self._add_menuitem(i)

    def on_Dialog_delete_event(self, *a):
        try:
            if self.original_type == MenuEditor.TYPE_GLOBAL:
                MenuEditor.OPEN.remove(self.original_id + ".menu")
            else:
                MenuEditor.OPEN.remove(self.original_id)
        except KeyError:
            pass
        return False

    def close(self, *a):
        self.on_Dialog_delete_event()
        Editor.close(self)

    def _load_items_from_file(self, id):
        for p in (get_menus_path(), get_default_menus_path()):
            path = os.path.join(p, "%s.menu" % (id, ))
            if os.path.exists(path):
                return MenuData.from_file(path, TalkingActionParser())
        # Menu file not found
        return None

    def _load_items_from_profile(self, id):
        try:
            return self.app.current.menus[id]
        except KeyError:
            # Menu not found
            return None

    def _remove_original(self):
        if self.original_id is None:
            # Created new menu
            pass
        elif self.original_type == MenuEditor.TYPE_INTERNAL:
            try:
                del self.app.current.menus[self.original_id]
            except:
                pass
        elif self.original_type == MenuEditor.TYPE_GLOBAL:
            try:
                path = os.path.join(get_menus_path(),
                                    "%s.menu" % (self.original_id, ))
                log.debug("Removing %s", path)
                os.unlink(path)
            except:
                pass

    def _generate_menudata(self):
        """
		Generates MenuData instance from items in list
		"""
        model = self.builder.get_object("tvItems").get_model()
        data = MenuData(*[i[0].item for i in model])
        i = 1
        for item in data:
            item.id = "item%s" % (i, )
            i += 1
        return data

    def _save_to_profile(self, id):
        """
		Stores menu in loaded profile. Doesn't actually save anything, that's
		for main app window thing.
		"""
        self.app.current.menus[id] = self._generate_menudata()
        log.debug("Stored menu ID %s", id)
        self.app.on_profile_modified()
        if self.callback:
            self.callback(id)

    def _save_to_file(self, id):
        """
		Stores menu in json file
		"""
        id = "%s.menu" % (id, )
        path = os.path.join(get_menus_path(), id)
        data = self._generate_menudata()
        jstr = Encoder(sort_keys=True, indent=4).encode(data)
        open(path, "w").write(jstr)
        log.debug("Wrote menu file %s", path)
        if self.callback:
            self.callback(id)

    def setup_menu_icon(self, editor):
        container = self.builder.get_object("menu_icon")
        editor.add_widget(_("Icon"), container)

    def update_menu_icon(self):
        lblItemIconName = self.builder.get_object("lblItemIconName")
        if self.selected_icon is None:
            lblItemIconName.set_label(_("(no icon)"))
            self.menu_icon.set_visible(False)
        else:
            lblItemIconName.set_label(self.selected_icon)
            try:
                filename, trash = find_icon(self.selected_icon)
                self.menu_icon.set_filename(filename)
                self.menu_icon.set_visible(True)
            except Exception, e:
                log.error(e)
                log.error(traceback.format_exc())
                self.menu_icon.set_visible(False)
示例#5
0
    def pack_items(self, trash, items):
        if self._size > 0 and self._size < 100:
            self.scale = self._size / 100.0
            root = SVGEditor.get_element(self.editor, "root")
            SVGEditor.scale(root, self.scale)
        pb = self.b.get_pixbuf()
        # Image width is not scaled as everything bellow operates
        # in 'root' object coordinate space
        image_width = pb.get_width()

        index = 0
        item_offset = 360.0 / len(self.items)
        a1 = (-90.0 - item_offset * 0.5) * PI / 180.0
        a2 = (-90.0 + item_offset * 0.5) * PI / 180.0
        for i in self.items_with_icon:
            i.icon_widget.get_parent().remove_child(i.icon_widget)
        self.items_with_icon = []
        for i in items:
            # Set size of each arc
            if SVGEditor.get_element(i.widget, "arc") is not None:
                l = SVGEditor.get_element(i.widget, "arc")
                radius = float(
                    l.attrib["radius"]
                )  # TODO: Find how to get value of 'sodipodi:rx'
                l.attrib["d"] = l.attrib["d-template"] % (
                    radius * cos(a1) + image_width / 2,
                    radius * sin(a1) + image_width / 2,
                    radius * cos(a2) + image_width / 2,
                    radius * sin(a2) + image_width / 2,
                )
            # Rotate arc to correct position
            i.a = (360.0 / float(len(self.items))) * float(index)
            SVGEditor.rotate(i.widget, i.a, image_width * 0.5,
                             image_width * 0.5)
            # Check if there is any icon
            icon_file, has_colors = find_icon(i.icon, False) if hasattr(
                i, "icon") else (None, False)
            if icon_file:
                # Icon - hide all text and place MenuIcon widget on top of image
                self.editor.remove_element(
                    SVGEditor.get_element(i.widget, "menuitem_text"))
                self.editor.remove_element(
                    SVGEditor.get_element(i.widget, "line0"))
                self.editor.remove_element(
                    SVGEditor.get_element(i.widget, "line2"))
                i.icon_widget = MenuIcon(icon_file, has_colors)
                i.icon_widget.set_name("osd-radial-menu-icon")
                i.icon_widget.set_size_request(self.ICON_SIZE * self.scale,
                                               self.ICON_SIZE * self.scale)
                self.b.get_parent().put(i.icon_widget, 200, 200)
                self.items_with_icon.append(i)
            else:
                # No icon - rotate text in arc to other direction to keep it horisontal
                if SVGEditor.get_element(i.widget,
                                         "menuitem_text") is not None:
                    l = SVGEditor.get_element(i.widget, "menuitem_text")
                    l.attrib['id'] = "text_" + i.id
                    l.attrib['transform'] = "%s rotate(%s)" % (
                        l.attrib['transform'], -i.a)
                # Place up to 3 lines of item label
                label = i.label.split("\n")
                first_line = 0
                if len(label) == 1:
                    self.editor.remove_element(
                        SVGEditor.get_element(i.widget, "line0"))
                    self.editor.remove_element(
                        SVGEditor.get_element(i.widget, "line2"))
                    first_line = 1
                elif len(label) == 2:
                    self.editor.remove_element(
                        SVGEditor.get_element(i.widget, "line0"))
                    first_line = 1
                for line in xrange(0, len(label)):
                    l = SVGEditor.get_element(i.widget,
                                              "line%s" % (first_line + line, ))
                    if l is None:
                        break
                    SVGEditor.set_text(l, label[line])
            # Continue with next menu item
            i.index = index

            index += 1

        self.editor.remove_element("menuitem_template")
        self.editor.commit()
        del self.editor