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-codeorder_line_cancel_nowork_debugging
parent
12c346d846
commit
3db0cf9054
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
Loading…
Reference in New Issue