Skip to content
Snippets Groups Projects
Commit 05ef2fdc authored by moon2's avatar moon2 :speech_balloon:
Browse files

widgets: various minor fixes

parent 32877736
No related branches found
No related tags found
1 merge request!735various bugfixes
Pipeline #13253 passed
...@@ -279,7 +279,6 @@ class Pressable: ...@@ -279,7 +279,6 @@ class Pressable:
class TouchableState(Enum): class TouchableState(Enum):
UP = "up" UP = "up"
BEGIN = "begin" BEGIN = "begin"
RESTING = "resting"
MOVED = "moved" MOVED = "moved"
ENDED = "ended" ENDED = "ended"
...@@ -345,16 +344,17 @@ class Touchable: ...@@ -345,16 +344,17 @@ class Touchable:
def __init__(self, ix) -> None: def __init__(self, ix) -> None:
self._state = self.UP self._state = self.UP
self._dis = None
self._vel = 0j
self._ts_prev = 0 self._ts_prev = 0
conf = captouch.Config.empty() conf = captouch.Config.empty()
self._scroller = widgets.Scroller( self._scroller = widgets.Scroller(
conf, ix, constraint=widgets.constraints.Ellipse() conf, ix, constraint=widgets.constraints.Ellipse()
) )
# somewhat illegal, just for the backwards hack...
self._scroller.constraint = None self._scroller.constraint = None
self._active_prev = False self._active_prev = False
self._cached_gesture = None
def _update(self, ts: int, petal: captouch.CaptouchPetalState) -> None: def _update(self, ts: int, petal: captouch.CaptouchPetalState) -> None:
""" """
...@@ -363,23 +363,20 @@ class Touchable: ...@@ -363,23 +363,20 @@ class Touchable:
self._scroller.think(None, ts - self._ts_prev, petal) self._scroller.think(None, ts - self._ts_prev, petal)
self._ts_prev = ts self._ts_prev = ts
self._cached_gesture = None
if self._scroller.active: if self._scroller.active:
if self._active_prev == self._scroller.active: if self._active_prev == self._scroller.active:
self._state = self.MOVED self._state = self.MOVED
self._dis = self._scroller.pos
else: else:
self._state = self.BEGIN self._state = self.BEGIN
self._vel = 0j
self._dis = 0j
else:
if self._active_prev == self._scroller.active:
self._state = self.UP
self._dis = None
else: else:
self._state = self.ENDED self._state = self.ENDED
self._vel = self._scroller._vel if self._scroller.pos or self._scroller._vel:
self._cached_gesture = self.current_gesture()
self._scroller.pos = 0j self._scroller.pos = 0j
self._scroller._vel = 0j self._scroller._vel = 0j
elif self._active_prev == self._scroller.active:
self._state = self.UP
self._active_prev = self._scroller.active self._active_prev = self._scroller.active
def phase(self) -> TouchableState: def phase(self) -> TouchableState:
...@@ -389,10 +386,12 @@ class Touchable: ...@@ -389,10 +386,12 @@ class Touchable:
return self._state return self._state
def current_gesture(self) -> Optional[Gesture]: def current_gesture(self) -> Optional[Gesture]:
if self._dis is None: if self._cached_gesture:
return self._cached_gesture
if self._state == self.UP:
return None return None
dis = self._dis * 35000 dis = self._scroller.pos * 35000
vel = self._vel * 35000 * 1000 vel = self._scroller._vel * 35000 * 1000
return self.Gesture(*[(p.real, p.imag) for p in [dis, vel]]) return self.Gesture(*[(p.real, p.imag) for p in [dis, vel]])
......
...@@ -97,8 +97,14 @@ class OSMenu(SimpleMenu): ...@@ -97,8 +97,14 @@ class OSMenu(SimpleMenu):
def __init__(self, items: List[MenuItem]) -> None: def __init__(self, items: List[MenuItem]) -> None:
super().__init__(items) super().__init__(items)
self.captouch_config = captouch.Config.default() self.captouch_config = captouch.Config.empty()
self._scroller = widgets.MultiItemScroller(self.captouch_config, petals=[2, 8]) for x in range(10):
self.captouch_config.petals[x].set_min_mode(1)
self.captouch_config.petals[5].mode = 0
self._scroller = widgets.MultiItemScroller(
self.captouch_config, petals=[2, 8], friction=1
)
self._scroller.max_item = len(items) - 1 self._scroller.max_item = len(items) - 1
self._scroll_controller = self._FakeScrollController(self._scroller) self._scroll_controller = self._FakeScrollController(self._scroller)
self.sensitivity = 1.5 self.sensitivity = 1.5
......
...@@ -207,14 +207,21 @@ class CapScrollController: ...@@ -207,14 +207,21 @@ class CapScrollController:
""" """
Call this in your think() method. Call this in your think() method.
""" """
if t.phase() == t.BEGIN: if t.phase() == t.UP:
rad_p, phi_p = self.position
rad_m, phi_m = self.momentum
rad_p += rad_m / (1000 / delta_ms)
phi_p += phi_m / (1000 / delta_ms)
rad_m *= self._damp
phi_m *= self._damp
self.momentum = (rad_m, phi_m)
self.position = (rad_p, phi_p)
self._grab_start = None
else:
if self._grab_start is None:
self._grab_start = self.position self._grab_start = self.position
self.momentum = (0.0, 0.0)
if t.phase() == t.MOVED and self._grab_start is not None:
move = t.current_gesture() move = t.current_gesture()
assert move is not None assert move is not None
assert self._grab_start is not None
drad, dphi = move.distance drad, dphi = move.distance
drad /= 1000 drad /= 1000
dphi /= 1000 dphi /= 1000
...@@ -222,20 +229,7 @@ class CapScrollController: ...@@ -222,20 +229,7 @@ class CapScrollController:
sphi = self._grab_start[1] sphi = self._grab_start[1]
self.position = (srad + drad, sphi + dphi) self.position = (srad + drad, sphi + dphi)
if t.phase() == t.ENDED:
move = t.current_gesture()
assert move is not None
vrad, vphi = move.velocity vrad, vphi = move.velocity
vrad /= 1000 vrad /= 1000
vphi /= 1000 vphi /= 1000
self.momentum = (vrad, vphi) self.momentum = (vrad, vphi)
if t.phase() == t.UP:
rad_p, phi_p = self.position
rad_m, phi_m = self.momentum
rad_p += rad_m / (1000 / delta_ms)
phi_p += phi_m / (1000 / delta_ms)
rad_m *= self._damp
phi_m *= self._damp
self.momentum = (rad_m, phi_m)
self.position = (rad_p, phi_p)
...@@ -241,6 +241,7 @@ class CaptouchWidget(Widget): ...@@ -241,6 +241,7 @@ class CaptouchWidget(Widget):
) )
def _apply_velocity(self, delta_ms): def _apply_velocity(self, delta_ms):
vel_prev = self._vel
if (not self._vel) or abs(self._vel) < 0.0001: if (not self._vel) or abs(self._vel) < 0.0001:
self._vel = 0j self._vel = 0j
return False return False
...@@ -437,7 +438,7 @@ class Scroller(PetalWidget): ...@@ -437,7 +438,7 @@ class Scroller(PetalWidget):
def _autoclear(self): def _autoclear(self):
self._update_pos() self._update_pos()
self._ref = None self._ref = None
if self._log.length_ms() > 40: if self._log.length_ms() > 27:
start = 0 start = 0
stop = self._log.length() - 1 stop = self._log.length() - 1
if stop > 2: if stop > 2:
...@@ -446,6 +447,11 @@ class Scroller(PetalWidget): ...@@ -446,6 +447,11 @@ class Scroller(PetalWidget):
start = self._log.index_offset_ms(-1, -70) start = self._log.index_offset_ms(-1, -70)
if self._log.index_offset_ms(start, 20) is not None: if self._log.index_offset_ms(start, 20) is not None:
vel = self._log.slope_per_ms(start, stop) vel = self._log.slope_per_ms(start, stop)
# gate val experimentally determined on petal 2
# optimum might be different for each petal but good enough for now
if abs(vel) < 0.01:
self._vel = 0
else:
self._vel = vel * self.gain self._vel = vel * self.gain
self._pos_range = None self._pos_range = None
# trigger callbacks # trigger callbacks
...@@ -662,30 +668,36 @@ class MultiSlider(CaptouchWidget): ...@@ -662,30 +668,36 @@ class MultiSlider(CaptouchWidget):
class MultiItemScroller(CaptouchWidget): class MultiItemScroller(CaptouchWidget):
def __init__(self, config, *, petals): def __init__(self, config, *, petals, gain=1, friction=0.7):
self._widgets = [] super().__init__(config, gain=gain, friction=friction)
super().__init__(config)
self._item = 0 self._item = 0
self._max_item = None self._max_item = None
self._vel = 0
petals = set(petals) petals = set(petals)
for petal in petals: for petal in petals:
if petal not in range(0, 10, 2): if petal not in range(0, 10, 2):
raise ValueError("all petals must be top petals") raise ValueError("all petals must be top petals")
constraint = constraints.Rectangle(100) constraint = constraints.Rectangle()
self._widgets = [ self._widgets = [
Scroller( Scroller(
config, config,
x, x,
gain=self.gain * captouch.PETAL_ANGLES[x], gain=self.gain * captouch.PETAL_ANGLES[x],
friction=1, friction=self.friction,
constraint=constraint, constraint=constraint,
) )
for x in petals for x in petals
] ]
for widget in self._widgets: for widget in self._widgets:
widget.ref_precision = 3 widget.ref_precision = 3
widget.constraint = None
def add_to_config(self, config):
if hasattr(self, "_widgets"):
for widget in self._widgets:
widget.add_to_config(config)
@property @property
def gain(self): def gain(self):
...@@ -694,9 +706,23 @@ class MultiItemScroller(CaptouchWidget): ...@@ -694,9 +706,23 @@ class MultiItemScroller(CaptouchWidget):
@gain.setter @gain.setter
def gain(self, value): def gain(self, value):
self._gain = value self._gain = value
if hasattr(self, "_widgets"):
for widget in self._widgets: for widget in self._widgets:
widget.gain = value * captouch.PETAL_ANGLES[widget.petal] widget.gain = value * captouch.PETAL_ANGLES[widget.petal]
@property
def friction(self):
return self._friction
@friction.setter
def friction(self, value):
if value != 1:
raise ValueError("unfinished widget, friction must be 1 for now, sorry!")
self._friction = value
if hasattr(self, "_widgets"):
for widget in self._widgets:
widget.friction = value
@property @property
def item(self): def item(self):
return self._item return self._item
...@@ -725,10 +751,6 @@ class MultiItemScroller(CaptouchWidget): ...@@ -725,10 +751,6 @@ class MultiItemScroller(CaptouchWidget):
self._max_item = val self._max_item = val
self.item = self._item self.item = self._item
def add_to_config(self, config):
for widget in self._widgets:
widget.add_to_config(config)
def on_enter(self): def on_enter(self):
for widget in self._widgets: for widget in self._widgets:
widget.on_enter() widget.on_enter()
...@@ -749,12 +771,30 @@ class MultiItemScroller(CaptouchWidget): ...@@ -749,12 +771,30 @@ class MultiItemScroller(CaptouchWidget):
else: else:
widget.pos = 0j widget.pos = 0j
offset = self._item + delta - self.pos target = self._item + delta
delta_ms_phys = delta_ms
while delta_ms_phys:
if delta_ms_phys < 50:
delta_s = delta_ms_phys / 1000
delta_ms_phys = 0
else:
delta_s = 50 / 1000
delta_ms_phys -= 50
offset = target - self.pos
if offset > 4: if offset > 4:
offset = 4 offset = 4
elif offset < -4: elif offset < -4:
offset = -4 offset = -4
self.pos += offset * (1 - (0.002 ** (delta_ms / 1000))) acc = offset * 175
acc -= self._vel * 25
# unit: items per second
self._vel += acc * delta_s
# if self._vel > 8:
# self._vel = 8
# elif self._vel < -8:
# self._vel = -8
self.pos += self._vel * delta_s
delta_hyst = int(delta * 1.5) delta_hyst = int(delta * 1.5)
if delta_hyst: if delta_hyst:
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment