From ca65705c6e7115fd8baca16eb5be24c23b601642 Mon Sep 17 00:00:00 2001 From: AlexLaur Date: Sun, 28 Mar 2021 15:07:47 +0200 Subject: [PATCH 1/6] add args for toolbars actions --- app/libs/widgets/toolbar.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/libs/widgets/toolbar.py b/app/libs/widgets/toolbar.py index bdb1b34..97b4638 100644 --- a/app/libs/widgets/toolbar.py +++ b/app/libs/widgets/toolbar.py @@ -28,7 +28,7 @@ def __init__(self, parent=None): def _trigger_action(self): """Called on action triggered""" sender = self.sender() - self.signals.sig_action_triggered.emit(sender.action) + self.signals.sig_action_triggered.emit(sender.action, sender.args) def init_toolbar(self): """This method inits the toolbar of the app""" @@ -136,6 +136,7 @@ def __init__(self, parent=None, text=None, action=None, **kwargs): # Properties self.action = action + self.args = kwargs.get("args", {}) icon = kwargs.get("icon", None) if icon: From ae5a8e392c961a1ca99ebe874b604b752ec2e774 Mon Sep 17 00:00:00 2001 From: AlexLaur Date: Sun, 28 Mar 2021 15:11:18 +0200 Subject: [PATCH 2/6] args for draw line --- app/resources/toolbar/toolbar.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/resources/toolbar/toolbar.json b/app/resources/toolbar/toolbar.json index f3f4d7b..b083503 100644 --- a/app/resources/toolbar/toolbar.json +++ b/app/resources/toolbar/toolbar.json @@ -16,7 +16,10 @@ "type": "resources", "value": ":/svg/trend-line.svg" }, - "action": "method_to_call", + "action": "roi_manager.set_tool", + "args": { + "tool": "line_drawer" + }, "tooltip": "Trend Line", "text": "Trend Line", "shortcut": "Alt+T", From 274712d415629b8c15d5cfe3a20821b38c554f9e Mon Sep 17 00:00:00 2001 From: AlexLaur Date: Sun, 28 Mar 2021 15:14:58 +0200 Subject: [PATCH 3/6] edit events for action trigerred --- app/libs/events_handler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/libs/events_handler.py b/app/libs/events_handler.py index 2021684..5c23967 100644 --- a/app/libs/events_handler.py +++ b/app/libs/events_handler.py @@ -22,7 +22,7 @@ class EventHandler(QtCore.QObject): sig_indicator_settings_canceled = QtCore.Signal(object) sig_indicator_settings_reseted = QtCore.Signal(object) - sig_action_triggered = QtCore.Signal(str) + sig_action_triggered = QtCore.Signal(str, dict) sig_favorite_created = QtCore.Signal(str) sig_favorite_loaded = QtCore.Signal(list) From 57e7a7f6b0ad14b89186d340a5dc81636bc0e2e2 Mon Sep 17 00:00:00 2001 From: AlexLaur Date: Sun, 28 Mar 2021 15:15:56 +0200 Subject: [PATCH 4/6] edit signal action triggered --- app/view.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/app/view.py b/app/view.py index ee274fe..d3aa622 100644 --- a/app/view.py +++ b/app/view.py @@ -13,6 +13,7 @@ from libs.thread_pool import ThreadPool from libs.graph.candlestick import CandlestickItem from libs.io.favorite_settings import FavoritesManager +from libs.roi_manager import ROIManager from ui import main_window @@ -67,7 +68,6 @@ def __init__(self, parent=None, data=None): self.signals.sig_ticker_infos_fetched.connect( self.wgt_company._on_ticker_infos ) - ## self.signals.sig_ticker_articles_fetched.connect( self.wgt_articles.get_articles ) @@ -157,16 +157,18 @@ def _on_indicator_switched(self, indicator: object, state: bool): else: indicator.remove_indicator(graph_view=self.wgt_graph.graph) - @QtCore.Slot(str) - def _on_action_triggered(self, action: str): + @QtCore.Slot(str, dict) + def _on_action_triggered(self, action: str, args:dict): """Callback on action triggered from the toolbar :param action: The action to find and call :type action: str + :param args: Args for the action + :type args: dict """ action_obj = utils.find_method(module=action, obj=self) if action_obj: - action_obj() + action_obj(**args) def resizeEvent(self, event): if self.tickers_dialog: From 274d84a0da7ea1eeb57de74ab088673a31aca34e Mon Sep 17 00:00:00 2001 From: AlexLaur Date: Sun, 28 Mar 2021 15:52:45 +0200 Subject: [PATCH 5/6] Base for drawing ROI --- app/libs/events_handler.py | 2 + app/libs/graph/graphwidget.py | 25 ++++++++++ app/libs/roi_manager.py | 75 ++++++++++++++++++++++++++++++ app/resources/toolbar/toolbar.json | 2 +- app/view.py | 5 +- 5 files changed, 106 insertions(+), 3 deletions(-) create mode 100644 app/libs/roi_manager.py diff --git a/app/libs/events_handler.py b/app/libs/events_handler.py index 5c23967..40d2097 100644 --- a/app/libs/events_handler.py +++ b/app/libs/events_handler.py @@ -31,4 +31,6 @@ class EventHandler(QtCore.QObject): sig_favorite_removed = QtCore.Signal(dict) sig_favorite_clicked = QtCore.Signal(str) + sig_graph_clicked = QtCore.Signal(list, object) + sig_articles = QtCore.Signal(dict) diff --git a/app/libs/graph/graphwidget.py b/app/libs/graph/graphwidget.py index 7e58082..ddd4688 100644 --- a/app/libs/graph/graphwidget.py +++ b/app/libs/graph/graphwidget.py @@ -2,6 +2,7 @@ from PySide2 import QtCore, QtGui, QtWidgets from libs.graph.candlestick import CandlestickItem +from libs.events_handler import EventHandler from utils import utils # TODO import from palette or Qss @@ -19,11 +20,16 @@ def __init__(self, parent=None): self.v_line = None self.h_line = None + self.signals = EventHandler() + self.g_quotation = self.addPlot(row=0, col=0, name="Quotation") self.g_quotation.showGrid(x=True, y=True, alpha=0.3) self.g_vb = self.g_quotation.vb self.set_cross_hair() + self.g_quotation.scene().sigMouseClicked.connect( + self._on_mouse_clicked + ) def plot_quotation(self, data, clear=True): """Plot the quotation @@ -79,6 +85,7 @@ def set_cross_hair(self): def set_time_x_axis(self, widget): widget.setAxisItems({"bottom": pg.DateAxisItem(orientation="bottom")}) + @QtCore.Slot(object) def _on_mouse_moved(self, event): """Signal on mouse moved @@ -91,6 +98,17 @@ def _on_mouse_moved(self, event): self.v_line.setPos(mousePoint.x()) self.h_line.setPos(mousePoint.y()) + @QtCore.Slot(object) + def _on_mouse_clicked(self, event): + """Called on mouse clicked + + :param event: Mouse clicked + :type event: event + """ + items = self.g_quotation.scene().items(event.scenePos()) + plot_items = [x for x in items if isinstance(x, pg.PlotItem)] + self.signals.sig_graph_clicked.emit(plot_items, event) + class GraphWidget(QtWidgets.QWidget): """Widget wrapper for the graph""" @@ -103,6 +121,13 @@ def __init__(self, parent=None): layout.addWidget(self._graph) self.setLayout(layout) + self.signals = EventHandler() + + # Signals + self._graph.signals.sig_graph_clicked.connect( + self.signals.sig_graph_clicked.emit + ) # Relay signal + @property def graph(self): """Return the graph diff --git a/app/libs/roi_manager.py b/app/libs/roi_manager.py new file mode 100644 index 0000000..b58f1e6 --- /dev/null +++ b/app/libs/roi_manager.py @@ -0,0 +1,75 @@ +import pyqtgraph as pg +from PySide2 import QtCore, QtWidgets + + +class ROIManager(QtCore.QObject): + def __init__(self, parent=None): + super(ROIManager, self).__init__(parent) + + # Constants + self.current_tool = None + self._graph = self.parent().wgt_graph.graph + + # Signals + self.parent().wgt_graph.signals.sig_graph_clicked.connect( + self._on_roi_add_requested + ) + + def drawer(self, graph, event): + """Drawer over the graph""" + # Test + vb = graph.vb + mousePoint = vb.mapSceneToView(event.pos()) + print(mousePoint) + # End test + + if self.current_tool: + self.current_tool(graph=graph) # Exec the current tool + self.unset_tool() + + def bounded_line_drawer(self, graph, **kwargs): + """Draw a bounded line + + :param graph: The graph on whch to draw + :type graph: pg.PlotItem + """ + roi = pg.LineSegmentROI(([50, 50], [150, 50]), removable=True) + graph.addItem(roi) + roi.sigRemoveRequested.connect(self._on_roi_remove_requested) + + def set_tool(self, **kwargs): + """Set the current tool. kwargs may have a tool which corresponds to + the method to call inside this module. + + :return: The current tool + :rtype: method if found, None instead + """ + self.current_tool = getattr(self, kwargs.get("tool", None), None) + return self.current_tool + + def unset_tool(self): + """Unset the current tool""" + self.current_tool = None + + def remove_roi(self, roi): + """Remove the given roi + + :param roi: The roi to remove + :type roi: pg.ROI + """ + print(roi.parent()) + + @QtCore.Slot(list, object) + def _on_roi_add_requested(self, objects, event): + """Called on a draw requested""" + if objects: + self.drawer(graph=objects[0], event=event) + + @QtCore.Slot(object) + def _on_roi_remove_requested(self, roi): + """Called on a request for ROI deletion + + :param roi: The roi to remove + :type roi: pg.ROI + """ + self.remove_roi(roi=roi) diff --git a/app/resources/toolbar/toolbar.json b/app/resources/toolbar/toolbar.json index b083503..dd5c0bd 100644 --- a/app/resources/toolbar/toolbar.json +++ b/app/resources/toolbar/toolbar.json @@ -18,7 +18,7 @@ }, "action": "roi_manager.set_tool", "args": { - "tool": "line_drawer" + "tool": "bounded_line_drawer" }, "tooltip": "Trend Line", "text": "Trend Line", diff --git a/app/view.py b/app/view.py index d3aa622..50902e5 100644 --- a/app/view.py +++ b/app/view.py @@ -28,7 +28,7 @@ def __init__(self, parent=None, data=None): super(MainWindow, self).__init__(parent=parent) self.setupUi(self) - self.setWindowState(QtCore.Qt.WindowMaximized) + # self.setWindowState(QtCore.Qt.WindowMaximized) # Constants self.tickers_dialog = None @@ -41,6 +41,7 @@ def __init__(self, parent=None, data=None): self.thread_pool = ThreadPool() self.signals = EventHandler() self.favorites_manager = FavoritesManager(parent=self) + self.roi_manager = ROIManager(parent=self) # Signals self.lie_ticker.mousePressEvent = self.tickers_dialog.show @@ -158,7 +159,7 @@ def _on_indicator_switched(self, indicator: object, state: bool): indicator.remove_indicator(graph_view=self.wgt_graph.graph) @QtCore.Slot(str, dict) - def _on_action_triggered(self, action: str, args:dict): + def _on_action_triggered(self, action: str, args: dict): """Callback on action triggered from the toolbar :param action: The action to find and call From 4f99c7003f8d72d83c6eb4512ac4b33bf85ff377 Mon Sep 17 00:00:00 2001 From: AlexLaur Date: Mon, 29 Mar 2021 09:33:25 +0200 Subject: [PATCH 6/6] continue tests arround rois --- app/libs/events_handler.py | 7 ++-- app/libs/graph/graphwidget.py | 25 +++++++++++++-- app/libs/roi_manager.py | 60 +++++++++++++++++++++++++---------- 3 files changed, 71 insertions(+), 21 deletions(-) diff --git a/app/libs/events_handler.py b/app/libs/events_handler.py index 40d2097..167c240 100644 --- a/app/libs/events_handler.py +++ b/app/libs/events_handler.py @@ -31,6 +31,9 @@ class EventHandler(QtCore.QObject): sig_favorite_removed = QtCore.Signal(dict) sig_favorite_clicked = QtCore.Signal(str) - sig_graph_clicked = QtCore.Signal(list, object) - sig_articles = QtCore.Signal(dict) + + sig_graph_clicked = QtCore.Signal(list, object) + sig_graph_mouse_moved = QtCore.Signal(object) + sig_graph_mouse_pressed = QtCore.Signal(object) + sig_graph_mouse_released = QtCore.Signal(object) diff --git a/app/libs/graph/graphwidget.py b/app/libs/graph/graphwidget.py index ddd4688..857be52 100644 --- a/app/libs/graph/graphwidget.py +++ b/app/libs/graph/graphwidget.py @@ -109,6 +109,18 @@ def _on_mouse_clicked(self, event): plot_items = [x for x in items if isinstance(x, pg.PlotItem)] self.signals.sig_graph_clicked.emit(plot_items, event) + def mousePressEvent(self, event): + self.signals.sig_graph_mouse_pressed.emit(event) + super(GraphView, self).mousePressEvent(event) + + def mouseReleaseEvent(self, event): + self.signals.sig_graph_mouse_released.emit(event) + super(GraphView, self).mouseReleaseEvent(event) + + def mouseMoveEvent(self, event): + self.signals.sig_graph_mouse_moved.emit(event) + super(GraphView, self).mouseMoveEvent(event) + class GraphWidget(QtWidgets.QWidget): """Widget wrapper for the graph""" @@ -123,10 +135,19 @@ def __init__(self, parent=None): self.signals = EventHandler() - # Signals + # Relay Signals self._graph.signals.sig_graph_clicked.connect( self.signals.sig_graph_clicked.emit - ) # Relay signal + ) + self._graph.signals.sig_graph_mouse_pressed.connect( + self.signals.sig_graph_mouse_pressed.emit + ) + self._graph.signals.sig_graph_mouse_released.connect( + self.signals.sig_graph_mouse_released.emit + ) + self._graph.signals.sig_graph_mouse_moved.connect( + self.signals.sig_graph_mouse_moved.emit + ) @property def graph(self): diff --git a/app/libs/roi_manager.py b/app/libs/roi_manager.py index b58f1e6..5d28070 100644 --- a/app/libs/roi_manager.py +++ b/app/libs/roi_manager.py @@ -1,3 +1,4 @@ +import time import pyqtgraph as pg from PySide2 import QtCore, QtWidgets @@ -8,33 +9,38 @@ def __init__(self, parent=None): # Constants self.current_tool = None + self.current_handle = None + self.current_graph = None self._graph = self.parent().wgt_graph.graph # Signals self.parent().wgt_graph.signals.sig_graph_clicked.connect( self._on_roi_add_requested ) + self.parent().wgt_graph.signals.sig_graph_mouse_moved.connect(self._on_mouse_moved) + # self.parent().wgt_graph.signals.sig_graph_mouse_pressed.connect(self._on_mouse_pressed) + # self.parent().wgt_graph.signals.sig_graph_mouse_released.connect(self._on_mouse_released) def drawer(self, graph, event): - """Drawer over the graph""" - # Test - vb = graph.vb - mousePoint = vb.mapSceneToView(event.pos()) - print(mousePoint) - # End test + """Drawer over the graph + :param graph: The graph on whch to draw + :type graph: pg.PlotItem + :param event: The event + :type event: object + """ + self.current_graph = graph + vb = graph.vb + mouse_point = vb.mapSceneToView(event.pos()) if self.current_tool: - self.current_tool(graph=graph) # Exec the current tool - self.unset_tool() + self.current_tool(initial_pos=mouse_point) # Exec the current tool - def bounded_line_drawer(self, graph, **kwargs): + def bounded_line_drawer(self, initial_pos, **kwargs): """Draw a bounded line - - :param graph: The graph on whch to draw - :type graph: pg.PlotItem """ - roi = pg.LineSegmentROI(([50, 50], [150, 50]), removable=True) - graph.addItem(roi) + roi = pg.LineSegmentROI((initial_pos, initial_pos), removable=True) + self.current_handle = roi.getHandles()[-1] + self.current_graph.addItem(roi) roi.sigRemoveRequested.connect(self._on_roi_remove_requested) def set_tool(self, **kwargs): @@ -50,6 +56,8 @@ def set_tool(self, **kwargs): def unset_tool(self): """Unset the current tool""" self.current_tool = None + self.current_handle = None + self.current_graph = None def remove_roi(self, roi): """Remove the given roi @@ -57,13 +65,31 @@ def remove_roi(self, roi): :param roi: The roi to remove :type roi: pg.ROI """ - print(roi.parent()) + print(roi) + + @QtCore.Slot(object) + def _on_mouse_moved(self, event): + if self.current_handle: + vb = self.current_graph.vb + mousePoint = vb.mapSceneToView(event.pos()) + self.current_handle.setPos(mousePoint) + + @QtCore.Slot(object) + def _on_mouse_released(self, event): + print("Released", event) + + @QtCore.Slot(object) + def _on_mouse_pressed(self, event): + print("Pressed", event) @QtCore.Slot(list, object) def _on_roi_add_requested(self, objects, event): """Called on a draw requested""" - if objects: - self.drawer(graph=objects[0], event=event) + if not self.current_handle: + if objects: + self.drawer(graph=objects[0], event=event) + else: + self.unset_tool() @QtCore.Slot(object) def _on_roi_remove_requested(self, roi):