def choose_editor(self, action, title, id=None): """ Chooses apropripate Editor instance for edited action """ if isinstance(action, SensitivityModifier): action = action.action if isinstance(action, FeedbackModifier): action = action.action if id in GYROS: e = ActionEditor(self.app, self.on_action_chosen) e.set_title(title) elif isinstance(action, (ModeModifier, DoubleclickModifier, HoldModifier)) and not is_gyro_enable(action): e = ModeshiftEditor(self.app, self.on_action_chosen) e.set_title(_("Mode Shift for %s") % (title,)) elif RingEditor.is_ring_action(action): e = RingEditor(self.app, self.on_action_chosen) e.set_title(title) elif isinstance(action, Type): # Type is subclass of Macro e = ActionEditor(self.app, self.on_action_chosen) e.set_title(title) elif isinstance(action, Macro) and not (is_button_togle(action) or is_button_repeat(action)): e = MacroEditor(self.app, self.on_action_chosen) e.set_title(_("Macro for %s") % (title,)) else: e = ActionEditor(self.app, self.on_action_chosen) e.set_title(title) return e
def _add_refereced_menu(self, model, menu_id, used): """ As _add_refereced_profile, but reads and parses menu file. """ if "." in menu_id and menu_id not in used: # Dot in id means filename used.add(menu_id) filename = find_menu(menu_id) name = ".".join(menu_id.split(".")[0:-1]) if name.startswith(".") and menu_is_default(menu_id): # Default and hidden, don't bother user with it return if filename: model.append((not menu_is_default(menu_id), _("Menu"), name, filename, True, self.TP_MENU)) try: menu = MenuData.from_file(filename, ActionParser()) except Exception, e: # Menu that cannot be parsed shouldn't be exported log.error(e) return for item in menu: if isinstance(item, Submenu): self._add_refereced_menu(model, os.path.split(item.filename)[-1], used) if hasattr(item, "action"): self._parse_action(model, item.action, used) else: model.append((False, _("Menu"), _("%s (not found)") % (name,), "", False, self.TP_MENU))
def describe(self, context): if self.name: return self.name axis, neg, pos = self._get_axis_description() if context in (Action.AC_STICK, Action.AC_PAD): xy = "X" if self.parameters[0] in AxisAction.X else "Y" return _("%s %s (reversed)") % (axis, xy) return _("Reverse %s Axis") % (axis,)
def describe(self, context): if self.name: return self.name if self.parameters[0] == Rels.REL_WHEEL: return _("Circular Wheel") elif self.parameters[0] == Rels.REL_HWHEEL: return _("Circular Horizontal Wheel") return _("Circular Mouse %s") % (self.parameters[0].name.split("_", 1)[-1],)
def select_gyro_button(self, item): """ Just sets combobox value """ cb = self.builder.get_object("cbGyroButton") rvSoftLevel = self.builder.get_object("rvSoftLevel") sclSoftLevel = self.builder.get_object("sclSoftLevel") lblSoftLevel = self.builder.get_object("lblSoftLevel") model = cb.get_model() self._recursing = True button = None if isinstance(item, RangeOP): button = nameof(item.what) sclSoftLevel.set_value(item.value) rvSoftLevel.set_reveal_child(True) if item.what == STICK: lblSoftLevel.set_label(_("Stick deadzone")) else: lblSoftLevel.set_label(_("Trigger Pull Level")) elif item is not None: button = nameof(item.name) for row in model: if button == row[0] and row[1] != None: cb.set_active_iter(row.iter) self._recursing = False return self._recursing = False
def on_menus_loaded(self, menus): cb = self.builder.get_object("cbMenus") cb.set_row_separator_func( lambda model, iter : model.get_value(iter, 1) is None ) model = cb.get_model() model.clear() i, current_index = 0, 0 if self.allow_in_profile: # Add menus from profile for key in sorted(self.app.current.menus): model.append((key, key)) if self._current_menu == key: current_index = i i += 1 if i > 0: model.append((None, None)) # Separator i += 1 if self.allow_globals: for f in menus: key = f.get_basename() name = key if "." in name: name = _("%s (global)" % (name.split(".")[0])) model.append((name, key)) if self._current_menu == key: current_index = i i += 1 if i > 0: model.append((None, None)) # Separator model.append(( _("New Menu..."), "" )) self._recursing = True cb.set_active(current_index) self._recursing = False self.on_cbMenus_changed()
def on_txName2_changed(self, *a): txName2 = self.builder.get_object("txName2") btNext = self.enable_next(True, self.on_scc_import_confirmed) files = self.builder.get_object("lstImportPackage") cbImportHidden = self.builder.get_object("cbImportPackageHidden") cbImportVisible = self.builder.get_object("cbImportPackageVisible") cbImportNone = self.builder.get_object("cbImportPackageNone") rvAdvanced = self.builder.get_object("rvImportPackageAdvanced") btNext.set_label('Apply') btNext.set_use_stock(True) main_name = txName2.get_text().decode("utf-8") if self.check_name(main_name): btNext.set_sensitive(True) else: btNext.set_sensitive(False) cbImportHidden.set_label(_("Import as hidden menus and profiles named \".%s:name\"") % (main_name,)) cbImportVisible.set_label(_("Import normaly, with names formated as \"%s:name\"") % (main_name,)) for i in xrange(0, len(files)): enabled, name, importas, type, obj = files[i] if enabled == 2: importas = main_name elif cbImportHidden.get_active(): importas = ".%s:%s" % (main_name, name) enabled = 1 elif cbImportVisible.get_active(): importas = "%s:%s" % (main_name, name) enabled = 1 elif cbImportNone.get_active(): enabled = 0 files[i] = enabled, name, importas, type, obj
def on_button(self, keycode, pressed): #if len(self.grabbed) == 2 and self.grabbed[X] != None: # # Already grabbed one axis, don't grab buttons # return if keycode in self.grabbed: # Don't allow same button to be used twice return if not pressed: if len(self.grabbed) < 4: self.grabbed = [ None ] * 4 if self.grabbed[0] is None: self.grabbed[0] = keycode self.set_message(_("Move DPAD to right")) elif self.grabbed[1] is None: self.grabbed[1] = keycode self.set_message(_("Move DPAD up")) elif self.grabbed[2] is None: self.grabbed[2] = keycode self.set_message(_("Move DPAD down")) elif self.grabbed[3] is None: self.grabbed[3] = keycode self.set_message(str(self.grabbed)) grabbed = [] + self.grabbed for w in self.what: for negative in (False, True): keycode, grabbed = grabbed[0], grabbed[1:] w.reset() self.set_mapping(keycode, DPadEmuData(w, negative)) self.parent.generate_unassigned() self.parent.generate_raw_data() self.cancel()
def set_profile_modified(self, has_changes, is_template=False): """ Called to signalize that profile has changes to save in UI by displaying "changed" next to profile name and showing Save button. Returns giofile for currently selected profile. If profile is set as changed, giofile is automatically changed to 'original/filename.mod', so application can save changes without overwriting original wile. """ if has_changes: if not self._savebutton: # Save button has to be created self._savebutton = ButtonInRevealer( "gtk-save", _("Save changes"), self.on_savebutton_clicked) self._box.pack_start(self._savebutton, False, True, 0) self.show_all() self._savebutton.set_reveal_child(True) iter = self._combo.get_active_iter() if is_template: self._model.set_value(iter, 2, _("(changed template)")) else: self._model.set_value(iter, 2, _("(changed)")) else: if self._savebutton: # Nothing to hide if there is no revealer self._savebutton.set_reveal_child(False) for i in self._model: i[2] = None if is_template: iter = self._combo.get_active_iter() self._model.set_value(iter, 2, _("(template)"))
def on_mnuMenuDelete_activate(self, *a): id = self.get_selected_menu() if MenuEditor.menu_is_global(id): text = _("Really delete selected global menu?") else: text = _("Really delete selected menu?") d = Gtk.MessageDialog(parent=self.editor.window, flags = Gtk.DialogFlags.MODAL, type = Gtk.MessageType.WARNING, buttons = Gtk.ButtonsType.OK_CANCEL, message_format = text, ) if MenuEditor.menu_is_global(id): d.format_secondary_text(_("This action is not undoable!")) if d.run() == -5: # OK button, no idea where is this defined... if MenuEditor.menu_is_global(id): fname = os.path.join(get_menus_path(), id) try: os.unlink(fname) except Exception, e: log.error("Failed to remove %s: %s", fname, e) else: del self.app.current.menus[id] self.app.on_profile_modified() self.load_menu_list()
def describe_button(button): if button in ButtonAction.SPECIAL_NAMES: return _(ButtonAction.SPECIAL_NAMES[button]) elif button in MOUSE_BUTTONS: return _("Mouse %s") % (button,) elif button is None: # or isinstance(button, NoAction): return "None" return button.name.split("_", 1)[-1]
def on_cbInvertGyro_toggled(self, cb, *a): lblGyroEnable = self.builder.get_object("lblGyroEnable") if cb.get_active(): lblGyroEnable.set_label(_("Gyro Disable Button")) else: lblGyroEnable.set_label(_("Gyro Enable Button")) if not self._recursing: self.send()
def describe(self, context): if self.name: return self.name if self._mouse_axis == Rels.REL_WHEEL: return _("Wheel") elif self._mouse_axis == Rels.REL_HWHEEL: return _("Horizontal Wheel") elif self._mouse_axis in (PITCH, YAW, ROLL, None): return _("Mouse") else: return _("Mouse %s") % (self._mouse_axis.name.split("_", 1)[-1],)
def describe(self, context): if self.name: return self.name if self.parameters[0] == Rels.REL_WHEEL: return _("Wheel") elif self.parameters[0] == Rels.REL_HWHEEL: return _("Horizontal Wheel") elif self.parameters[0] in (PITCH, YAW, ROLL): return _("Mouse") else: return _("Mouse %s") % (self.parameters[0].name.split("_", 1)[-1],)
def load(self): if AEComponent.load(self): markup = "" if self.editor.get_mode() == Action.AC_PAD: markup = MARKUP_PAD elif self.editor.get_mode() == Action.AC_STICK: markup = MARKUP_STICK elif self.editor.get_mode() == Action.AC_GYRO: markup = MARKUP_GYRO elif self.editor.get_mode() == Action.AC_TRIGGER: markup = MARKUP_TRIGGER else: markup = MARKUP_BUTTON long_names = { 'LPAD' : _("Left Pad"), 'RPAD' : _("Right Pad"), 'LGRIP' : _("Left Grip"), 'RGRIP' : _("Right Grip"), 'LB' : _("Left Bumper"), 'RB' : _("Right Bumper"), 'LEFT' : _("Left Trigger"), 'RIGHT' : _("Right Trigger"), 'STICK' : _("Stick"), } markup = markup % { 'what' : long_names.get(nameof(self.editor.get_id()), nameof(self.editor.get_id()).title()) } self.builder.get_object("lblMarkup").set_markup(markup.strip(" \r\n\t")) return True
def _choose_editor(self, action, cb): if isinstance(action, Macro): from scc.gui.macro_editor import MacroEditor # Cannot be imported @ top e = MacroEditor(self.app, cb) e.set_title(_("Edit Macro")) else: from scc.gui.action_editor import ActionEditor # Cannot be imported @ top e = ActionEditor(self.app, cb) e.set_title(_("Edit Action")) e.hide_modeshift() return e
def on_sclMenuSize_format_value(self, scale, val): cbm = self.builder.get_object("cbMenuType") menu_type = cbm.get_model().get_value(cbm.get_active_iter(), 1) if menu_type == "radialmenu": if val < 1: return _("default") return "%s%%" % (int(val),) else: # if menu_type == "hmenu" val = int(val) if val < 2: return _("default") return str(int(val))
def describe(self, context): if self.name: return self.name if self.button in ButtonAction.SPECIAL_NAMES: return _(ButtonAction.SPECIAL_NAMES[self.button]) elif self.button == Rels.REL_WHEEL: if len(self.parameters) < 2 or self.parameters[1] > 0: return _("Wheel UP") else: return _("Wheel DOWN") elif self.button in MOUSE_BUTTONS: return _("Mouse %s") % (self.button,) return self.button.name.split("_", 1)[-1]
def _choose_editor(self, action, cb): if isinstance(action, ModeModifier): from scc.gui.modeshift_editor import ModeshiftEditor # Cannot be imported @ top e = ModeshiftEditor(self.app, cb) e.set_title(_("Edit Action")) else: from scc.gui.action_editor import ActionEditor # Cannot be imported @ top e = ActionEditor(self.app, cb) e.set_title(_("Edit Action")) e.hide_macro() e.hide_ring() return e
def on_change_delay(self, scale, trash, value, data): """ Called when delay slider is moved """ ms = int(value) action = data[0] label = data[-1][-2] action.delay = value / 1000.0 if ms < 1000: label.set_markup(_("<b>Delay: %sms</b>") % (ms,)) else: s = ms / 1000.0 label.set_markup(_("<b>Delay: %0.2fs</b>") % (s,)) self.update_action_field()
def _choose_editor(self, action, title): if isinstance(action, SensitivityModifier): action = action.action if isinstance(action, ModeModifier) and not is_gyro_enable(action): e = ModeshiftEditor(self, self.on_action_chosen) e.set_title(_("Mode Shift for %s") % (title,)) elif isinstance(action, Macro): e = MacroEditor(self, self.on_action_chosen) e.set_title(_("Macro for %s") % (title,)) else: e = ActionEditor(self, self.on_action_chosen) e.set_title(title) return e
def describe(self, context): if self.name: return self.name elif self.button == Rels.REL_WHEEL: if len(self.parameters) < 2 or self.parameters[1] > 0: return _("Wheel UP") else: return _("Wheel DOWN") else: rv = [ ] for x in (self.button, self.button2): if x: rv.append(ButtonAction.describe_button(x)) return ", ".join(rv)
def on_new_clicked(self, ps, name): new_name = _("Copy of %s") % (name,) filename = os.path.join(get_profiles_path(), new_name + ".sccprofile") i = 0 while os.path.exists(filename): i += 1 new_name = _("Copy of %s (%s)") % (name, i) filename = os.path.join(get_profiles_path(), new_name + ".sccprofile") dlg = self.builder.get_object("dlgNewProfile") txNewProfile = self.builder.get_object("txNewProfile") txNewProfile.set_text(new_name) dlg.set_transient_for(self.window) dlg.show()
def check(self): """ Performs various (three) checks and reports possible problems """ # TODO: Maybe not best place to do this try: kernel_mods = [ line.split(" ")[0] for line in file("/proc/modules", "r").read().split("\n") ] except Exception: # Maybe running on BSD or Windows... kernel_mods = [ ] if len(kernel_mods) > 0 and "uinput" not in kernel_mods: # There is no uinput msg = _('uinput kernel module not loaded') msg += "\n\n" + _('Please, consult your distribution manual on how to enable uinput') self.show_error(msg) elif not os.path.exists("/dev/uinput"): # /dev/uinput missing msg = _('/dev/uinput doesn\'t exists') msg += "\n" + _('uinput kernel module is loaded, but /dev/uinput is missing.') #msg += "\n\n" + _('Please, consult your distribution manual on what in the world could cause this.') msg += "\n\n" + _('Please, consult your distribution manual on how to enable uinput') self.show_error(msg) elif not check_access("/dev/uinput"): # Cannot acces uinput msg = _('You don\'t have required access to /dev/uinput.') msg += "\n" + _('This will most likely prevent emulation from working.') msg += "\n\n" + _('Please, consult your distribution manual on how to enable uinput') self.show_error(msg)
def check_shell_commands(self): """ Check for shell commands in profiles being imported. If there are any shell commands found, displays warning page and lets user to confirm import of them. Othewise, goes straight to next page as if user already confirmed them. """ grShellCommands = self.builder.get_object("grShellCommands") tvShellCommands = self.builder.get_object("tvShellCommands") files = self.builder.get_object("lstImportPackage") model = tvShellCommands.get_model() model.clear() # Get all shell commands in all profiles for trash, trash, trash, trash, obj in files: if isinstance(obj.obj, Profile): for a in obj.obj.get_all_actions(): if isinstance(a, ShellCommandAction): model.append((False, a.command)) if len(model) > 0: # If there is shell command present, jump to warning page self.next_page(grShellCommands) btNext = self.enable_next(True, self.shell_import_confirmed) btNext.set_label(_("Continue")) btNext.set_sensitive(False) else: # Otherwise continue to next one self.shell_import_confirmed()
def on_btDPAD_clicked(self, b): """ 'Select DPAD Left Action' handler """ i = int(b.get_name()) ae = ActionEditor(self.app, self.on_choosen) ae.set_title(_("Select DPAD Action")) ae.set_button(i, self.actions[i]) ae.show(self.app.window)
def generate_widget(self, item): """ Generates gtk widget for specified menutitem """ if isinstance(item, Separator) and item.label: widget = Gtk.Button.new_with_label(item.label) widget.set_relief(Gtk.ReliefStyle.NONE) widget.set_name("osd-menu-separator") return widget elif isinstance(item, Separator): widget = Gtk.Separator(orientation=Gtk.Orientation.HORIZONTAL) widget.set_name("osd-menu-separator") return widget else: 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: widget.set_name("osd-menu-dummy") else: widget.set_name("osd-menu-item") return widget
def on_spMenuSize_format_value(self, spinner): val = int(spinner.get_adjustment().get_value()) if val < 1: spinner.get_buffer().set_text(_("auto"), -1) else: spinner.get_buffer().set_text(str(val), -1) return True
def on_cbProfile_changed(self, cb, *a): """ Called when user chooses profile in selection combo """ if self.recursing : return model = cb.get_model() iter = cb.get_active_iter() f = model.get_value(iter, 1) if f is None: if self.current_file is None: cb.set_active(0) else: self.select_profile(self.current_file.get_path()) new_name = os.path.split(self.current_file.get_path())[-1] if new_name.endswith(".mod"): new_name = new_name[0:-4] if new_name.endswith(".sccprofile"): new_name = new_name[0:-11] new_name = _("Copy of") + " " + new_name dlg = self.builder.get_object("dlgNewProfile") txNewProfile = self.builder.get_object("txNewProfile") txNewProfile.set_text(new_name) dlg.set_transient_for(self.window) dlg.show() else: self.load_profile(f) if not self.daemon_changed_profile: self.dm.set_profile(f.get_path()) self.save_profile_selection(f.get_path())
def on_btSaveAs_clicked(self, *a): # Grab stuff tvProfiles = self.builder.get_object("tvProfiles") model, iter = tvProfiles.get_selection().get_selected() # Determine format f = Gtk.FileFilter() if self._needs_package(): f.set_name("SC-Controller Profile Archive") fmt = "sccprofile.tar.gz" else: f.set_name("SC-Controller Profile") fmt = "sccprofile" f.add_pattern("*.%s" % (fmt,)) # Create dialog d = Gtk.FileChooserNative.new(_("Export to File..."), self.window, Gtk.FileChooserAction.SAVE) d.add_filter(f) d.set_do_overwrite_confirmation(True) # Set default filename d.set_current_name("%s.%s" % (model[iter][2], fmt)) if d.run() == Gtk.ResponseType.ACCEPT: fn = d.get_filename() if len(os.path.split(fn)[-1].split(".")) < 2: # User wrote filename without extension fn = "%s.%s" % (fn, fmt) if self._needs_package(): if self._export_package(model[iter][1], fn): self.window.destroy() else: if self._export(model[iter][1], fn): self.window.destroy()
def generate(self, menuhandler): return _("[ Window Lists ]")
def get_button_title(self): return _("DPAD or Menu")
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 describe(self): return _("[ All Profiles ]")
class ModeshiftEditor(Editor): GLADE = "modeshift_editor.glade" BUTTONS = ( # in order as displayed in combobox (SCButtons.A, _('A') ), (SCButtons.B, _('B') ), (SCButtons.X, _('X') ), (SCButtons.Y, _('Y') ), (None, None), (SCButtons.BACK, _('Back (select)') ), (SCButtons.C, _('Center') ), (SCButtons.START, _('Start') ), (None, None), (SCButtons.LGRIP, _('Left Grip') ), (SCButtons.RGRIP, _('Right Grip') ), (SCButtons.LB, _('Left Bumper') ), (SCButtons.RB, _('Right Bumper') ), (None, None), (SCButtons.LT, _('Left Trigger (full)') ), (SCButtons.RT, _('Right Trigger (full)') ), ("Soft LT", _('Left Trigger (soft)') ), ("Soft RT", _('Right Trigger (soft)') ), (None, None), (SCButtons.STICKPRESS, _('Stick Pressed') ), (SCButtons.LPAD, _('Left Pad Pressed') ), (SCButtons.RPAD, _('Right Pad Pressed') ), (SCButtons.LPADTOUCH, _('Left Pad Touched') ), (SCButtons.RPADTOUCH, _('Right Pad Touched') ), ) def __init__(self, app, callback): Editor.__init__(self) self.app = app self.id = None self.mode = Action.AC_BUTTON self.ac_callback = callback self.soft_level = -1 self.current_page = 0 self.actions = ( [], [], [] ) self.nomods = [ NoAction(), NoAction(), NoAction() ] self.setup_widgets() def setup_widgets(self): Editor.setup_widgets(self) cbButtonChooser = self.builder.get_object("cbButtonChooser") cbButtonChooser.set_row_separator_func( lambda model, iter : model.get_value(iter, 0) is None ) b = lambda a : self.builder.get_object(a) self.action_widgets = ( # Order goes: Grid, 1st Action Button, Clear Button # 1st group, 'pressed' ( b('grActions'), b('btDefault'), b('btClearDefault') ), # 2nd group, 'hold' ( b('grHold'), b('btHold'), b('btClearHold') ), # 2nd group, 'double-click' ( b('grDoubleClick'), b('btDoubleClick'), b('btClearDoubleClick') ), ) headerbar(self.builder.get_object("header")) def on_Dialog_destroy(self, *a): self.remove_added_widget() def _fill_button_chooser(self, *a): cbButtonChooser = self.builder.get_object("cbButtonChooser") model = cbButtonChooser.get_model() model.clear() for item, text in self.BUTTONS: if any([ x[0] == item for x in self.actions[self.current_page] ]): # Skip already added buttons continue if type(item) in (str, unicode): # Special case for soft pull items button = getattr(SCButtons, item.split(" ")[-1]) if any([ (isinstance(x, RangeOP) and x.what == button) for x in self.actions[self.current_page] ]): # Skip already added soft pulls continue if item == SCButtons.STICKPRESS: if self.id == nameof(SCButtons.LPAD): # Controller cannot handle pressing stick and lpad at once continue model.append(( None if item is None else nameof(item), text )) cbButtonChooser.set_active(0) def _add_action(self, index, what, action): cbButtonChooser = self.builder.get_object("cbButtonChooser") adjSoftLevel = self.builder.get_object("adjSoftLevel") rvSoftLevel = self.builder.get_object("rvSoftLevel") grActions = self.action_widgets[index][0] model = cbButtonChooser.get_model() for row in model: item = model.get_value(row.iter, 0) if item: if item == nameof(what): model.remove(row.iter) break if isinstance(what, RangeOP) and item.startswith("Soft"): if nameof(what.what) == item.split(" ")[-1]: model.remove(row.iter) break try: while model.get_value(model[0].iter, 0) is None: model.remove(model[0].iter) cbButtonChooser.set_active(0) except: pass i = len(self.actions[index]) + 1 l = Gtk.Label() if isinstance(what, RangeOP) and what.op == ">=": if self.soft_level == -1: # First Range added, load level from it self.soft_level = what.value if what.value > 0.0 else 0.75 adjSoftLevel.set_value(self.soft_level) rvSoftLevel.set_reveal_child(True) what.value = -1 if what.value == -1: # Range with value taken from "Soft Pull Level" slider l.set_markup("<b>%s (soft pull)</b>" % (nameof(what.what),)) else: # Any other range l.set_markup("<b>%s</b>" % (nameof(what),)) else: l.set_markup("<b>%s</b>" % (nameof(what),)) l.set_xalign(0.0) b = Gtk.Button.new_with_label(action.describe(self.mode)) b.set_property("hexpand", True) b.connect('clicked', self.on_actionb_clicked, index, what) clearb = Gtk.Button() clearb.set_image(Gtk.Image.new_from_stock("gtk-delete", Gtk.IconSize.SMALL_TOOLBAR)) clearb.set_relief(Gtk.ReliefStyle.NONE) clearb.connect('clicked', self.on_clearb_clicked, index, what) grActions.attach(l, 0, i, 1, 1) grActions.attach(b, 1, i, 1, 1) grActions.attach(clearb, 2, i, 1, 1) self.actions[index].append([ what, action, l, b, clearb ]) grActions.show_all() def on_clearb_clicked(self, trash, index, button): grActions = self.action_widgets[index][0] cbButtonChooser = self.builder.get_object("cbButtonChooser") model = cbButtonChooser.get_model() # Remove requested action from the list for i in xrange(0, len(self.actions[index])): if self.actions[index][i][0] == button: button, action, l, b, clearb = self.actions[index][i] for w in (l, b, clearb): grActions.remove(w) del self.actions[index][i] break # Move everything after that action one position up # - remove it for j in xrange(i, len(self.actions[index])): button, action, l, b, clearb = self.actions[index][j] for w in (l, b, clearb): grActions.remove(w) # - add it again for j in xrange(i, len(self.actions[index])): button, action, l, b, clearb = self.actions[index][j] grActions.attach(l, 0, j + 1, 1, 1) grActions.attach(b, 1, j + 1, 1, 1) grActions.attach(clearb, 2, j + 1, 1, 1) # Regenereate combobox with removed button added back to it # - Store acive item from in combobox active, i, index = None, 0, -1 try: active = model.get_value(cbButtonChooser.get_active_iter(), 0) except: pass # Clear entire combobox model.clear() # Fill it again for button, text in self.BUTTONS: model.append(( None if button is None else nameof(button), text )) if button is not None: if nameof(button) == active: index = i i += 1 # Reselect formely active item if index >= 0: cbButtonChooser.set_active(index) def _choose_editor(self, action, cb): if isinstance(action, Macro): from scc.gui.macro_editor import MacroEditor # Cannot be imported @ top e = MacroEditor(self.app, cb) e.set_title(_("Edit Macro")) else: from scc.gui.action_editor import ActionEditor # Cannot be imported @ top e = ActionEditor(self.app, cb) e.set_title(_("Edit Action")) e.hide_modeshift() return e def on_actionb_clicked(self, trash, index, clicked_button): for i in self.actions[index]: button, action, l, b, clearb = i if button == clicked_button: def on_chosen(id, action): b.set_label(action.describe(self.mode)) i[1] = action ae = self._choose_editor(action, on_chosen) ae.set_input(self.id, action, mode = self.mode) ae.show(self.window) return def on_ntbMore_switch_page(self, ntb, box, index): self.current_page = index self._fill_button_chooser() self.builder.get_object("cbButtonChooser").set_sensitive(box.get_sensitive()) self.builder.get_object("btAddAction").set_sensitive(box.get_sensitive()) def on_nomodbt_clicked(self, button, *a): actionButton = self.action_widgets[self.current_page][1] def on_chosen(id, action): actionButton.set_label(action.describe(self.mode)) self.nomods[self.current_page] = action ae = self._choose_editor(self.nomods[self.current_page], on_chosen) ae.set_input(self.id, self.nomods[self.current_page], mode = self.mode) ae.show(self.window) def on_nomodclear_clicked(self, button, *a): self.nomods[self.current_page] = NoAction() actionButton = self.action_widgets[self.current_page][1] actionButton.set_label(self.nomods[self.current_page].describe(self.mode)) def on_btAddAction_clicked(self, *a): cbButtonChooser = self.builder.get_object("cbButtonChooser") item = cbButtonChooser.get_model().get_value(cbButtonChooser.get_active_iter(), 0) if item.startswith("Soft"): b = getattr(SCButtons, item.split(" ")[-1]) rng = RangeOP(b, ">=", -1) self._add_action(self.current_page, rng, NoAction()) else: b = getattr(SCButtons, item) self._add_action(self.current_page, b, NoAction()) def on_sclSoftLevel_format_value(self, scale, value): return "%s%%" % (int(value * 100.0),) def on_btClear_clicked(self, *a): """ Handler for clear button """ action = NoAction() if self.ac_callback is not None: self.ac_callback(self.id, action) self.close() def on_btCustomActionEditor_clicked(self, *a): """ Handler for 'Custom Editor' button """ from scc.gui.action_editor import ActionEditor # Can't be imported on top e = ActionEditor(self.app, self.ac_callback) e.set_input(self.id, self._make_action(), mode = self.mode) e.hide_action_buttons() e.hide_advanced_settings() e.set_title(self.window.get_title()) e.force_page(e.load_component("custom"), True) self.send_added_widget(e) self.close() e.show(self.get_transient_for()) def on_cbHoldFeedback_toggled(self, cb, *a): rvHoldFeedbackAmplitude = self.builder.get_object("rvHoldFeedbackAmplitude") rvHoldFeedbackAmplitude.set_reveal_child(cb.get_active()) def on_btOK_clicked(self, *a): """ Handler for OK button """ if self.ac_callback is not None: self.ac_callback(self.id, self._make_action()) self.close() def _make_action(self): """ Generates and returns Action instance """ cbHoldFeedback = self.builder.get_object("cbHoldFeedback") sclHoldFeedback = self.builder.get_object("sclHoldFeedback") normalaction = self._save_modemod(0) holdaction = self._save_modemod(1) dblaction = self._save_modemod(2) if dblaction: action = DoubleclickModifier(dblaction, normalaction) action.holdaction = holdaction elif holdaction: action = HoldModifier(holdaction, normalaction) else: action = normalaction action.timeout = self.builder.get_object("adjTime").get_value() if cbHoldFeedback.get_active(): action = FeedbackModifier(HapticPos.BOTH, sclHoldFeedback.get_value(), action) return action def _save_modemod(self, index): """ Generates ModeModifier from page in Notebook """ adjSoftLevel = self.builder.get_object("adjSoftLevel") pars = [] for item, action, l, b, clearb in self.actions[index]: if isinstance(item, RangeOP) and item.value == -1: # Value taken from slider item.value = adjSoftLevel.get_value() pars += [ item, action ] if self.nomods[index]: pars += [ self.nomods[index] ] action = ModeModifier(*pars) if len(pars) == 0: # No action is actually set action = NoAction() elif len(pars) == 1: # Only default action left action = self.nomods[index] return action def _load_modemod(self, index, action): for key in action.mods: self._add_action(index, key, action.mods[key]) def _set_nomod_button(self, index, action): if isinstance(action, ModeModifier): self._load_modemod(index, action) self.nomods[index] = action.default else: self.nomods[index] = action actionButton = self.action_widgets[index][1] actionButton.set_label(self.nomods[index].describe(self.mode)) def set_input(self, id, action, mode=None): btDefault = self.builder.get_object("btDefault") lblPressAlone = self.builder.get_object("lblPressAlone") cbHoldFeedback = self.builder.get_object("cbHoldFeedback") sclHoldFeedback = self.builder.get_object("sclHoldFeedback") self.id = id self._fill_button_chooser() if id in STICKS: lblPressAlone.set_label(_("(no button pressed)")) self.mode = mode = mode or Action.AC_STICK elif id in PADS: lblPressAlone.set_label(_("(no button pressed)")) self.mode = mode = mode or Action.AC_PAD else: lblPressAlone.set_label(_("(pressed alone)")) self.mode = mode = mode or Action.AC_BUTTON self.set_title("Modeshift for %s" % (nameof(id) if id in SCButtons else str(id),)) if isinstance(action, FeedbackModifier): cbHoldFeedback.set_active(True) sclHoldFeedback.set_value(action.haptic.get_amplitude()) action = action.action else: cbHoldFeedback.set_active(False) sclHoldFeedback.set_value(512) if isinstance(action, ModeModifier): self._load_modemod(0, action) self._set_nomod_button(0, action.default) self._set_nomod_button(1, NoAction()) self._set_nomod_button(2, NoAction()) elif isinstance(action, DoubleclickModifier): # includes HoldModifier self._set_nomod_button(0, action.normalaction) self._set_nomod_button(1, action.holdaction) self._set_nomod_button(2, action.action) self.builder.get_object("adjTime").set_value(action.timeout) if mode == Action.AC_OSK: # This is kinda bad, but allowing Custom Editor # from OSK editor is in TODO self.builder.get_object("btCustomActionEditor").set_visible(False) if mode != Action.AC_BUTTON: for w in ("vbHold", "vbDoubleClick", "lblHold", "lblDoubleClick"): self.builder.get_object(w).set_sensitive(False)
def _get_axis_description(self): axis, neg, pos = "%s %s" % (self.id.name, _("Axis")), _("Negative"), _("Positive") if self.id in AxisAction.AXIS_NAMES: axis, neg, pos = [_(x) for x in AxisAction.AXIS_NAMES[self.id]] return axis, neg, pos
def describe(self): return self.label + " " + _(">>")
class GyroActionComponent(AEComponent): GLADE = "ae/gyro_action.glade" NAME = "gyro_action" CTXS = Action.AC_GYRO, PRIORITY = 3 BUTTONS = ( # in order as displayed in combobox (None, _('Always Active')), (None, None), (SCButtons.LT, _('Left Trigger')), (SCButtons.RT, _('Right Trigger')), (SCButtons.LB, _('Left Bumper')), (SCButtons.RB, _('Right Bumper')), (None, None), (SCButtons.LPADTOUCH, _('Left Pad Touched')), (SCButtons.RPADTOUCH, _('Right Pad Touched')), (SCButtons.LPAD, _('Left Pad Pressed')), (SCButtons.RPAD, _('Right Pad Pressed')), (None, None), (SCButtons.LGRIP, _('Left Grip')), (SCButtons.RGRIP, _('Right Grip')), (None, None), (SCButtons.A, _('A')), (SCButtons.B, _('B')), (SCButtons.X, _('X')), (SCButtons.Y, _('Y')), (None, None), (SCButtons.BACK, _('Back (select)')), (SCButtons.C, _('Center')), (SCButtons.START, _('Start')), ) def __init__(self, app, editor): AEComponent.__init__(self, app, editor) self._recursing = False self.parser = GuiActionParser() def load(self): if self.loaded: return AEComponent.load(self) self._recursing = True cbGyroButton = self.builder.get_object("cbGyroButton") fill_buttons(cbGyroButton) self._recursing = False def set_action(self, mode, action): if self.handles(mode, action): if isinstance(action, NoAction): self.select_gyro_output("none") self.select_gyro_button(None) return if isinstance(action, ModeModifier): b = action.order[0] action = action.mods[b] self.select_gyro_button(b) else: self.select_gyro_button(None) if isinstance(action, MouseAction): self.select_gyro_output("mouse") if len(action.parameters) >= 2 and action.parameters[1] == YAW: self.select_yaw_roll(YAW) else: self.select_yaw_roll(ROLL) elif isinstance(action, GyroAction): ap = action.parameters if len(ap) == 2: self.select_yaw_roll(YAW) else: self.select_yaw_roll(ROLL) if ap[0] == Axes.ABS_X and ap[-1] == Axes.ABS_Y: if isinstance(action, GyroAbsAction): self.select_gyro_output("left_abs") else: self.select_gyro_output("left") self.select_yaw_roll(ROLL) elif ap[0] == Axes.ABS_RX and ap[-1] == Axes.ABS_RY: if isinstance(action, GyroAbsAction): self.select_gyro_output("right_abs") else: self.select_gyro_output("right") self.select_yaw_roll(ROLL) def get_button_title(self): return _("Joystick or Mouse") def handles(self, mode, action): if isinstance(action, NoAction): return True if is_gyro_enable(action): action = action.mods[action.order[0]] if isinstance(action, GyroAction): # Takes GyroAbsAction as well ap = action.parameters if (len(ap) == 3 and not ap[1]) or len(ap) == 2: if ap[0] == Axes.ABS_X and ap[-1] == Axes.ABS_Y: return True if ap[0] == Axes.ABS_RX and ap[-1] == Axes.ABS_RY: return True return False if isinstance(action, MultiAction): return False return True def select_gyro_output(self, key): """ Just sets combobox value """ cb = self.builder.get_object("cbMode") model = cb.get_model() self._recursing = True for row in model: if key == row[2]: cb.set_active_iter(row.iter) self._recursing = False return self._recursing = False def select_yaw_roll(self, yawroll): """ Just sets combobox value """ cb = self.builder.get_object("cbYawRoll") model = cb.get_model() self._recursing = True for row in model: if yawroll == row[0]: cb.set_active_iter(row.iter) self._recursing = False return self._recursing = False def select_gyro_button(self, button): """ Just sets combobox value """ cb = self.builder.get_object("cbGyroButton") model = cb.get_model() self._recursing = True if button is not None: button = button.name for row in model: if button == row[0] and row[1] != None: cb.set_active_iter(row.iter) self._recursing = False return self._recursing = False def update(self, *a): pass def send(self, *a): if self._recursing: return cbMode = self.builder.get_object("cbMode") cbYawRoll = self.builder.get_object("cbYawRoll") cbGyroButton = self.builder.get_object("cbGyroButton") action = cbMode.get_model().get_value(cbMode.get_active_iter(), 0) yawroll = cbYawRoll.get_model().get_value(cbYawRoll.get_active_iter(), 0) button = cbGyroButton.get_model().get_value( cbGyroButton.get_active_iter(), 0) match = re.match(r"([^\[]+)\[([^\|]+)\|([^\]]+)\](.*)", action) if match: grps = match.groups() if yawroll == YAW: action = "%s%s%s" % (grps[0], grps[1], grps[3]) else: action = "%s%s%s" % (grps[0], grps[2], grps[3]) action = self.parser.restart(action).parse() if button: action = ModeModifier(getattr(SCButtons, button), action) self.editor.set_action(action)
def get_button_title(self): return _("Joystick or Mouse")
class GyroActionComponent(AEComponent): GLADE = "ae/gyro_action.glade" NAME = "gyro_action" CTXS = Action.AC_GYRO PRIORITY = 3 BUTTONS = ( # in order as displayed in combobox (None, _('Always Active')), (None, None), (SCButtons.LT, _('Left Trigger') ), (SCButtons.RT, _('Right Trigger') ), (SCButtons.LB, _('Left Bumper') ), (SCButtons.RB, _('Right Bumper') ), (None, None), (SCButtons.LPADTOUCH, _('Left Pad Touched') ), (SCButtons.RPADTOUCH, _('Right Pad Touched') ), (SCButtons.LPAD, _('Left Pad Pressed') ), (SCButtons.RPAD, _('Right Pad Pressed') ), (None, None), (SCButtons.LGRIP, _('Left Grip') ), (SCButtons.RGRIP, _('Right Grip') ), (STICK, _('Stick Tilted') ), (None, None), (SCButtons.A, _('A') ), (SCButtons.B, _('B') ), (SCButtons.X, _('X') ), (SCButtons.Y, _('Y') ), (None, None), (SCButtons.BACK, _('Back (select)') ), (SCButtons.C, _('Center') ), (SCButtons.START, _('Start') ), ) def __init__(self, app, editor): AEComponent.__init__(self, app, editor) self._recursing = False self.parser = GuiActionParser() def load(self): if self.loaded : return AEComponent.load(self) self._recursing = True cbGyroButton = self.builder.get_object("cbGyroButton") fill_buttons(cbGyroButton) self._recursing = False def set_action(self, mode, action): if self.handles(mode, action): if isinstance(action, NoAction): self.select_gyro_output("none") self.select_gyro_button(SCButtons.RPADTOUCH) return if isinstance(action, ModeModifier): self._recursing = True self.builder.get_object("cbInvertGyro").set_active(bool(action.default)) self._recursing = False b = action.mods.keys()[0] action = action.mods[b] or action.default self.select_gyro_button(b) else: self.select_gyro_button(None) if isinstance(action, SensitivityModifier) and isinstance(action.action, MouseAction): # Mouse (Desktop) self.select_gyro_output("mouse") if len(action.action.parameters) > 0 and action.action.parameters[0] == YAW: self.select_yaw_roll(YAW) else: self.select_yaw_roll(ROLL) self.editor.set_default_sensitivity(3.5, 3.5, 3.5) self.editor.set_sensitivity(*action.speeds) elif isinstance(action, MouseAction): # Mouse (Camera) self.select_gyro_output("mouse_cam") if len(action.parameters) > 0 and action.parameters[0] == YAW: self.select_yaw_roll(YAW) else: self.select_yaw_roll(ROLL) elif isinstance(action, GyroAction): ap = action.parameters if len(ap) == 2: self.select_yaw_roll(YAW) else: self.select_yaw_roll(ROLL) if ap[0] == Axes.ABS_X and ap[-1] == Axes.ABS_Y: if isinstance(action, GyroAbsAction): self.select_gyro_output("left_abs") else: self.select_gyro_output("left") elif ap[0] == Axes.ABS_RX and ap[-1] == Axes.ABS_RY: if isinstance(action, GyroAbsAction): self.select_gyro_output("right_abs") else: self.select_gyro_output("right") elif ap[0] == Rels.REL_Y and ap[-1] == Rels.REL_X: self.select_gyro_output("mouse_stick") self.modifier_updated() def modifier_updated(self): cbInvertY = self.builder.get_object("cbInvertY") sens = self.editor.get_sensitivity() inverted = len(sens) >= 2 and sens[1] < 0 if cbInvertY.get_active() != inverted: self._recursing = True cbInvertY.set_active(inverted) self._recursing = False def cbInvertY_toggled_cb(self, cb, *a): if self._recursing: return sens = list(self.editor.get_sensitivity()) # Ensure that editor accepts Y sensitivity if len(sens) >= 2: sens[1] = abs(sens[1]) if cb.get_active(): # Ensure that Y sensitivity is negative sens[1] *= -1 self.editor.set_sensitivity(*sens) def get_button_title(self): return _("Joystick or Mouse") def handles(self, mode, action): if isinstance(action, NoAction): return True if is_gyro_enable(action): action = action.mods.values()[0] or action.default if isinstance(action, SensitivityModifier): action = action.action if isinstance(action, GyroAction): # Takes GyroAbsAction as well ap = action.parameters if (len(ap) == 3 and not ap[1]) or len(ap) == 2: if ap[0] == Axes.ABS_X and ap[-1] == Axes.ABS_Y: return True elif ap[0] == Axes.ABS_RX and ap[-1] == Axes.ABS_RY: return True elif ap[0] == Rels.REL_Y and ap[-1] == Rels.REL_X: return True return False if isinstance(action, (MouseAction, MouseAbsAction)): return True return False def select_gyro_output(self, key): """ Just sets combobox value """ cb = self.builder.get_object("cbMode") model = cb.get_model() self._recursing = True for row in model: if key == row[2]: cb.set_active_iter(row.iter) self._recursing = False return self._recursing = False def select_yaw_roll(self, yawroll): """ Just sets combobox value """ cb = self.builder.get_object("cbYawRoll") model = cb.get_model() self._recursing = True for row in model: if yawroll == row[0]: cb.set_active_iter(row.iter) self._recursing = False return self._recursing = False def select_gyro_button(self, item): """ Just sets combobox value """ cb = self.builder.get_object("cbGyroButton") rvSoftLevel = self.builder.get_object("rvSoftLevel") sclSoftLevel = self.builder.get_object("sclSoftLevel") model = cb.get_model() self._recursing = True button = None if isinstance(item, RangeOP): button = nameof(item.what) sclSoftLevel.set_value(item.value) rvSoftLevel.set_reveal_child(True) elif item is not None: button = nameof(item.name) for row in model: if button == row[0] and row[1] != None: cb.set_active_iter(row.iter) self._recursing = False return self._recursing = False def on_cbInvertGyro_toggled(self, cb, *a): lblGyroEnable = self.builder.get_object("lblGyroEnable") if cb.get_active(): lblGyroEnable.set_label(_("Gyro Disable Button")) else: lblGyroEnable.set_label(_("Gyro Enable Button")) if not self._recursing: self.send() def on_sclSoftLevel_format_value(self, scale, value): return "%s%%" % (int(value * 100.0),) def update(self, *a): pass def hidden(self): self.editor.set_default_sensitivity(1, 1, 1) def send(self, *a): if self._recursing : return cbMode = self.builder.get_object("cbMode") cbYawRoll = self.builder.get_object("cbYawRoll") rvSoftLevel = self.builder.get_object("rvSoftLevel") sclSoftLevel = self.builder.get_object("sclSoftLevel") cbGyroButton = self.builder.get_object("cbGyroButton") cbInvertGyro = self.builder.get_object("cbInvertGyro") action = cbMode.get_model().get_value(cbMode.get_active_iter(), 0) key = cbMode.get_model().get_value(cbMode.get_active_iter(), 2) yawroll = cbYawRoll.get_model().get_value(cbYawRoll.get_active_iter(), 0) item = cbGyroButton.get_model().get_value(cbGyroButton.get_active_iter(), 0) rvSoftLevel.set_reveal_child(item in TRIGGERS) match = re.match(r"([^\[]+)\[([^\|]+)\|([^\]]+)\](.*)", action) if match: grps = match.groups() if yawroll == YAW: action = "%s%s%s" % (grps[0], grps[1], grps[3]) else: action = "%s%s%s" % (grps[0], grps[2], grps[3]) action = self.parser.restart(action).parse() if item and action: if item in TRIGGERS: what = RangeOP(getattr(SCButtons, item), ">=", sclSoftLevel.get_value()) elif item == STICK: what = RangeOP(item, ">=", sclSoftLevel.get_value()) else: what = getattr(SCButtons, item) if cbInvertGyro.get_active(): action = ModeModifier(what, NoAction(), action) else: action = ModeModifier(what, action) if key == "mouse": self.editor.set_default_sensitivity(3.5, 3.5, 3.5) else: self.editor.set_default_sensitivity(1, 1, 1) self.editor.set_action(action)
class StatusIcon(GObject.GObject): """ Base class for all status icon backends """ TRAY_TITLE = _("Syncthing") __gsignals__ = { b"clicked": (GObject.SIGNAL_RUN_FIRST, None, ()), } __gproperties__ = { b"active": (GObject.TYPE_BOOLEAN, "is the icon user-visible?", "does the icon back-end think that anything is might be shown to the user?", True, GObject.PARAM_READWRITE) } def __init__(self, icon_path, popupmenu, force=False): GObject.GObject.__init__(self) self.__icon_path = os.path.normpath(os.path.abspath(icon_path)) self.__popupmenu = popupmenu self.__active = True self.__visible = False self.__hidden = False self.__icon = "si-syncthing-unknown" self.__text = "" self.__force = force def get_active(self): """ Return whether there is at least a chance that the icon might be shown to the user If this returns `False` then the icon will definetely not be shown, but if it returns `True` it doesn't have to be visible... <em>Note:</em> This value is not directly influenced by calling `hide()` and `show()`. @return {bool} """ return self.get_property("active") def set(self, icon=None, text=None): """ Set the status icon image and descriptive text If either of these are `None` their previous value will be used. @param {String} icon The name of the icon to show (i.e. `si-syncthing-idle`) @param {String} text Some text that indicates what the application is currently doing (generally this be used for the tooltip) """ if not icon.endswith("-0"): # si-syncthing-0 # Ignore first syncing icon state to prevent the icon from flickering # into the main notification bar during initialization self.__visible = True if self.__hidden: self._set_visible(False) else: self._set_visible(self.__visible) def hide(self): """ Hide the icon This method tries its best to ensure the icon is hidden, but there are no guarantees as to how use well its going to work. """ self.__hidden = True self._set_visible(False) def show(self): """ Show a previously hidden icon This method tries its best to ensure the icon is hidden, but there are no guarantees as to how use well its going to work. """ self.__hidden = False self._set_visible(self.__visible) def is_clickable(self): """ Basically, returns False is appindicator is used """ return True def _is_forced(self): return self.__force def _on_click(self, *a): self.emit("clicked") def _get_icon(self, icon=None): """ @internal Use `set()` instead. """ if icon: self.__icon = icon return self.__icon def _get_text(self, text=None): """ @internal Use `set()` instead. """ if text: self.__text = text return self.__text def _get_popupmenu(self): """ @internal """ return self.__popupmenu def _set_visible(self, visible): """ @internal """ pass def do_get_property(self, property): if property.name == "active": return self.__active else: raise AttributeError("Unknown property %s" % property.name) def do_set_property(self, property, value): if property.name == "active": self.__active = value else: raise AttributeError("unknown property %s" % property.name)
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 get_button_title(self): return _("Per Axis")
class ModeshiftEditor(Editor): GLADE = "modeshift_editor.glade" BUTTONS = ( # in order as displayed in combobox (SCButtons.A, _('A')), (SCButtons.B, _('B')), (SCButtons.X, _('X')), (SCButtons.Y, _('Y')), (None, None), (SCButtons.BACK, _('Back (select)')), (SCButtons.C, _('Center')), (SCButtons.START, _('Start')), (None, None), (SCButtons.LGRIP, _('Left Grip')), (SCButtons.RGRIP, _('Right Grip')), (None, None), (SCButtons.LB, _('Left Bumper')), (SCButtons.RB, _('Right Bumper')), (SCButtons.LT, _('Left Trigger')), (SCButtons.RT, _('Right Trigger')), (None, None), (SCButtons.LPAD, _('Left Pad Pressed')), (SCButtons.RPAD, _('Right Pad Pressed')), (SCButtons.LPADTOUCH, _('Left Pad Touched')), (SCButtons.RPADTOUCH, _('Right Pad Touched')), ) def __init__(self, app, callback): self.app = app self.id = None self.mode = Action.AC_BUTTON self.ac_callback = callback self.current_page = 0 self.actions = ([], [], []) self.nomods = [NoAction(), NoAction(), NoAction()] self.setup_widgets() def setup_widgets(self): Editor.setup_widgets(self) cbButtonChooser = self.builder.get_object("cbButtonChooser") cbButtonChooser.set_row_separator_func( lambda model, iter: model.get_value(iter, 0) is None) b = lambda a: self.builder.get_object(a) self.action_widgets = ( # Order goes: Grid, 1st Action Button, Clear Button # 1st group, 'pressed' (b('grActions'), b('btDefault'), b('btClearDefault')), # 2nd group, 'hold' (b('grHold'), b('btHold'), b('btClearHold')), # 2nd group, 'double-click' (b('grDoubleClick'), b('btDoubleClick'), b('btClearDoubleClick')), ) self._fill_button_chooser() headerbar(self.builder.get_object("header")) def _fill_button_chooser(self, *a): cbButtonChooser = self.builder.get_object("cbButtonChooser") model = cbButtonChooser.get_model() model.clear() for button, text in self.BUTTONS: if any([ True for x in self.actions[self.current_page] if x[0] == button ]): # Skip already added buttons continue model.append((None if button is None else button.name, text)) cbButtonChooser.set_active(0) def _add_action(self, index, button, action): grActions = self.action_widgets[index][0] cbButtonChooser = self.builder.get_object("cbButtonChooser") model = cbButtonChooser.get_model() for row in model: if model.get_value(row.iter, 0) == button.name: model.remove(row.iter) break try: while model.get_value(model[0].iter, 0) is None: model.remove(model[0].iter) cbButtonChooser.set_active(0) except: pass i = len(self.actions[index]) + 1 l = Gtk.Label() l.set_markup("<b>%s</b>" % (button.name, )) l.set_xalign(0.0) b = Gtk.Button.new_with_label(action.describe(self.mode)) b.set_property("hexpand", True) b.connect('clicked', self.on_actionb_clicked, index, button) clearb = Gtk.Button() clearb.set_image( Gtk.Image.new_from_stock("gtk-delete", Gtk.IconSize.SMALL_TOOLBAR)) clearb.set_relief(Gtk.ReliefStyle.NONE) clearb.connect('clicked', self.on_clearb_clicked, index, button) grActions.attach(l, 0, i, 1, 1) grActions.attach(b, 1, i, 1, 1) grActions.attach(clearb, 2, i, 1, 1) self.actions[index].append([button, action, l, b, clearb]) grActions.show_all() def on_clearb_clicked(self, trash, index, button): grActions = self.action_widgets[index][0] cbButtonChooser = self.builder.get_object("cbButtonChooser") model = cbButtonChooser.get_model() # Remove requested action from the list for i in xrange(0, len(self.actions[index])): if self.actions[index][i][0] == button: button, action, l, b, clearb = self.actions[index][i] for w in (l, b, clearb): grActions.remove(w) del self.actions[index][i] break # Move everything after that action one position up # - remove it for j in xrange(i, len(self.actions[index])): button, action, l, b, clearb = self.actions[index][j] for w in (l, b, clearb): grActions.remove(w) # - add it again for j in xrange(i, len(self.actions[index])): button, action, l, b, clearb = self.actions[index][j] grActions.attach(l, 0, j + 1, 1, 1) grActions.attach(b, 1, j + 1, 1, 1) grActions.attach(clearb, 2, j + 1, 1, 1) # Regenereate combobox with removed button added back to it # - Store acive item from in combobox active, i, index = None, 0, -1 try: active = model.get_value(cbButtonChooser.get_active_iter(), 0) except: pass # Clear entire combobox model.clear() # Fill it again for button, text in self.BUTTONS: model.append((None if button is None else button.name, text)) if button is not None: if button.name == active: index = i i += 1 # Reselect formely active item if index >= 0: cbButtonChooser.set_active(index) def _choose_editor(self, action, cb): if isinstance(action, Macro): from scc.gui.macro_editor import MacroEditor # Cannot be imported @ top e = MacroEditor(self.app, cb) e.set_title(_("Edit Macro")) else: from scc.gui.action_editor import ActionEditor # Cannot be imported @ top e = ActionEditor(self.app, cb) e.set_title(_("Edit Action")) e.hide_modeshift() return e def on_actionb_clicked(self, trash, index, clicked_button): for i in self.actions[index]: button, action, l, b, clearb = i if button == clicked_button: def on_chosen(id, action): b.set_label(action.describe(self.mode)) i[1] = action ae = self._choose_editor(action, on_chosen) ae.set_input(self.id, action, mode=self.mode) ae.show(self.window) return def on_ntbMore_switch_page(self, ntb, box, index): self.current_page = index self._fill_button_chooser() self.builder.get_object("cbButtonChooser").set_sensitive( box.get_sensitive()) self.builder.get_object("btAddAction").set_sensitive( box.get_sensitive()) def on_nomodbt_clicked(self, button, *a): actionButton = self.action_widgets[self.current_page][1] def on_chosen(id, action): actionButton.set_label(action.describe(self.mode)) self.nomods[self.current_page] = action ae = self._choose_editor(self.nomods[self.current_page], on_chosen) ae.set_input(self.id, self.nomods[self.current_page], mode=self.mode) ae.show(self.window) def on_nomodclear_clicked(self, button, *a): self.nomods[self.current_page] = NoAction() actionButton = self.action_widgets[self.current_page][1] actionButton.set_label(self.nomods[self.current_page].describe( self.mode)) def on_btAddAction_clicked(self, *a): cbButtonChooser = self.builder.get_object("cbButtonChooser") b = getattr( SCButtons, cbButtonChooser.get_model().get_value( cbButtonChooser.get_active_iter(), 0)) self._add_action(self.current_page, b, NoAction()) def on_btClear_clicked(self, *a): """ Handler for clear button """ action = NoAction() if self.ac_callback is not None: self.ac_callback(self.id, action) self.close() def on_btCustomActionEditor_clicked(self, *a): """ Handler for 'Custom Editor' button """ from scc.gui.action_editor import ActionEditor # Can't be imported on top e = ActionEditor(self.app, self.ac_callback) e.set_input(self.id, self._make_action(), mode=self.mode) e.hide_action_buttons() e.hide_advanced_settings() e.set_title(self.window.get_title()) e.force_page(e.load_component("custom"), True) self.close() e.show(self.get_transient_for()) def on_btOK_clicked(self, *a): """ Handler for OK button """ if self.ac_callback is not None: self.ac_callback(self.id, self._make_action()) self.close() def _make_action(self): """ Generates and returns Action instance """ normalaction = self._save_modemod(0) holdaction = self._save_modemod(1) dblaction = self._save_modemod(2) if dblaction: action = DoubleclickModifier(dblaction, normalaction) action.holdaction = holdaction elif holdaction: action = HoldModifier(holdaction, normalaction) else: action = normalaction action.timeout = self.builder.get_object("adjTime").get_value() return action def _save_modemod(self, index): """ Generates ModeModifier from page in Notebook """ pars = [] # TODO: Other pages for button, action, l, b, clearb in self.actions[index]: pars += [button, action] if self.nomods[index]: pars += [self.nomods[index]] action = ModeModifier(*pars) if len(pars) == 0: # No action is actually set action = NoAction() elif len(pars) == 1: # Only default action left action = self.nomods[index] return action def _load_modemod(self, index, action): for key in action.mods: self._add_action(index, key, action.mods[key]) def _set_nomod_button(self, index, action): if isinstance(action, ModeModifier): self._load_modemod(index, action) self.nomods[index] = action.default else: self.nomods[index] = action actionButton = self.action_widgets[index][1] actionButton.set_label(self.nomods[index].describe(self.mode)) def set_input(self, id, action, mode=Action.AC_BUTTON): btDefault = self.builder.get_object("btDefault") self.id = id self.mode = mode self.set_title("Modeshift for %s" % (id.name if id in SCButtons else str(id), )) if isinstance(action, ModeModifier): self._load_modemod(0, action) self._set_nomod_button(0, action.default) self._set_nomod_button(1, NoAction()) self._set_nomod_button(2, NoAction()) elif isinstance(action, DoubleclickModifier): # includes HoldModifier self._set_nomod_button(0, action.normalaction) self._set_nomod_button(1, action.holdaction) self._set_nomod_button(2, action.action) self.builder.get_object("adjTime").set_value(action.timeout) if mode == Action.AC_OSK: # This is kinda bad, but allowing Custom Editor # from OSK editor is in TODO self.builder.get_object("btCustomActionEditor").set_visible(False) if mode != Action.AC_BUTTON: for w in ("vbHold", "vbDoubleClick", "lblHold", "lblDoubleClick"): self.builder.get_object(w).set_sensitive(False)
def describe(self, context): if self.name: return self.name return _("Mouse Region")
def describe(self, context): return _("(not set)")
def grab_action(self, button, cb): b = SimpleChooser(self.app, "buttons", cb) b.set_title(_("Select Button")) b.hide_axes() b.display_action(Action.AC_BUTTON, ButtonAction(button)) b.show(self.editor.window)
def get_button_title(self): return _("On-Screen Keyboard")
def grab_action(self, action, cb): b = SimpleChooser(self.app, "axis", cb) b.set_title(_("Select Axis")) area = action_to_area(action) b.display_action(Action.AC_STICK, area) b.show(self.editor.window)
def get_button_title(self): return _("Special Action")
def get_button_title(self): return _("Recent List")
def generate(self, menuhandler): return _("[ %s Recent Profiles ]") % (self.rows,)
def describe(self): if self.label: return _("----[ %s ]----") % (self.label,) else: return _("---- Separator ----")
def get_button_title(self): return _("Menu")
def update(self): if self.id in TRIGGERS and self.id in self.app.current.triggers: self.label.set_label(self.app.current.triggers[self.id].describe( self.ACTION_CONTEXT)) else: self.label.set_label(_("(no action)"))
def update(self): self.label.set_label(_("(no action)"))
def get_button_title(self): return _("Key or Button")
def on_btAnalog_clicked(self, *a): """ 'Analog Output' handler """ b = SimpleChooser(self.app, "axis", lambda action: self.on_action_chosen("analog", action) ) b.set_title(_("Select Analog Axis")) b.display_action(Action.AC_STICK, AxisAction(self.analog)) b.show(self.editor.window)
def check(self): """ Performs various (three) checks and reports possible problems """ # TODO: Maybe not best place to do this try: # Dynamic modules rawlist = file("/proc/modules", "r").read().split("\n") kernel_mods = [ line.split(" ")[0] for line in rawlist ] # Built-in modules release = platform.uname()[2] rawlist = file("/lib/modules/%s/modules.builtin" % release, "r").read().split("\n") kernel_mods += [ os.path.split(x)[-1].split(".")[0] for x in rawlist ] except Exception: # Maybe running on BSD or Windows... kernel_mods = [ ] if len(kernel_mods) > 0 and "uinput" not in kernel_mods: # There is no uinput msg = _('uinput kernel module not loaded') msg += "\n\n" + _('Please, consult your distribution manual on how to enable uinput') msg += "\n" + _('or click on "Fix Temporary" button to attempt fix that should work until next restart.') ribar = self.show_error(msg) gksudo = find_gksudo() modprobe = find_binary("modprobe") if gksudo and not hasattr(ribar, "_fix_tmp"): button = Gtk.Button.new_with_label(_("Fix Temporary")) ribar._fix_tmp = button button.connect('clicked', self.apply_temporary_fix, gksudo + [modprobe, "uinput"], _("This will load missing uinput module.") ) ribar.add_button(button, -1) return True elif not os.path.exists("/dev/uinput"): # /dev/uinput missing msg = _('/dev/uinput doesn\'t exists') msg += "\n" + _('uinput kernel module is loaded, but /dev/uinput is missing.') #msg += "\n\n" + _('Please, consult your distribution manual on what in the world could cause this.') msg += "\n\n" + _('Please, consult your distribution manual on how to enable uinput') self.show_error(msg) return True elif not check_access("/dev/uinput"): # Cannot acces uinput msg = _('You don\'t have required access to /dev/uinput.') msg += "\n" + _('This will most likely prevent emulation from working.') msg += "\n\n" + _('Please, consult your distribution manual on how to enable uinput') msg += "\n" + _('or click on "Fix Temporary" button to attempt fix that should work until next restart.') ribar = self.show_error(msg) gksudo = find_gksudo() if gksudo and not hasattr(ribar, "_fix_tmp"): button = Gtk.Button.new_with_label(_("Fix Temporary")) ribar._fix_tmp = button button.connect('clicked', self.apply_temporary_fix, gksudo + ["chmod", "666", "/dev/uinput"], _("This will enable input emulation for <i>every application</i> and <i>all users</i> on this machine.") ) ribar.add_button(button, -1) return True return False
def set_input(self, id, action, mode=None): """ Setups action editor for editing specified input. Mode (buttton/axis/trigger...) is either provided or chosen based on id. Also sets title, but that can be overriden by calling set_title after. """ self.id = id if id in SCButtons or mode in (Action.AC_MENU, Action.AC_BUTTON): if id in PRESSABLE: self.set_title(_("%s Press") % (nameof(id),)) elif id in SCButtons: self.set_title(nameof(id),) self._set_mode(action, mode or Action.AC_BUTTON) self.hide_sensitivity(0, 1, 2) self.hide_rotation() self.hide_hide_enable_deadzones() self.hide_require_click() self.set_action(action) elif id in TRIGGERS: self.set_title(_("%s Trigger") % (id,)) self._set_mode(action, mode or Action.AC_TRIGGER) self.hide_modifiers() self.set_action(action) self.hide_macro() elif id in STICKS: self.set_title(_("Stick")) self._set_mode(action, mode or Action.AC_STICK) self.hide_sensitivity(2) # Z only self.hide_require_click() self.hide_osd() self.set_action(action) self.hide_macro() self.id = Profile.STICK elif id in GYROS: self.set_title(_("Gyro")) self._set_mode(action, mode or Action.AC_GYRO) self.set_action(action) self.hide_rotation() self.hide_require_click() self.hide_hide_enable_deadzones() self.hide_osd() self.hide_macro() self.hide_modeshift() self.id = Profile.GYRO elif id in PADS: self._set_mode(action, mode or Action.AC_PAD) self.hide_sensitivity(2) # Z only self.set_action(action) self.hide_osd() self.hide_macro() if id == "LPAD": self.set_title(_("Left Pad")) else: self.set_title(_("Right Pad")) if mode == Action.AC_OSK: self.hide_osd() self.hide_name() self.hide_macro() self.hide_modeshift() self.hide_rotation() elif mode == Action.AC_MENU: self.hide_modeshift() self.hide_macro()