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