Move level marker to annotate module

fsp_feeds
Tyler Goodlet 2021-07-22 12:05:53 -04:00
parent a4028d3475
commit 568dd488b5
2 changed files with 149 additions and 162 deletions

View File

@ -18,18 +18,20 @@
Annotations for ur faces. Annotations for ur faces.
""" """
import PyQt5 from typing import Callable
from PyQt5 import QtCore, QtGui
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import QPointF
from PyQt5.QtWidgets import QGraphicsPathItem from PyQt5.QtWidgets import QGraphicsPathItem
from pyqtgraph import Point, functions as fn, Color from pyqtgraph import Point, functions as fn, Color
import numpy as np import numpy as np
from ._anchors import marker_right_points
def mk_marker_path( def mk_marker_path(
style, style: str,
# size: float = 20.0,
# use_path_type: type = QGraphicsPathItem
) -> QGraphicsPathItem: ) -> QGraphicsPathItem:
"""Add a marker to be displayed on the line wrapped in a ``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]) # 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 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( def qgo_draw_markers(
markers: list, markers: list,

View File

@ -18,19 +18,18 @@
Position info and display Position info and display
""" """
from typing import Optional, Callable from typing import Optional
from functools import partial from functools import partial
from math import floor from math import floor
from pyqtgraph import functions as fn from pyqtgraph import functions as fn
from pydantic import BaseModel from pydantic import BaseModel
from PyQt5 import QtGui, QtWidgets
from PyQt5.QtCore import QPointF from PyQt5.QtCore import QPointF
from PyQt5.QtGui import QGraphicsPathItem from PyQt5.QtGui import QGraphicsPathItem
from ._annotate import mk_marker_path from ._annotate import LevelMarker
from ._anchors import ( from ._anchors import (
marker_right_points, # marker_right_points,
gpath_pin, gpath_pin,
# keep_marker_in_view, # keep_marker_in_view,
) )
@ -58,146 +57,6 @@ class Position(BaseModel):
fills: list[Status] = [] 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: class PositionTracker:
'''Track and display a real-time position for a single symbol '''Track and display a real-time position for a single symbol
on a chart. on a chart.
@ -366,11 +225,9 @@ class PositionTracker:
if size > 0: if size > 0:
style = '|<' style = '|<'
direction = 'up'
elif size < 0: elif size < 0:
style = '>|' style = '>|'
direction = 'down'
arrow = LevelMarker( arrow = LevelMarker(
chart=self.chart, chart=self.chart,
@ -378,13 +235,6 @@ class PositionTracker:
get_level=self.level, get_level=self.level,
size=arrow_size, 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) self.chart.getViewBox().scene().addItem(arrow)
arrow.show() arrow.show()