Move level marker to annotate module
parent
6cdb2fca41
commit
40a38284df
|
@ -18,18 +18,20 @@
|
|||
Annotations for ur faces.
|
||||
|
||||
"""
|
||||
import PyQt5
|
||||
from PyQt5 import QtCore, QtGui
|
||||
from typing import Callable
|
||||
|
||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||
from PyQt5.QtCore import QPointF
|
||||
from PyQt5.QtWidgets import QGraphicsPathItem
|
||||
from pyqtgraph import Point, functions as fn, Color
|
||||
import numpy as np
|
||||
|
||||
from ._anchors import marker_right_points
|
||||
|
||||
|
||||
def mk_marker_path(
|
||||
|
||||
style,
|
||||
# size: float = 20.0,
|
||||
# use_path_type: type = QGraphicsPathItem
|
||||
style: str,
|
||||
|
||||
) -> QGraphicsPathItem:
|
||||
"""Add a marker to be displayed on the line wrapped in a ``QGraphicsPathItem``
|
||||
|
@ -83,13 +85,148 @@ def mk_marker_path(
|
|||
|
||||
# self._maxMarkerSize = max([m[2] / 2. for m in self.markers])
|
||||
|
||||
# if use_path_type:
|
||||
# path = use_path_type(path)
|
||||
# path.scale(size, size)
|
||||
|
||||
return path
|
||||
|
||||
|
||||
class LevelMarker(QGraphicsPathItem):
|
||||
'''An arrow marker path graphich which redraws itself
|
||||
to the specified view coordinate level on each paint cycle.
|
||||
|
||||
'''
|
||||
def __init__(
|
||||
self,
|
||||
chart: 'ChartPlotWidget', # noqa
|
||||
style: str,
|
||||
get_level: Callable[..., float],
|
||||
size: float = 20,
|
||||
keep_in_view: bool = True,
|
||||
|
||||
) -> None:
|
||||
|
||||
# get polygon and scale
|
||||
super().__init__()
|
||||
self.scale(size, size)
|
||||
|
||||
# interally generates path
|
||||
self._style = None
|
||||
self.style = style
|
||||
|
||||
self.chart = chart
|
||||
|
||||
self.get_level = get_level
|
||||
self.scene_x = lambda: marker_right_points(chart)[1]
|
||||
self.level: float = 0
|
||||
self.keep_in_view = keep_in_view
|
||||
|
||||
assert self.path_br
|
||||
|
||||
@property
|
||||
def style(self) -> str:
|
||||
return self._style
|
||||
|
||||
@style.setter
|
||||
def style(self, value: str) -> None:
|
||||
if self._style != value:
|
||||
polygon = mk_marker_path(value)
|
||||
self.setPath(polygon)
|
||||
self._style = value
|
||||
|
||||
# get the path for the opaque path **without** weird
|
||||
# surrounding margin
|
||||
self.path_br = self.mapToScene(
|
||||
self.path()
|
||||
).boundingRect()
|
||||
|
||||
def delete(self) -> None:
|
||||
self.scene().removeItem(self)
|
||||
|
||||
@property
|
||||
def h(self) -> float:
|
||||
return self.path_br.height()
|
||||
|
||||
@property
|
||||
def w(self) -> float:
|
||||
return self.path_br.width()
|
||||
|
||||
def position_in_view(
|
||||
self,
|
||||
# level: float,
|
||||
|
||||
) -> None:
|
||||
'''Show a pp off-screen indicator for a level label.
|
||||
|
||||
This is like in fps games where you have a gps "nav" indicator
|
||||
but your teammate is outside the range of view, except in 2D, on
|
||||
the y-dimension.
|
||||
|
||||
'''
|
||||
level = self.get_level()
|
||||
|
||||
view = self.chart.getViewBox()
|
||||
vr = view.state['viewRange']
|
||||
ymn, ymx = vr[1]
|
||||
|
||||
# _, marker_right, _ = marker_right_points(line._chart)
|
||||
x = self.scene_x()
|
||||
|
||||
if level > ymx: # pin to top of view
|
||||
self.setPos(
|
||||
QPointF(
|
||||
x,
|
||||
self.h/3,
|
||||
)
|
||||
)
|
||||
|
||||
elif level < ymn: # pin to bottom of view
|
||||
|
||||
self.setPos(
|
||||
QPointF(
|
||||
x,
|
||||
view.height() - 4/3*self.h,
|
||||
)
|
||||
)
|
||||
|
||||
else:
|
||||
# pp line is viewable so show marker normally
|
||||
self.setPos(
|
||||
x,
|
||||
self.chart.view.mapFromView(
|
||||
QPointF(0, self.get_level())
|
||||
).y()
|
||||
)
|
||||
|
||||
# marker = line._marker
|
||||
if getattr(self, 'label', None):
|
||||
label = self.label
|
||||
|
||||
# re-anchor label (i.e. trigger call of ``arrow_tr()`` from above
|
||||
label.update()
|
||||
|
||||
def paint(
|
||||
self,
|
||||
|
||||
p: QtGui.QPainter,
|
||||
opt: QtWidgets.QStyleOptionGraphicsItem,
|
||||
w: QtWidgets.QWidget
|
||||
|
||||
) -> None:
|
||||
'''Core paint which we override to always update
|
||||
our marker position in scene coordinates from a
|
||||
view cooridnate "level".
|
||||
|
||||
'''
|
||||
if self.keep_in_view:
|
||||
self.position_in_view()
|
||||
|
||||
else: # just place at desired level even if not in view
|
||||
self.setPos(
|
||||
self.scene_x(),
|
||||
self.mapToScene(QPointF(0, self.get_level())).y()
|
||||
)
|
||||
|
||||
return super().paint(p, opt, w)
|
||||
|
||||
|
||||
def qgo_draw_markers(
|
||||
|
||||
markers: list,
|
||||
|
|
|
@ -18,19 +18,18 @@
|
|||
Position info and display
|
||||
|
||||
"""
|
||||
from typing import Optional, Callable
|
||||
from typing import Optional
|
||||
from functools import partial
|
||||
from math import floor
|
||||
|
||||
from pyqtgraph import functions as fn
|
||||
from pydantic import BaseModel
|
||||
from PyQt5 import QtGui, QtWidgets
|
||||
from PyQt5.QtCore import QPointF
|
||||
from PyQt5.QtGui import QGraphicsPathItem
|
||||
|
||||
from ._annotate import mk_marker_path
|
||||
from ._annotate import LevelMarker
|
||||
from ._anchors import (
|
||||
marker_right_points,
|
||||
# marker_right_points,
|
||||
gpath_pin,
|
||||
# keep_marker_in_view,
|
||||
)
|
||||
|
@ -58,146 +57,6 @@ class Position(BaseModel):
|
|||
fills: list[Status] = []
|
||||
|
||||
|
||||
class LevelMarker(QGraphicsPathItem):
|
||||
'''An arrow marker path graphich which redraws itself
|
||||
to the specified view coordinate level on each paint cycle.
|
||||
|
||||
'''
|
||||
def __init__(
|
||||
self,
|
||||
chart: 'ChartPlotWidget', # noqa
|
||||
style: str,
|
||||
get_level: Callable[..., float],
|
||||
size: float = 20,
|
||||
keep_in_view: bool = True,
|
||||
|
||||
) -> None:
|
||||
|
||||
# get polygon and scale
|
||||
super().__init__()
|
||||
self.scale(size, size)
|
||||
|
||||
# interally generates path
|
||||
self._style = None
|
||||
self.style = style
|
||||
|
||||
self.chart = chart
|
||||
|
||||
self.get_level = get_level
|
||||
self.scene_x = lambda: marker_right_points(chart)[1]
|
||||
self.level: float = 0
|
||||
self.keep_in_view = keep_in_view
|
||||
|
||||
assert self.path_br
|
||||
|
||||
@property
|
||||
def style(self) -> str:
|
||||
return self._style
|
||||
|
||||
@style.setter
|
||||
def style(self, value: str) -> None:
|
||||
if self._style != value:
|
||||
polygon = mk_marker_path(value)
|
||||
self.setPath(polygon)
|
||||
self._style = value
|
||||
|
||||
# get the path for the opaque path **without** weird
|
||||
# surrounding margin
|
||||
self.path_br = self.mapToScene(
|
||||
self.path()
|
||||
).boundingRect()
|
||||
|
||||
|
||||
def delete(self) -> None:
|
||||
self.scene().removeItem(self)
|
||||
|
||||
@property
|
||||
def h(self) -> float:
|
||||
return self.path_br.height()
|
||||
|
||||
@property
|
||||
def w(self) -> float:
|
||||
return self.path_br.width()
|
||||
|
||||
def position_in_view(
|
||||
self,
|
||||
# level: float,
|
||||
|
||||
) -> None:
|
||||
'''Show a pp off-screen indicator for a level label.
|
||||
|
||||
This is like in fps games where you have a gps "nav" indicator
|
||||
but your teammate is outside the range of view, except in 2D, on
|
||||
the y-dimension.
|
||||
|
||||
'''
|
||||
level = self.get_level()
|
||||
|
||||
view = self.chart.getViewBox()
|
||||
vr = view.state['viewRange']
|
||||
ymn, ymx = vr[1]
|
||||
|
||||
# _, marker_right, _ = marker_right_points(line._chart)
|
||||
x = self.scene_x()
|
||||
|
||||
if level > ymx: # pin to top of view
|
||||
self.setPos(
|
||||
QPointF(
|
||||
x,
|
||||
self.h/3,
|
||||
)
|
||||
)
|
||||
|
||||
elif level < ymn: # pin to bottom of view
|
||||
|
||||
self.setPos(
|
||||
QPointF(
|
||||
x,
|
||||
view.height() - 4/3*self.h,
|
||||
)
|
||||
)
|
||||
|
||||
else:
|
||||
# pp line is viewable so show marker normally
|
||||
self.setPos(
|
||||
x,
|
||||
self.chart.view.mapFromView(
|
||||
QPointF(0, self.get_level())
|
||||
).y()
|
||||
)
|
||||
|
||||
# marker = line._marker
|
||||
if getattr(self, 'label', None):
|
||||
label = self.label
|
||||
|
||||
# re-anchor label (i.e. trigger call of ``arrow_tr()`` from above
|
||||
label.update()
|
||||
|
||||
def paint(
|
||||
self,
|
||||
|
||||
p: QtGui.QPainter,
|
||||
opt: QtWidgets.QStyleOptionGraphicsItem,
|
||||
w: QtWidgets.QWidget
|
||||
|
||||
) -> None:
|
||||
'''Core paint which we override to always update
|
||||
our marker position in scene coordinates from a
|
||||
view cooridnate "level".
|
||||
|
||||
'''
|
||||
if self.keep_in_view:
|
||||
self.position_in_view()
|
||||
|
||||
else: # just place at desired level even if not in view
|
||||
self.setPos(
|
||||
self.scene_x(),
|
||||
self.mapToScene(QPointF(0, self.get_level())).y()
|
||||
)
|
||||
|
||||
return super().paint(p, opt, w)
|
||||
|
||||
|
||||
class PositionTracker:
|
||||
'''Track and display a real-time position for a single symbol
|
||||
on a chart.
|
||||
|
@ -366,11 +225,9 @@ class PositionTracker:
|
|||
|
||||
if size > 0:
|
||||
style = '|<'
|
||||
direction = 'up'
|
||||
|
||||
elif size < 0:
|
||||
style = '>|'
|
||||
direction = 'down'
|
||||
|
||||
arrow = LevelMarker(
|
||||
chart=self.chart,
|
||||
|
@ -378,13 +235,6 @@ class PositionTracker:
|
|||
get_level=self.level,
|
||||
size=arrow_size,
|
||||
)
|
||||
# _, marker_right, _ = marker_right_points(self.chart)
|
||||
# arrow.scene_x = marker_right
|
||||
|
||||
# monkey-cache height for sizing on pp nav-hub
|
||||
# arrow._height = path_br.height()
|
||||
# arrow._width = path_br.width()
|
||||
arrow._direction = direction
|
||||
|
||||
self.chart.getViewBox().scene().addItem(arrow)
|
||||
arrow.show()
|
||||
|
|
Loading…
Reference in New Issue