def on_btSave_clicked(self, *a): tvItems = self.builder.get_object("tvItems") cbProfile = self.builder.get_object("cbProfile") entTitle = self.builder.get_object("entTitle") entClass = self.builder.get_object("entClass") cbMatchTitle = self.builder.get_object("cbMatchTitle") cbMatchClass = self.builder.get_object("cbMatchClass") cbExactTitle = self.builder.get_object("cbExactTitle") cbRegExp = self.builder.get_object("cbRegExp") rbProfile = self.builder.get_object("rbProfile") rbTurnOff = self.builder.get_object("rbTurnOff") rbRestart = self.builder.get_object("rbRestart") ce = self.builder.get_object("ConditionEditor") # Build condition data = {} if cbMatchTitle.get_active() and entTitle.get_text(): if cbExactTitle.get_active(): data['exact_title'] = entTitle.get_text() elif cbRegExp.get_active(): data['regexp'] = entTitle.get_text() else: data['title'] = entTitle.get_text() if cbMatchClass.get_active() and entClass.get_text(): data['wm_class'] = entClass.get_text() condition = Condition(**data) # Grab selected action model, iter = cbProfile.get_model(), cbProfile.get_active_iter() action = NoAction() if rbProfile.get_active(): action = ChangeProfileAction(model.get_value(iter, 0)) elif rbTurnOff.get_active(): action = TurnOffAction() elif rbRestart.get_active(): action = RestartDaemonAction() # Grab & update current row model, iter = tvItems.get_selection().get_selected() o = model.get_value(iter, 0) o.condition = condition o.action = action model.set_value(iter, 1, condition.describe()) model.set_value(iter, 2, action.describe(Action.AC_SWITCHER)) self.hide_dont_destroy(ce) self.save_config()
class AxisActionComponent(AEComponent, TimerManager): GLADE = "ae/axis_action.glade" NAME = "axis_action" CTXS = Action.AC_STICK | Action.AC_PAD PRIORITY = 3 def __init__(self, app, editor): AEComponent.__init__(self, app, editor) TimerManager.__init__(self) self._recursing = False self.relative_area = False self.osd_area_instance = None self.on_wayland = False self.circular_axis = MouseAction(Rels.REL_WHEEL) self.circular_buttons = [None, None] self.button = None self.parser = GuiActionParser() def load(self): if self.loaded: return AEComponent.load(self) cbAreaType = self.builder.get_object("cbAreaType") cbAreaType.set_row_separator_func( lambda model, iter: model.get_value(iter, 0) == "-") self.on_wayland = "WAYLAND_DISPLAY" in os.environ or not isinstance( Gdk.Display.get_default(), GdkX11.X11Display) if self.on_wayland: self.builder.get_object("lblArea").set_text( _("Note: Mouse Region option is not available with Wayland-based display server" )) self.builder.get_object("grArea").set_sensitive(False) # Remove options that are not applicable to currently editted input if self.editor.get_id() in STICKS: # Remove "Mouse Region", "Mouse" and "Mouse (Emulate Stick)" options # when editing stick bindings cb = self.builder.get_object("cbAxisOutput") for row in cb.get_model(): if row[2] in ("wheel_pad", "area", "mouse", "mouse_pad"): cb.get_model().remove(row.iter) else: # Remove "Mouse" option when editing pads # (it's effectivelly same as Trackpad) cb = self.builder.get_object("cbAxisOutput") for row in cb.get_model(): if row[2] in ("wheel_stick", "mouse_stick"): cb.get_model().remove(row.iter) def hidden(self): self.update_osd_area(None) def set_action(self, mode, action): if self.handles(mode, action): cb = self.builder.get_object("cbAxisOutput") if isinstance(action, AreaAction): self.load_area_action(action) self.set_cb(cb, "area", 2) self.update_osd_area(action) return self.update_osd_area(None) if isinstance(action, MouseAction): self.load_mouse_action(action) elif isinstance(action, CircularModifier): self.load_circular_action(action) elif isinstance(action, ButtonAction): self.load_button_action(action) elif isinstance(action, XYAction): if self.editor.friction > 0: self.load_mouse_action(action) else: p = [None, None] for x in (0, 1): if len(action.actions[0].strip().parameters) >= x: if len(action.actions[x].strip().parameters) > 0: p[x] = action.actions[x].strip().parameters[0] if p[0] == Axes.ABS_X and p[1] == Axes.ABS_Y: self.set_cb(cb, "lstick", 2) elif p[0] == Axes.ABS_RX and p[1] == Axes.ABS_RY: if isinstance(action, RelXYAction): self.set_cb(cb, "rstick_rel", 2) else: self.set_cb(cb, "rstick", 2) elif p[0] == Rels.REL_HWHEEL and p[1] == Rels.REL_WHEEL: self.set_cb(cb, "wheel_pad", 2) self.set_cb(cb, "wheel_stick", 2) else: self.set_cb(cb, "none", 2) def update_osd_area(self, action): """ Updates preview area displayed on screen """ if action: if self.osd_area_instance is None: if self.on_wayland: # Cannot display preview with non-X11 backends return self.osd_area_instance = Area() self.osd_area_instance.show() action.update_osd_area(self.osd_area_instance, FakeMapper(self.editor)) self.timer("area", 0.5, self.update_osd_area, action) elif self.osd_area_instance: self.osd_area_instance.quit() self.osd_area_instance = None self.cancel_timer("area") def load_circular_action(self, action): cbAxisOutput = self.builder.get_object("cbAxisOutput") btCircularAxis = self.builder.get_object("btCircularAxis") btCircularButton0 = self.builder.get_object("btCircularButton0") btCircularButton1 = self.builder.get_object("btCircularButton1") # Turn action into list of subactions (even if it's just single action) if isinstance(action.action, MultiAction): actions = action.action.actions else: actions = [action.action] # Parse that list self.circular_axis, self.circular_buttons = NoAction(), [None, None] for action in actions: if isinstance(action, ButtonAction): self.circular_buttons = [action.button, action.button2] else: self.circular_axis = action # Set labels b0, b1 = self.circular_buttons btCircularButton0.set_label(ButtonAction.describe_button(b0)) btCircularButton1.set_label(ButtonAction.describe_button(b1)) btCircularAxis.set_label(self.circular_axis.describe(Action.AC_PAD)) self.set_cb(cbAxisOutput, "circular", 2) def load_button_action(self, action): self.button = action cbAxisOutput = self.builder.get_object("cbAxisOutput") btSingleButton = self.builder.get_object("btSingleButton") btSingleButton.set_label(self.button.describe(Action.AC_PAD)) self.set_cb(cbAxisOutput, "button", 2) def load_mouse_action(self, action): cbMouseOutput = self.builder.get_object("cbMouseOutput") cbAxisOutput = self.builder.get_object("cbAxisOutput") self._recursing = True if isinstance(action, MouseAction): self.set_cb(cbMouseOutput, "mouse", 1) self.set_cb(cbAxisOutput, "mouse", 2) elif isinstance(action, XYAction): if isinstance(action.x, AxisAction): if action.x.parameters[0] == Axes.ABS_X: self.set_cb(cbMouseOutput, "left", 1) else: self.set_cb(cbMouseOutput, "right", 1) self.set_cb(cbAxisOutput, "mouse", 2) elif isinstance(action.x, MouseAction): if self.editor.get_id() in STICKS: self.set_cb(cbAxisOutput, "wheel_stick", 2) else: self.set_cb(cbAxisOutput, "wheel_pad", 2) self._recursing = False def load_area_action(self, action): """ Load AreaAction values into UI. """ cbAreaType = self.builder.get_object("cbAreaType") x1, y1, x2, y2 = action.coords self.relative_area = False if isinstance(action, RelAreaAction): key = "screensize" self.relative_area = True x1, y1, x2, y2 = x1 * 100.0, y1 * 100.0, x2 * 100.0, y2 * 100.0 elif isinstance(action, RelWinAreaAction): key = "windowsize" self.relative_area = True x1, y1, x2, y2 = x1 * 100.0, y1 * 100.0, x2 * 100.0, y2 * 100.0 else: t1 = "1" if x1 < 0 and x2 < 0 else "0" t2 = "1" if y1 < 0 and y2 < 0 else "0" x1, y1, x2, y2 = abs(x1), abs(y1), abs(x2), abs(y2) if x2 < x1: x1, x2 = x2, x1 if y2 < y1: y1, y2 = y2, y1 if isinstance(action, WinAreaAction): key = "window-%s%s" % (t1, t2) else: key = "screen-%s%s" % (t1, t2) self._recursing = True self.builder.get_object("sbAreaX1").set_value(x1) self.builder.get_object("sbAreaY1").set_value(y1) self.builder.get_object("sbAreaX2").set_value(x2) self.builder.get_object("sbAreaY2").set_value(y2) self.builder.get_object("cbAreaOSDEnabled").set_active(self.editor.osd) self.builder.get_object("cbAreaClickEnabled").set_active( self.pressing_pad_clicks()) for row in cbAreaType.get_model(): if key == row[1]: cbAreaType.set_active_iter(row.iter) break self._recursing = False def on_btCircularAxis_clicked(self, *a): def cb(action): self.circular_axis = action btCircularAxis = self.builder.get_object("btCircularAxis") btCircularAxis.set_label(action.describe(Action.AC_PAD)) self.editor.set_action(self.make_circular_action()) b = SimpleChooser(self.app, "axis", cb) b.set_title(_("Select Axis")) b.display_action(Action.AC_STICK, self.circular_axis) b.show(self.editor.window) def on_btCircularButton_clicked(self, button, *a): index = 0 if button == self.builder.get_object( "btCircularButton0") else 1 def cb(action): self.circular_buttons[index] = action.button btCircularButton = self.builder.get_object("btCircularButton%s" % (index, )) btCircularButton.set_label(action.describe(Action.AC_PAD)) self.editor.set_action(self.make_circular_action()) b = SimpleChooser(self.app, "buttons", cb) b.set_title(_("Select Button")) b.display_action(Action.AC_STICK, self.circular_axis) b.show(self.editor.window) def on_btClearCircularAxis_clicked(self, *a): btCircularAxis = self.builder.get_object("btCircularAxis") self.circular_axis = NoAction() btCircularAxis.set_label(self.circular_axis.describe(Action.AC_PAD)) self.editor.set_action(self.make_circular_action()) def on_btClearCircularButtons_clicked(self, *a): btCircularButton0 = self.builder.get_object("btCircularButton0") btCircularButton1 = self.builder.get_object("btCircularButton1") self.circular_buttons = [None, None] btCircularButton0.set_label(NoAction().describe(Action.AC_PAD)) btCircularButton1.set_label(NoAction().describe(Action.AC_PAD)) self.editor.set_action(self.make_circular_action()) def on_btSingleButton_clicked(self, *a): def cb(action): self.button = action btSingleButton = self.builder.get_object("btSingleButton") btSingleButton.set_label(self.button.describe(Action.AC_PAD)) self.editor.set_action(self.button) b = SimpleChooser(self.app, "buttons", cb) b.set_title(_("Select Button")) b.display_action(Action.AC_STICK, self.circular_axis) b.show(self.editor.window) def on_cbAreaOSDEnabled_toggled(self, *a): self.editor.builder.get_object("cbOSD").set_active( self.builder.get_object("cbAreaOSDEnabled").get_active()) def pressing_pad_clicks(self): """ Returns True if currently edited pad is set to press left mouse button when pressed. (yes, this is used somewhere) """ side = getattr(SCButtons, self.editor.get_id()) c_action = self.app.current.buttons[side] if isinstance(c_action, ButtonAction): return c_action.button == Keys.BTN_LEFT return False def on_ok(self, action): if isinstance(action.strip(), AreaAction): # Kinda hacky way to set action on LPAD press or RPAD press # when user selects Mouse Area as ouput and checks # 'Pressing the Pad Clicks' checkbox side = getattr(SCButtons, self.editor.get_id()) clicks = self.pressing_pad_clicks() if self.builder.get_object("cbAreaClickEnabled").get_active(): if not clicks: # Turn pad press into mouse clicks self.app.set_action(self.app.current, side, ButtonAction(Keys.BTN_LEFT)) else: if clicks: # Clear action created above if checkbox is uncheck self.app.set_action(self.app.current, side, NoAction()) def on_mouse_options_changed(self, *a): if self._recursing: return action = self.make_mouse_action() self.editor.set_action(action) def make_mouse_action(self): """ Loads values from UI into trackball-related action """ cbMouseOutput = self.builder.get_object("cbMouseOutput") a_str = cbMouseOutput.get_model().get_value( cbMouseOutput.get_active_iter(), 2) return self.parser.restart(a_str).parse() def make_circular_action(self): """ Constructs Circular Modifier """ if self.circular_axis and any(self.circular_buttons): return CircularModifier( MultiAction(self.circular_axis, ButtonAction(*self.circular_buttons))) elif any(self.circular_buttons): return CircularModifier(ButtonAction(*self.circular_buttons)) else: return CircularModifier(self.circular_axis) def make_area_action(self): """ Loads values from UI into new AreaAction or subclass. """ # Prepare cbAreaType = self.builder.get_object("cbAreaType") # Read numbers x1 = self.builder.get_object("sbAreaX1").get_value() y1 = self.builder.get_object("sbAreaY1").get_value() x2 = self.builder.get_object("sbAreaX2").get_value() y2 = self.builder.get_object("sbAreaY2").get_value() # Determine exact action type by looking into Area Type checkbox # (this part may seem little crazy) # ... numbers key = cbAreaType.get_model().get_value(cbAreaType.get_active_iter(), 1) if "-" in key: if key[-2] == "1": # Before-last character ius "1", that means that X coords are # counted from other side and has to be negated x1, x2 = -x1, -x2 if key[-1] == "1": # Key ends with "1". Same thing as above but for Y coordinate y1, y2 = -y1, -y2 if "size" in key: x1, y1, x2, y2 = x1 / 100.0, y1 / 100.0, x2 / 100.0, y2 / 100.0 # ... class if "window-" in key: cls = WinAreaAction self.relative_area = False elif "screensize" == key: cls = RelAreaAction self.relative_area = True elif "windowsize" == key: cls = RelWinAreaAction self.relative_area = True else: # "screen" in key cls = AreaAction self.relative_area = False if not self.relative_area: x1, y1, x2, y2 = int(x1), int(y1), int(x2), int(y2) return cls(x1, y1, x2, y2) def get_button_title(self): return _("Joystick / Mouse") def handles(self, mode, action): if isinstance(action, (NoAction, MouseAction, CircularModifier, InvalidAction, AreaAction, ButtonAction)): return True if isinstance(action, BallModifier): if isinstance(action.action, XYAction): return (isinstance(action.action.x, (AxisAction, MouseAction)) and isinstance(action.action.x, (AxisAction, MouseAction))) return isinstance(action.action, MouseAction) if isinstance(action, XYAction): p = [None, None] for x in (0, 1): if len(action.actions[0].strip().parameters) >= x: if len(action.actions[x].strip().parameters) > 0: p[x] = action.actions[x].strip().parameters[0] if p[0] == Axes.ABS_X and p[1] == Axes.ABS_Y: return True elif p[0] == Axes.ABS_RX and p[1] == Axes.ABS_RY: return True elif p[0] == Axes.ABS_HAT0X and p[1] == Axes.ABS_HAT0Y: return True elif p[0] == Rels.REL_HWHEEL and p[1] == Rels.REL_WHEEL: return True return False def on_area_options_changed(self, *a): if self._recursing: return action = self.make_area_action() self.editor.set_action(action) self.update_osd_area(action) for x in ('sbAreaX1', 'sbAreaX2', 'sbAreaY1', 'sbAreaY2'): spin = self.builder.get_object(x) if self.relative_area: spin.get_adjustment().set_upper(100) else: spin.get_adjustment().set_upper(1000) self.on_sbArea_output(spin) def on_sbArea_output(self, button, *a): if self.relative_area: button.set_text("%s %%" % (button.get_value())) else: button.set_text("%s px" % (int(button.get_value()))) def on_sbArea_focus_out_event(self, button, *a): GLib.idle_add(self.on_sbArea_output, button) def on_sbArea_changed(self, button, *a): self.on_sbArea_output(button) self.on_area_options_changed(button) def on_lblSetupTrackball_activate_link(self, trash, link): self.editor.on_link(link) def on_cbAxisOutput_changed(self, *a): cbAxisOutput = self.builder.get_object("cbAxisOutput") stActionData = self.builder.get_object("stActionData") key = cbAxisOutput.get_model().get_value( cbAxisOutput.get_active_iter(), 2) if key == 'area': stActionData.set_visible_child(self.builder.get_object("grArea")) action = self.make_area_action() self.update_osd_area(action) elif key == "button": stActionData.set_visible_child(self.builder.get_object("vbButton")) self.button = self.button or ButtonAction(Keys.BTN_GAMEPAD) action = self.button elif key == "circular": stActionData.set_visible_child( self.builder.get_object("grCircular")) action = self.make_circular_action() elif key == 'mouse': stActionData.set_visible_child(self.builder.get_object("vbMose")) if not self._recursing and self.editor.friction == 0: # When switching to mouse, enable trackball by default self.editor.friction = 10 action = self.make_mouse_action() else: stActionData.set_visible_child(self.builder.get_object("nothing")) action = cbAxisOutput.get_model().get_value( cbAxisOutput.get_active_iter(), 0) action = self.parser.restart(action).parse() self.update_osd_area(None) self.editor.set_action(action)
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.setup_widgets() self.actions = [] self.default = NoAction() def setup_widgets(self): self.builder = Gtk.Builder() self.builder.add_from_file(os.path.join(self.app.gladepath, self.GLADE)) self.window = self.builder.get_object("Dialog") self.builder.connect_signals(self) cbButtonChooser = self.builder.get_object("cbButtonChooser") cbButtonChooser.set_row_separator_func( lambda model, iter : model.get_value(iter, 0) is None ) model = cbButtonChooser.get_model() for button, text in self.BUTTONS: model.append(( None if button is None else button.name, text )) cbButtonChooser.set_active(0) headerbar(self.builder.get_object("header")) def _add_action(self, button, action): grActions = self.builder.get_object("grActions") 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) + 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, 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, button) grActions.attach(l, 0, i, 1, 1) grActions.attach(b, 1, i, 1, 1) grActions.attach(clearb, 2, i, 1, 1) self.actions.append([ button, action, l, b, clearb ]) grActions.show_all() def on_clearb_clicked(self, trash, button): grActions = self.builder.get_object("grActions") cbButtonChooser = self.builder.get_object("cbButtonChooser") model = cbButtonChooser.get_model() # Remove requested action from the list for i in xrange(0, len(self.actions)): if self.actions[i][0] == button: button, action, l, b, clearb = self.actions[i] for w in (l, b, clearb): grActions.remove(w) del self.actions[i] break # Move everything after that action one position up # - remove it for j in xrange(i, len(self.actions)): button, action, l, b, clearb = self.actions[j] for w in (l, b, clearb): grActions.remove(w) # - add it again for j in xrange(i, len(self.actions)): button, action, l, b, clearb = self.actions[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 _setup_editor(self, ae, action): if self.mode == Action.AC_BUTTON: ae.set_button(self.id, action) elif self.mode == Action.AC_TRIGGER: ae.set_trigger(self.id, action) elif self.mode == Action.AC_STICK: ae.set_stick(action) elif self.mode == Action.AC_GYRO: ae.set_gyro(action) elif self.mode == Action.AC_PAD: ae.set_pad(self.id, action) 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, clicked_button): for i in self.actions: button, action, l, b, clearb = i if button == clicked_button: def on_chosen(id, action, reopen=False): b.set_label(action.describe(self.mode)) i[1] = action if reopen: self.on_actionb_clicked(trash, clicked_button) ae = self._choose_editor(action, on_chosen) self._setup_editor(ae, action) ae.show(self.window) return def on_btDefault_clicked(self, *a): btDefault = self.builder.get_object("btDefault") def on_chosen(id, action, reopen=False): btDefault.set_label(action.describe(self.mode)) self.default = action if reopen: self.on_btDefault_clicked() ae = self._choose_editor(self.default, on_chosen) self._setup_editor(ae, self.default) ae.show(self.window) def on_btClearDefault_clicked(self, *a): self.default = NoAction() btDefault = self.builder.get_object("btDefault") btDefault.set_label(self.default.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(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_btOK_clicked(self, *a): """ Handler for OK button """ pars = [] for button, action, l, b, clearb in self.actions: pars += [ button, action ] if self.default: pars += [ self.default ] action = ModeModifier(*pars) if len(pars) == 0: # No action is actually set action = NoAction() elif len(pars) == 1: # Only default action left action = self.default if self.ac_callback is not None: self.ac_callback(self.id, action) self.close() def _set_mode(self, mode, id, action): btDefault = self.builder.get_object("btDefault") self.id = id self.mode = mode for key in action.mods: self._add_action(key, action.mods[key]) self.default = action.default btDefault.set_label(self.default.describe(self.mode)) def set_button(self, id, action): """ Setups editor as editor for button action """ self._set_mode(Action.AC_BUTTON, id, action) def set_trigger(self, id, action): """ Setups editor as editor for trigger action """ self._set_mode(Action.AC_TRIGGER, id, action) def set_stick(self, action): """ Setups action editor as editor for stick action """ self._set_mode(Action.AC_STICK, Profile.STICK, action) def set_pad(self, id, action): """ Setups action editor as editor for pad action """ self._set_mode(Action.AC_PAD, id, action) def set_gyro(self, action): """ Setups editor as editor for button action """ self._set_mode(Action.AC_GYRO, Profile.GYRO, action)
class AxisActionComponent(AEComponent, TimerManager): GLADE = "ae/axis_action.glade" NAME = "axis_action" CTXS = Action.AC_STICK | Action.AC_PAD PRIORITY = 3 def __init__(self, app, editor): AEComponent.__init__(self, app, editor) TimerManager.__init__(self) self._recursing = False self.relative_area = False self.osd_area_instance = None self.on_wayland = False self.circular_axis = MouseAction(Rels.REL_WHEEL) self.circular_buttons = [ None, None ] self.button = None self.parser = GuiActionParser() def load(self): if self.loaded : return AEComponent.load(self) cbAreaType = self.builder.get_object("cbAreaType") cbAreaType.set_row_separator_func( lambda model, iter : model.get_value(iter, 0) == "-" ) self.on_wayland = "WAYLAND_DISPLAY" in os.environ or not isinstance(Gdk.Display.get_default(), GdkX11.X11Display) if self.on_wayland: self.builder.get_object("lblArea").set_text(_("Note: Mouse Region option is not available with Wayland-based display server")) self.builder.get_object("grArea").set_sensitive(False) # Remove options that are not applicable to currently editted input if self.editor.get_id() in STICKS: # Remove "Mouse Region", "Mouse" and "Mouse (Emulate Stick)" options # when editing stick bindings cb = self.builder.get_object("cbAxisOutput") for row in cb.get_model(): if row[2] in ("wheel_pad", "area", "mouse", "mouse_pad"): cb.get_model().remove(row.iter) else: # Remove "Mouse" option when editing pads # (it's effectivelly same as Trackpad) cb = self.builder.get_object("cbAxisOutput") for row in cb.get_model(): if row[2] in ("wheel_stick", "mouse_stick"): cb.get_model().remove(row.iter) def hidden(self): self.update_osd_area(None) def set_action(self, mode, action): if self.handles(mode, action): cb = self.builder.get_object("cbAxisOutput") if isinstance(action, AreaAction): self.load_area_action(action) self.set_cb(cb, "area", 2) self.update_osd_area(action) return self.update_osd_area(None) if isinstance(action, MouseAction): self.load_mouse_action(action) elif isinstance(action, CircularModifier): self.load_circular_action(action) elif isinstance(action, ButtonAction): self.load_button_action(action) elif isinstance(action, XYAction): if self.editor.friction > 0: self.load_mouse_action(action) else: p = [ None, None ] for x in (0, 1): if len(action.actions[0].strip().parameters) >= x: if len(action.actions[x].strip().parameters) > 0: p[x] = action.actions[x].strip().parameters[0] if p[0] == Axes.ABS_X and p[1] == Axes.ABS_Y: self.set_cb(cb, "lstick", 2) elif p[0] == Axes.ABS_RX and p[1] == Axes.ABS_RY: if isinstance(action, RelXYAction): self.set_cb(cb, "rstick_rel", 2) else: self.set_cb(cb, "rstick", 2) elif p[0] == Rels.REL_HWHEEL and p[1] == Rels.REL_WHEEL: self.set_cb(cb, "wheel_pad", 2) self.set_cb(cb, "wheel_stick", 2) else: self.set_cb(cb, "none", 2) def update_osd_area(self, action): """ Updates preview area displayed on screen """ if action: if self.osd_area_instance is None: if self.on_wayland: # Cannot display preview with non-X11 backends return self.osd_area_instance = Area() self.osd_area_instance.show() action.update_osd_area(self.osd_area_instance, FakeMapper(self.editor)) self.timer("area", 0.5, self.update_osd_area, action) elif self.osd_area_instance: self.osd_area_instance.quit() self.osd_area_instance = None self.cancel_timer("area") def load_circular_action(self, action): cbAxisOutput = self.builder.get_object("cbAxisOutput") btCircularAxis = self.builder.get_object("btCircularAxis") btCircularButton0 = self.builder.get_object("btCircularButton0") btCircularButton1 = self.builder.get_object("btCircularButton1") # Turn action into list of subactions (even if it's just single action) if isinstance(action.action, MultiAction): actions = action.action.actions else: actions = [ action.action ] # Parse that list self.circular_axis, self.circular_buttons = NoAction(), [ None, None ] for action in actions: if isinstance(action, ButtonAction): self.circular_buttons = [ action.button, action.button2 ] else: self.circular_axis = action # Set labels b0, b1 = self.circular_buttons btCircularButton0.set_label(ButtonAction.describe_button(b0)) btCircularButton1.set_label(ButtonAction.describe_button(b1)) btCircularAxis.set_label(self.circular_axis.describe(Action.AC_PAD)) self.set_cb(cbAxisOutput, "circular", 2) def load_button_action(self, action): self.button = action cbAxisOutput = self.builder.get_object("cbAxisOutput") btSingleButton = self.builder.get_object("btSingleButton") btSingleButton.set_label(self.button.describe(Action.AC_PAD)) self.set_cb(cbAxisOutput, "button", 2) def load_mouse_action(self, action): cbMouseOutput = self.builder.get_object("cbMouseOutput") cbAxisOutput = self.builder.get_object("cbAxisOutput") self._recursing = True if isinstance(action, MouseAction): self.set_cb(cbMouseOutput, "mouse", 1) self.set_cb(cbAxisOutput, "mouse", 2) elif isinstance(action, XYAction): if isinstance(action.x, AxisAction): if action.x.parameters[0] == Axes.ABS_X: self.set_cb(cbMouseOutput, "left", 1) else: self.set_cb(cbMouseOutput, "right", 1) self.set_cb(cbAxisOutput, "mouse", 2) elif isinstance(action.x, MouseAction): if self.editor.get_id() in STICKS: self.set_cb(cbAxisOutput, "wheel_stick", 2) else: self.set_cb(cbAxisOutput, "wheel_pad", 2) self._recursing = False def load_area_action(self, action): """ Load AreaAction values into UI. """ cbAreaType = self.builder.get_object("cbAreaType") x1, y1, x2, y2 = action.coords self.relative_area = False if isinstance(action, RelAreaAction): key = "screensize" self.relative_area = True x1, y1, x2, y2 = x1 * 100.0, y1 * 100.0, x2 * 100.0, y2 * 100.0 elif isinstance(action, RelWinAreaAction): key = "windowsize" self.relative_area = True x1, y1, x2, y2 = x1 * 100.0, y1 * 100.0, x2 * 100.0, y2 * 100.0 else: t1 = "1" if x1 < 0 and x2 < 0 else "0" t2 = "1" if y1 < 0 and y2 < 0 else "0" x1, y1, x2, y2 = abs(x1), abs(y1), abs(x2), abs(y2) if x2 < x1 : x1, x2 = x2, x1 if y2 < y1 : y1, y2 = y2, y1 if isinstance(action, WinAreaAction): key = "window-%s%s" % (t1, t2) else: key = "screen-%s%s" % (t1, t2) self._recursing = True self.builder.get_object("sbAreaX1").set_value(x1) self.builder.get_object("sbAreaY1").set_value(y1) self.builder.get_object("sbAreaX2").set_value(x2) self.builder.get_object("sbAreaY2").set_value(y2) self.builder.get_object("cbAreaOSDEnabled").set_active(self.editor.osd) self.builder.get_object("cbAreaClickEnabled").set_active(self.pressing_pad_clicks()) for row in cbAreaType.get_model(): if key == row[1]: cbAreaType.set_active_iter(row.iter) break self._recursing = False def on_btCircularAxis_clicked(self, *a): def cb(action): self.circular_axis = action btCircularAxis = self.builder.get_object("btCircularAxis") btCircularAxis.set_label(action.describe(Action.AC_PAD)) self.editor.set_action(self.make_circular_action()) b = SimpleChooser(self.app, "axis", cb) b.set_title(_("Select Axis")) b.display_action(Action.AC_STICK, self.circular_axis) b.show(self.editor.window) def on_btCircularButton_clicked(self, button, *a): index = 0 if button == self.builder.get_object("btCircularButton0") else 1 def cb(action): self.circular_buttons[index] = action.button btCircularButton = self.builder.get_object("btCircularButton%s" % (index, )) btCircularButton.set_label(action.describe(Action.AC_PAD)) self.editor.set_action(self.make_circular_action()) b = SimpleChooser(self.app, "buttons", cb) b.set_title(_("Select Button")) b.display_action(Action.AC_STICK, self.circular_axis) b.show(self.editor.window) def on_btClearCircularAxis_clicked(self, *a): btCircularAxis = self.builder.get_object("btCircularAxis") self.circular_axis = NoAction() btCircularAxis.set_label(self.circular_axis.describe(Action.AC_PAD)) self.editor.set_action(self.make_circular_action()) def on_btClearCircularButtons_clicked(self, *a): btCircularButton0 = self.builder.get_object("btCircularButton0") btCircularButton1 = self.builder.get_object("btCircularButton1") self.circular_buttons = [ None, None ] btCircularButton0.set_label(NoAction().describe(Action.AC_PAD)) btCircularButton1.set_label(NoAction().describe(Action.AC_PAD)) self.editor.set_action(self.make_circular_action()) def on_btSingleButton_clicked(self, *a): def cb(action): self.button = action btSingleButton = self.builder.get_object("btSingleButton") btSingleButton.set_label(self.button.describe(Action.AC_PAD)) self.editor.set_action(self.button) b = SimpleChooser(self.app, "buttons", cb) b.set_title(_("Select Button")) b.display_action(Action.AC_STICK, self.circular_axis) b.show(self.editor.window) def on_cbAreaOSDEnabled_toggled(self, *a): self.editor.builder.get_object("cbOSD").set_active( self.builder.get_object("cbAreaOSDEnabled").get_active()) def pressing_pad_clicks(self): """ Returns True if currently edited pad is set to press left mouse button when pressed. (yes, this is used somewhere) """ side = getattr(SCButtons, self.editor.get_id()) c_action = self.app.current.buttons[side] if isinstance(c_action, ButtonAction): return c_action.button == Keys.BTN_LEFT return False def on_ok(self, action): if isinstance(action.strip(), AreaAction): # Kinda hacky way to set action on LPAD press or RPAD press # when user selects Mouse Area as ouput and checks # 'Pressing the Pad Clicks' checkbox side = getattr(SCButtons, self.editor.get_id()) clicks = self.pressing_pad_clicks() if self.builder.get_object("cbAreaClickEnabled").get_active(): if not clicks: # Turn pad press into mouse clicks self.app.set_action(self.app.current, side, ButtonAction(Keys.BTN_LEFT)) else: if clicks: # Clear action created above if checkbox is uncheck self.app.set_action(self.app.current, side, NoAction()) def on_mouse_options_changed(self, *a): if self._recursing : return action = self.make_mouse_action() self.editor.set_action(action) def make_mouse_action(self): """ Loads values from UI into trackball-related action """ cbMouseOutput = self.builder.get_object("cbMouseOutput") a_str = cbMouseOutput.get_model().get_value(cbMouseOutput.get_active_iter(), 2) return self.parser.restart(a_str).parse() def make_circular_action(self): """ Constructs Circular Modifier """ if self.circular_axis and any(self.circular_buttons): return CircularModifier(MultiAction( self.circular_axis, ButtonAction(*self.circular_buttons))) elif any(self.circular_buttons): return CircularModifier(ButtonAction(*self.circular_buttons)) else: return CircularModifier(self.circular_axis) def make_area_action(self): """ Loads values from UI into new AreaAction or subclass. """ # Prepare cbAreaType = self.builder.get_object("cbAreaType") # Read numbers x1 = self.builder.get_object("sbAreaX1").get_value() y1 = self.builder.get_object("sbAreaY1").get_value() x2 = self.builder.get_object("sbAreaX2").get_value() y2 = self.builder.get_object("sbAreaY2").get_value() # Determine exact action type by looking into Area Type checkbox # (this part may seem little crazy) # ... numbers key = cbAreaType.get_model().get_value(cbAreaType.get_active_iter(), 1) if "-" in key: if key[-2] == "1": # Before-last character ius "1", that means that X coords are # counted from other side and has to be negated x1, x2 = -x1, -x2 if key[-1] == "1": # Key ends with "1". Same thing as above but for Y coordinate y1, y2 = -y1, -y2 if "size" in key: x1, y1, x2, y2 = x1 / 100.0, y1 / 100.0, x2 / 100.0, y2 / 100.0 # ... class if "window-" in key: cls = WinAreaAction self.relative_area = False elif "screensize" == key: cls = RelAreaAction self.relative_area = True elif "windowsize" == key: cls = RelWinAreaAction self.relative_area = True else: # "screen" in key cls = AreaAction self.relative_area = False if not self.relative_area: x1, y1, x2, y2 = int(x1), int(y1), int(x2), int(y2) return cls(x1, y1, x2, y2) def get_button_title(self): return _("Joystick / Mouse") def handles(self, mode, action): if isinstance(action, (NoAction, MouseAction, CircularModifier, InvalidAction, AreaAction, ButtonAction)): return True if isinstance(action, BallModifier): if isinstance(action.action, XYAction): return ( isinstance(action.action.x, (AxisAction, MouseAction)) and isinstance(action.action.x, (AxisAction, MouseAction)) ) return isinstance(action.action, MouseAction) if isinstance(action, XYAction): p = [ None, None ] for x in (0, 1): if len(action.actions[0].strip().parameters) >= x: if len(action.actions[x].strip().parameters) > 0: p[x] = action.actions[x].strip().parameters[0] if p[0] == Axes.ABS_X and p[1] == Axes.ABS_Y: return True elif p[0] == Axes.ABS_RX and p[1] == Axes.ABS_RY: return True elif p[0] == Axes.ABS_HAT0X and p[1] == Axes.ABS_HAT0Y: return True elif p[0] == Rels.REL_HWHEEL and p[1] == Rels.REL_WHEEL: return True return False def on_area_options_changed(self, *a): if self._recursing : return action = self.make_area_action() self.editor.set_action(action) self.update_osd_area(action) for x in ('sbAreaX1', 'sbAreaX2', 'sbAreaY1', 'sbAreaY2'): spin = self.builder.get_object(x) if self.relative_area: spin.get_adjustment().set_upper(100) else: spin.get_adjustment().set_upper(1000) self.on_sbArea_output(spin) def on_sbArea_output(self, button, *a): if self.relative_area: button.set_text("%s %%" % (button.get_value())) else: button.set_text("%s px" % (int(button.get_value()))) def on_sbArea_focus_out_event(self, button, *a): GLib.idle_add(self.on_sbArea_output, button) def on_sbArea_changed(self, button, *a): self.on_sbArea_output(button) self.on_area_options_changed(button) def on_lblSetupTrackball_activate_link(self, trash, link): self.editor.on_link(link) def on_cbAxisOutput_changed(self, *a): cbAxisOutput = self.builder.get_object("cbAxisOutput") stActionData = self.builder.get_object("stActionData") key = cbAxisOutput.get_model().get_value(cbAxisOutput.get_active_iter(), 2) if key == 'area': stActionData.set_visible_child(self.builder.get_object("grArea")) action = self.make_area_action() self.update_osd_area(action) elif key == "button": stActionData.set_visible_child(self.builder.get_object("vbButton")) self.button = self.button or ButtonAction(Keys.BTN_GAMEPAD) action = self.button elif key == "circular": stActionData.set_visible_child(self.builder.get_object("grCircular")) action = self.make_circular_action() elif key == 'mouse': stActionData.set_visible_child(self.builder.get_object("vbMose")) if self.editor.friction == 0: # When switching to mouse, enable trackball by default self.editor.friction = 10 action = self.make_mouse_action() else: stActionData.set_visible_child(self.builder.get_object("nothing")) action = cbAxisOutput.get_model().get_value(cbAxisOutput.get_active_iter(), 0) action = self.parser.restart(action).parse() self.update_osd_area(None) self.editor.set_action(action)