class ModeModifier(Modifier): COMMAND = "mode" MIN_TRIGGER = 2 # When trigger is bellow this position, list of held_triggers is cleared MIN_STICK = 2 # When abs(stick) < MIN_STICK, stick is considered released and held_sticks is cleared def __init__(self, *stuff): Modifier.__init__(self) self.default = None self.mods = {} self.held_buttons = set() self.held_sticks = set() self.held_triggers = {} self.order = [] self.old_gyro = None button = None for i in stuff: if self.default is not None: # Default has to be last parameter raise ValueError("Invalid parameters for 'mode'") if isinstance(i, Action): if button is None: self.default = i continue self.mods[button] = i self.order.append(button) button = None elif i in SCButtons: button = i else: raise ValueError("Invalid parameter for 'mode': %s" % (i,)) if self.default is None: self.default = NoAction() def set_haptic(self, hapticdata): supports = False if self.default: supports = self.default.set_haptic(hapticdata) or supports for a in self.mods.values(): supports = a.set_haptic(hapticdata) or supports return supports def set_speed(self, x, y, z): supports = False if self.default: supports = self.default.set_speed(x, y, z) or supports for a in self.mods.values(): supports = a.set_speed(x, y, z) or supports return supports def strip(self): # Returns default action or action assigned to first modifier if self.default: return self.default.strip() if len(self.order) > 0: return self.mods[self.order[0]].strip() # Empty ModeModifier return NoAction() def compress(self): if self.default: self.default = self.default.compress() for button in self.mods: self.mods[button] = self.mods[button].compress() return self def __str__(self): rv = [ ] for key in self.mods: rv += [ key.name, self.mods[key] ] if self.default is not None: rv += [ self.default ] return "<Modifier '%s', %s>" % (self.COMMAND, rv) __repr__ = __str__ def describe(self, context): l = [] if self.default : l.append(self.default) for x in self.order: l.append(self.mods[x]) return "\n".join([ x.describe(context) for x in l ]) def to_string(self, multiline=False, pad=0): if multiline: rv = [ (" " * pad) + "mode(" ] for key in self.mods: a_str = self.mods[key].to_string(True).split("\n") a_str[0] = (" " * pad) + " " + (key.name + ",").ljust(11) + a_str[0] # Key has to be one of SCButtons for i in xrange(1, len(a_str)): a_str[i] = (" " * pad) + " " + a_str[i] a_str[-1] = a_str[-1] + "," rv += a_str if self.default is not None: a_str = [ (" " * pad) + " " + x for x in self.default.to_string(True).split("\n") ] rv += a_str if rv[-1][-1] == ",": rv[-1] = rv[-1][0:-1] rv += [ (" " * pad) + ")" ] return "\n".join(rv) else: rv = [ ] for key in self.mods: rv += [ key.name, self.mods[key].to_string(False) ] if self.default is not None: rv += [ self.default.to_string(False) ] return "mode(" + ", ".join(rv) + ")" def encode(self): rv = self.default.encode() rv['modes'] = {} for key in self.mods: rv['modes'][key.name] = self.mods[key].encode() if self.name: rv['name'] = self.name return rv def select(self, mapper): """ Selects action by pressed button. """ for b in self.order: if mapper.is_pressed(b): return self.mods[b] return self.default def select_b(self, mapper): """ Same as select but returns button as well. """ for b in self.order: if mapper.is_pressed(b): return b, self.mods[b] return None, self.default def button_press(self, mapper): sel = self.select(mapper) self.held_buttons.add(sel) return sel.button_press(mapper) def button_release(self, mapper): # Releases all held buttons, not just button that matches # currently pressed modifier for b in self.held_buttons: b.button_release(mapper) def trigger(self, mapper, position, old_position): if position < ModeModifier.MIN_TRIGGER: for b in self.held_triggers: b.trigger(mapper, 0, self.held_triggers[b]) self.held_triggers = {} return False else: sel = self.select(mapper) self.held_triggers[sel] = position return sel.trigger(mapper, position, old_position) def axis(self, mapper, position, what): return self.select(mapper).axis(mapper, position, what) def gyro(self, mapper, pitch, yaw, roll, *q): sel = self.select(mapper) if sel is not self.old_gyro: if self.old_gyro: self.old_gyro.gyro(mapper, 0, 0, 0, *q) self.old_gyro = sel return sel.gyro(mapper, pitch, yaw, roll, *q) def pad(self, mapper, position, what): return self.select(mapper).pad(mapper, position, what) def whole(self, mapper, x, y, what): if what == STICK: if abs(x) < ModeModifier.MIN_STICK and abs(y) < ModeModifier.MIN_STICK: for b in self.held_sticks: b.whole(mapper, 0, 0, what) self.held_sticks.clear() else: self.held_sticks.add(self.select(mapper)) for b in self.held_sticks: b.whole(mapper, x, y, what) else: return self.select(mapper).whole(mapper, x, y, what)
class DoubleclickModifier(Modifier): COMMAND = "doubleclick" DEAFAULT_TIMEOUT = 0.2 def __init__(self, doubleclickaction, normalaction=None): Modifier.__init__(self) self.action = doubleclickaction self.normalaction = normalaction or NoAction() self.holdaction = NoAction() self.timeout = self.DEAFAULT_TIMEOUT self.waiting = False self.pressed = False self.active = None def set_haptic(self, hapticdata): supports = self.action.set_haptic(hapticdata) if self.normalaction: supports = self.normalaction.set_haptic(hapticdata) or supports if self.holdaction: supports = self.holdaction.set_haptic(hapticdata) or supports return supports def set_speed(self, x, y, z): supports = self.action.set_speed(x, y, z) if self.normalaction: supports = self.normalaction.set_speed(x, y, z) or supports if self.holdaction: supports = self.holdaction.set_speed(x, y, z) or supports return supports def strip(self): if self.holdaction: return self.holdaction.strip() return self.action.strip() def compress(self): self.action = self.action.compress() self.holdaction = self.holdaction.compress() self.normalaction = self.normalaction.compress() if isinstance(self.normalaction, DoubleclickModifier): self.action = self.action.compress( ) or self.normalaction.action.compress() self.holdaction = self.holdaction.compress( ) or self.normalaction.holdaction.compress() self.normalaction = self.normalaction.normalaction.compress() elif isinstance(self.action, HoldModifier): self.holdaction = self.action.holdaction.compress() self.action = self.action.normalaction.compress() elif isinstance(self.holdaction, DoubleclickModifier): self.action = self.holdaction.action.compress() self.holdaction = self.holdaction.normalaction.compress() elif isinstance(self.holdaction, DoubleclickModifier): self.action = self.action.compress( ) or self.holdaction.action.compress() self.normalaction = self.normalaction.compress( ) or self.holdaction.normalaction.compress() self.holdaction = self.holdaction.holdaction.compress() return self def __str__(self): l = [self.action] if self.normalaction: l += [self.normalaction] return "<Modifier %s dbl='%s' hold='%s' normal='%s'>" % ( self.COMMAND, self.action, self.holdaction, self.normalaction) __repr__ = __str__ def describe(self, context): l = [] if self.action: l += [self.action] if self.holdaction: l += [self.holdaction] if self.normalaction: l += [self.normalaction] return "\n".join([x.describe(context) for x in l]) def to_string(self, multiline=False, pad=0): firstline, lastline = "", "" if self.action: firstline += DoubleclickModifier.COMMAND + "(" + self.action.to_string( ) + "," lastline += ")" if self.holdaction: firstline += HoldModifier.COMMAND + "(" + self.holdaction.to_string( ) + "," lastline += ")" if multiline: if self.normalaction: rv = [(" " * pad) + firstline] rv += self.normalaction.to_string(True, pad + 2).split("\n") rv += [(" " * pad) + lastline] else: rv = [firstline.strip(",") + lastline] return "\n".join(rv) elif self.normalaction: return firstline + self.normalaction.to_string() + lastline else: return firstline.strip(",") + lastline def encode(self): if self.normalaction: rv = self.normalaction.encode() else: rv = {} rv['doubleclick'] = self.action.encode() if self.holdaction: rv['hold'] = self.holdaction.encode() if self.name: rv['name'] = self.name return rv def button_press(self, mapper): self.pressed = True if self.waiting: # Double-click happened mapper.remove_scheduled(self.on_timeout) self.waiting = False self.active = self.action self.active.button_press(mapper) else: # First click, start the timer self.waiting = True mapper.schedule(self.timeout, self.on_timeout) def button_release(self, mapper): self.pressed = False if self.waiting and self.active is None and not self.action: # In HoldModifier, button released before timeout mapper.remove_scheduled(self.on_timeout) self.waiting = False if self.normalaction: self.normalaction.button_press(mapper) self.normalaction.button_release(mapper) elif self.active: # Released held button self.active.button_release(mapper) self.active = None def on_timeout(self, mapper, *a): if self.waiting: self.waiting = False if self.pressed: # Timeouted while button is still pressed self.active = self.holdaction if self.holdaction else self.normalaction self.active.button_press(mapper) elif self.normalaction: # User did short click and nothing else self.normalaction.button_press(mapper) self.normalaction.button_release(mapper)
class DoubleclickModifier(Modifier): COMMAND = "doubleclick" DEAFAULT_TIMEOUT = 0.2 def __init__(self, doubleclickaction, normalaction=None): Modifier.__init__(self) self.action = doubleclickaction self.normalaction = normalaction or NoAction() self.holdaction = NoAction() self.timeout = self.DEAFAULT_TIMEOUT self.waiting = False self.pressed = False self.active = None def set_haptic(self, hapticdata): supports = self.action.set_haptic(hapticdata) if self.normalaction: supports = self.normalaction.set_haptic(hapticdata) or supports if self.holdaction: supports = self.holdaction.set_haptic(hapticdata) or supports return supports def set_speed(self, x, y, z): supports = self.action.set_speed(x, y, z) if self.normalaction: supports = self.normalaction.set_speed(x, y, z) or supports if self.holdaction: supports = self.holdaction.set_speed(x, y, z) or supports return supports def strip(self): if self.holdaction: return self.holdaction.strip() return self.action.strip() def compress(self): self.action = self.action.compress() self.holdaction = self.holdaction.compress() self.normalaction = self.normalaction.compress() if isinstance(self.normalaction, DoubleclickModifier): self.action = self.action.compress() or self.normalaction.action.compress() self.holdaction = self.holdaction.compress() or self.normalaction.holdaction.compress() self.normalaction = self.normalaction.normalaction.compress() elif isinstance(self.action, HoldModifier): self.holdaction = self.action.holdaction.compress() self.action = self.action.normalaction.compress() elif isinstance(self.holdaction, DoubleclickModifier): self.action = self.holdaction.action.compress() self.holdaction = self.holdaction.normalaction.compress() elif isinstance(self.holdaction, DoubleclickModifier): self.action = self.action.compress() or self.holdaction.action.compress() self.normalaction = self.normalaction.compress() or self.holdaction.normalaction.compress() self.holdaction = self.holdaction.holdaction.compress() return self def __str__(self): l = [ self.action ] if self.normalaction: l += [ self.normalaction ] return "<Modifier %s dbl='%s' hold='%s' normal='%s'>" % ( self.COMMAND, self.action, self.holdaction, self.normalaction ) __repr__ = __str__ def describe(self, context): l = [ ] if self.action: l += [ self.action ] if self.holdaction: l += [ self.holdaction ] if self.normalaction: l += [ self.normalaction ] return "\n".join([ x.describe(context) for x in l ]) def to_string(self, multiline=False, pad=0): firstline, lastline = "", "" if self.action: firstline += DoubleclickModifier.COMMAND + "(" + self.action.to_string() + "," lastline += ")" if self.holdaction: firstline += HoldModifier.COMMAND + "(" + self.holdaction.to_string() + "," lastline += ")" if multiline: if self.normalaction: rv = [ (" " * pad) + firstline ] rv += self.normalaction.to_string(True, pad+2).split("\n") rv += [ (" " * pad) + lastline ] else: rv = [ firstline.strip(",") + lastline ] return "\n".join(rv) elif self.normalaction: return firstline + self.normalaction.to_string() + lastline else: return firstline.strip(",") + lastline def encode(self): if self.normalaction: rv = self.normalaction.encode() else: rv = {} rv['doubleclick'] = self.action.encode() if self.holdaction: rv['hold'] = self.holdaction.encode() if self.name: rv['name'] = self.name return rv def button_press(self, mapper): self.pressed = True if self.waiting: # Double-click happened mapper.remove_scheduled(self.on_timeout) self.waiting = False self.active = self.action self.active.button_press(mapper) else: # First click, start the timer self.waiting = True mapper.schedule(self.timeout, self.on_timeout) def button_release(self, mapper): self.pressed = False if self.waiting and self.active is None and not self.action: # In HoldModifier, button released before timeout mapper.remove_scheduled(self.on_timeout) self.waiting = False if self.normalaction: self.normalaction.button_press(mapper) self.normalaction.button_release(mapper) elif self.active: # Released held button self.active.button_release(mapper) self.active = None def on_timeout(self, mapper, *a): if self.waiting: self.waiting = False if self.pressed: # Timeouted while button is still pressed self.active = self.holdaction if self.holdaction else self.normalaction self.active.button_press(mapper) elif self.normalaction: # User did short click and nothing else self.normalaction.button_press(mapper) self.normalaction.button_release(mapper)
class ModeModifier(Modifier): COMMAND = "mode" MIN_TRIGGER = 2 # When trigger is bellow this position, list of held_triggers is cleared MIN_STICK = 2 # When abs(stick) < MIN_STICK, stick is considered released and held_sticks is cleared def __init__(self, *stuff): Modifier.__init__(self) self.default = None self.mods = {} self.held_buttons = set() self.held_sticks = set() self.held_triggers = {} self.order = [] self.old_gyro = None button = None for i in stuff: if self.default is not None: # Default has to be last parameter raise ValueError("Invalid parameters for 'mode'") if isinstance(i, Action): if button is None: self.default = i continue self.mods[button] = i self.order.append(button) button = None elif i in SCButtons: button = i else: raise ValueError("Invalid parameter for 'mode': %s" % (i, )) if self.default is None: self.default = NoAction() def set_haptic(self, hapticdata): supports = False if self.default: supports = self.default.set_haptic(hapticdata) or supports for a in self.mods.values(): supports = a.set_haptic(hapticdata) or supports return supports def set_speed(self, x, y, z): supports = False if self.default: supports = self.default.set_speed(x, y, z) or supports for a in self.mods.values(): supports = a.set_speed(x, y, z) or supports return supports def strip(self): # Returns default action or action assigned to first modifier if self.default: return self.default.strip() if len(self.order) > 0: return self.mods[self.order[0]].strip() # Empty ModeModifier return NoAction() def compress(self): if self.default: self.default = self.default.compress() for button in self.mods: self.mods[button] = self.mods[button].compress() return self def __str__(self): rv = [] for key in self.mods: rv += [key.name, self.mods[key]] if self.default is not None: rv += [self.default] return "<Modifier '%s', %s>" % (self.COMMAND, rv) __repr__ = __str__ def describe(self, context): l = [] if self.default: l.append(self.default) for x in self.order: l.append(self.mods[x]) return "\n".join([x.describe(context) for x in l]) def to_string(self, multiline=False, pad=0): if multiline: rv = [(" " * pad) + "mode("] for key in self.mods: a_str = self.mods[key].to_string(True).split("\n") a_str[0] = (" " * pad) + " " + (key.name + ",").ljust( 11) + a_str[0] # Key has to be one of SCButtons for i in xrange(1, len(a_str)): a_str[i] = (" " * pad) + " " + a_str[i] a_str[-1] = a_str[-1] + "," rv += a_str if self.default is not None: a_str = [(" " * pad) + " " + x for x in self.default.to_string(True).split("\n")] rv += a_str if rv[-1][-1] == ",": rv[-1] = rv[-1][0:-1] rv += [(" " * pad) + ")"] return "\n".join(rv) else: rv = [] for key in self.mods: rv += [key.name, self.mods[key].to_string(False)] if self.default is not None: rv += [self.default.to_string(False)] return "mode(" + ", ".join(rv) + ")" def encode(self): rv = self.default.encode() rv['modes'] = {} for key in self.mods: rv['modes'][key.name] = self.mods[key].encode() if self.name: rv['name'] = self.name return rv def select(self, mapper): """ Selects action by pressed button. """ for b in self.order: if mapper.is_pressed(b): return self.mods[b] return self.default def select_b(self, mapper): """ Same as select but returns button as well. """ for b in self.order: if mapper.is_pressed(b): return b, self.mods[b] return None, self.default def button_press(self, mapper): sel = self.select(mapper) self.held_buttons.add(sel) return sel.button_press(mapper) def button_release(self, mapper): # Releases all held buttons, not just button that matches # currently pressed modifier for b in self.held_buttons: b.button_release(mapper) def trigger(self, mapper, position, old_position): if position < ModeModifier.MIN_TRIGGER: for b in self.held_triggers: b.trigger(mapper, 0, self.held_triggers[b]) self.held_triggers = {} return False else: sel = self.select(mapper) self.held_triggers[sel] = position return sel.trigger(mapper, position, old_position) def axis(self, mapper, position, what): return self.select(mapper).axis(mapper, position, what) def gyro(self, mapper, pitch, yaw, roll, *q): sel = self.select(mapper) if sel is not self.old_gyro: if self.old_gyro: self.old_gyro.gyro(mapper, 0, 0, 0, *q) self.old_gyro = sel return sel.gyro(mapper, pitch, yaw, roll, *q) def pad(self, mapper, position, what): return self.select(mapper).pad(mapper, position, what) def whole(self, mapper, x, y, what): if what == STICK: if abs(x) < ModeModifier.MIN_STICK and abs( y) < ModeModifier.MIN_STICK: for b in self.held_sticks: b.whole(mapper, 0, 0, what) self.held_sticks.clear() else: self.held_sticks.add(self.select(mapper)) for b in self.held_sticks: b.whole(mapper, x, y, what) else: return self.select(mapper).whole(mapper, x, y, what)