Add order-cancel debugging and multiline kbd logs

Add verbose logging + error handling for order cancellation
hotkey path and multiline style for view-mode kb msgs.

Deats,
- add `Cursor.is_hovered()` to check hover state
- log warnings when no orders cancelled via <c> hotkey
- add try-except around `.cancel_orders_under_cursor()`
- log `cur._hovered` state in `.ui._lines` hover handlers
- change `Dialog.cancel_orders()` to return `list[Dialog]`
- fix import: `Flume` from `.data.flows` vs `.data.feed`
- comment-out multi-status msgs in order submit/cancel

Also,
- convert all multiline kbd `if` conditionals to use `and`
  on separate lines for consistency
- move `import tractor` to top of `._interaction`
- change `print()` to `log.debug()` in `LevelLine`
- fix type annotation spacing: `Callable|None` vs `Callable | None`

(this commit msg was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
order_line_cancel_nowork_debugging
Gud Boi 2026-02-04 18:52:47 -05:00
parent 12c346d846
commit 3db0cf9054
5 changed files with 98 additions and 36 deletions

View File

@ -413,9 +413,18 @@ class Cursor(pg.GraphicsObject):
self,
item: pg.GraphicsObject,
) -> None:
assert getattr(item, 'delete'), f"{item} must define a ``.delete()``"
assert getattr(
item,
'delete',
), f"{item} must define a ``.delete()``"
self._hovered.add(item)
def is_hovered(
self,
item: pg.GraphicsObject,
) -> bool:
return item in self._hovered
def add_plot(
self,
plot: ChartPlotWidget, # noqa

View File

@ -45,7 +45,7 @@ from piker.ui.qt import QLineF
from ..data._sharedmem import (
ShmArray,
)
from ..data.feed import Flume
from ..data.flows import Flume
from ..data._formatters import (
IncrementalFormatter,
OHLCBarsFmtr, # Plain OHLC renderer

View File

@ -43,6 +43,7 @@ from pyqtgraph import (
functions as fn,
)
import numpy as np
import tractor
import trio
from piker.ui.qt import (
@ -72,7 +73,10 @@ if TYPE_CHECKING:
GodWidget,
)
from ._dataviz import Viz
from .order_mode import OrderMode
from .order_mode import (
OrderMode,
Dialog,
)
from ._display import DisplayState
@ -130,7 +134,12 @@ async def handle_viewmode_kb_inputs(
async for kbmsg in recv_chan:
event, etype, key, mods, text = kbmsg.to_tuple()
log.debug(f'key: {key}, mods: {mods}, text: {text}')
log.debug(
f'View-mode kb-msg received,\n'
f'mods: {mods!r}\n'
f'key: {key!r}\n'
f'text: {text!r}\n'
)
now = time.time()
period = now - last
@ -158,8 +167,12 @@ async def handle_viewmode_kb_inputs(
# have no previous keys or we do and the min_tap period is
# met
if (
not fast_key_seq or
period <= min_tap and fast_key_seq
not fast_key_seq
or (
period <= min_tap
and
fast_key_seq
)
):
fast_key_seq.append(text)
log.debug(f'fast keys seqs {fast_key_seq}')
@ -174,7 +187,8 @@ async def handle_viewmode_kb_inputs(
# UI REPL-shell, with ctrl-p (for "pause")
if (
ctrl
and key in {
and
key in {
Qt.Key_P,
}
):
@ -184,7 +198,6 @@ async def handle_viewmode_kb_inputs(
vlm_chart = chart.linked.subplots['volume'] # noqa
vlm_viz = vlm_chart.main_viz # noqa
dvlm_pi = vlm_chart._vizs['dolla_vlm'].plot # noqa
import tractor
await tractor.pause()
view.interact_graphics_cycle()
@ -192,7 +205,8 @@ async def handle_viewmode_kb_inputs(
# shown data `Viz`s for the current chart app.
if (
ctrl
and key in {
and
key in {
Qt.Key_R,
}
):
@ -231,7 +245,8 @@ async def handle_viewmode_kb_inputs(
key == Qt.Key_Escape
or (
ctrl
and key == Qt.Key_C
and
key == Qt.Key_C
)
):
# ctrl-c as cancel
@ -242,17 +257,35 @@ async def handle_viewmode_kb_inputs(
# cancel order or clear graphics
if (
key == Qt.Key_C
or key == Qt.Key_Delete
or
key == Qt.Key_Delete
):
# log.info('Handling <c> hotkey!')
try:
dialogs: list[Dialog] = order_mode.cancel_orders_under_cursor()
except BaseException:
log.exception('Failed to cancel orders !?\n')
await tractor.pause()
order_mode.cancel_orders_under_cursor()
if not dialogs:
log.warning(
'No orders were cancelled?\n'
'Is there an order-line under the cursor?\n'
'If you think there IS your DE might be "hiding the mouse" before '
'we rx the keyboard input via Qt..\n'
'=> Check your DE and/or TWM settings to be sure! <=\n'
)
# ^TODO?, some way to detect if there's lines and
# the DE is cuckin with things?
# await tractor.pause()
# View modes
if (
ctrl
and (
key == Qt.Key_Equal
or key == Qt.Key_I
or
key == Qt.Key_I
)
):
view.wheelEvent(
@ -264,7 +297,8 @@ async def handle_viewmode_kb_inputs(
ctrl
and (
key == Qt.Key_Minus
or key == Qt.Key_O
or
key == Qt.Key_O
)
):
view.wheelEvent(
@ -275,7 +309,8 @@ async def handle_viewmode_kb_inputs(
elif (
not ctrl
and key == Qt.Key_R
and
key == Qt.Key_R
):
# NOTE: seems that if we don't yield a Qt render
# cycle then the m4 downsampled curves will show here
@ -477,7 +512,8 @@ async def handle_viewmode_mouse(
# view.raiseContextMenu(event)
if (
view.order_mode.active and
view.order_mode.active
and
button == QtCore.Qt.LeftButton
):
# when in order mode, submit execution
@ -781,7 +817,8 @@ class ChartView(ViewBox):
# Scale or translate based on mouse button
if btn & (
QtCore.Qt.LeftButton | QtCore.Qt.MidButton
QtCore.Qt.LeftButton
| QtCore.Qt.MidButton
):
# zoom y-axis ONLY when click-n-drag on it
# if axis == 1:

View File

@ -51,10 +51,13 @@ from ._anchors import (
from ..calc import humanize
from ._label import Label
from ._style import hcolor, _font
from ..log import get_logger
if TYPE_CHECKING:
from ._cursor import Cursor
log = get_logger(__name__)
# TODO: probably worth investigating if we can
# make .boundingRect() faster:
@ -346,7 +349,7 @@ class LevelLine(pg.InfiniteLine):
) -> None:
# TODO: enter labels edit mode
print(f'double click {ev}')
log.debug(f'double click {ev}')
def paint(
self,
@ -460,10 +463,19 @@ class LevelLine(pg.InfiniteLine):
# hovered
if (
not ev.isExit()
and ev.acceptDrags(QtCore.Qt.LeftButton)
and
ev.acceptDrags(QtCore.Qt.LeftButton)
):
# if already hovered we don't need to run again
if self.mouseHovering is True:
if (
self.mouseHovering is True
and
cur.is_hovered(self)
):
log.debug(
f'Already hovering ??\n'
f'cur._hovered: {cur._hovered!r}\n'
)
return
if self.only_show_markers_on_hover:
@ -480,6 +492,7 @@ class LevelLine(pg.InfiniteLine):
cur._y_label_update = False
# add us to cursor state
log.debug(f'Adding line {self!r}\n')
cur.add_hovered(self)
if self._hide_xhair_on_hover:
@ -507,6 +520,7 @@ class LevelLine(pg.InfiniteLine):
self.currentPen = self.pen
log.debug(f'Removing line {self!r}\n')
cur._hovered.remove(self)
if self.only_show_markers_on_hover:

View File

@ -77,7 +77,6 @@ from ._style import _font
from ._forms import open_form_input_handling
from ._notify import notify_from_ems_status_msg
if TYPE_CHECKING:
from ._chart import (
ChartPlotWidget,
@ -436,7 +435,7 @@ class OrderMode:
lines=lines,
last_status_close=self.multistatus.open_status(
f'submitting {order.exec_mode}-{order.action}',
final_msg=f'submitted {order.exec_mode}-{order.action}',
# final_msg=f'submitted {order.exec_mode}-{order.action}',
clear_on_next=True,
)
)
@ -528,7 +527,7 @@ class OrderMode:
# a submission is the start of a new order dialog
dialog = self.dialogs[uuid]
dialog.lines = lines
cls: Callable | None = dialog.last_status_close
cls: Callable|None = dialog.last_status_close
if cls:
cls()
@ -658,7 +657,7 @@ class OrderMode:
return True
def cancel_orders_under_cursor(self) -> list[str]:
def cancel_orders_under_cursor(self) -> list[Dialog]:
return self.cancel_orders(
self.oids_from_lines(
self.lines.lines_under_cursor()
@ -687,24 +686,28 @@ class OrderMode:
self,
oids: list[str],
) -> None:
) -> list[Dialog]:
'''
Cancel all orders from a list of order ids: `oids`.
'''
key = self.multistatus.open_status(
f'cancelling {len(oids)} orders',
final_msg=f'cancelled orders:\n{oids}',
group_key=True
)
# key = self.multistatus.open_status(
# f'cancelling {len(oids)} orders',
# final_msg=f'cancelled orders:\n{oids}',
# group_key=True
# )
dialogs: list[Dialog] = []
for oid in oids:
if dialog := self.dialogs.get(oid):
self.client.cancel_nowait(uuid=oid)
cancel_status_close = self.multistatus.open_status(
f'cancelling order {oid}',
group_key=key,
)
dialog.last_status_close = cancel_status_close
# cancel_status_close = self.multistatus.open_status(
# f'cancelling order {oid}',
# group_key=key,
# )
# dialog.last_status_close = cancel_status_close
dialogs.append(dialog)
return dialogs
def cancel_all_orders(self) -> None:
'''
@ -776,7 +779,6 @@ class OrderMode:
@asynccontextmanager
async def open_order_mode(
feed: Feed,
godw: GodWidget,
fqme: str,