1"""Common gui.OWComponent components.""" 2 3from AnyQt.QtCore import Qt, QRectF 4from AnyQt.QtGui import QColor, QFont 5from AnyQt.QtWidgets import QGraphicsEllipseItem 6 7import pyqtgraph as pg 8from Orange.widgets.visualize.owscatterplotgraph import ( 9 OWScatterPlotBase, ScatterBaseParameterSetter 10) 11from Orange.widgets.visualize.utils.customizableplot import Updater 12from Orange.widgets.visualize.utils.plotutils import ( 13 MouseEventDelegate, DraggableItemsViewBox 14) 15 16class AnchorParameterSetter(ScatterBaseParameterSetter): 17 ANCHOR_LABEL = "Anchor" 18 19 def __init__(self, master): 20 super().__init__(master) 21 self.anchor_font = QFont() 22 23 def update_setters(self): 24 super().update_setters() 25 self.initial_settings[self.LABELS_BOX].update({ 26 self.ANCHOR_LABEL: self.FONT_SETTING 27 }) 28 29 def update_anchors(**settings): 30 self.anchor_font = Updater.change_font(self.anchor_font, settings) 31 self.master.update_anchors() 32 33 self._setters[self.LABELS_BOX][self.ANCHOR_LABEL] = update_anchors 34 35 36class OWGraphWithAnchors(OWScatterPlotBase): 37 """ 38 Graph for projections in which dimensions can be manually moved 39 40 Class is used as a graph base class for OWFreeViz and OWRadviz.""" 41 DISTANCE_DIFF = 0.08 42 43 def __init__(self, scatter_widget, parent, view_box=DraggableItemsViewBox): 44 super().__init__(scatter_widget, parent, view_box) 45 self.anchor_items = None 46 self.circle_item = None 47 self.indicator_item = None 48 self._tooltip_delegate = MouseEventDelegate(self.help_event, 49 self.show_indicator_event) 50 self.plot_widget.scene().installEventFilter(self._tooltip_delegate) 51 self.parameter_setter = AnchorParameterSetter(self) 52 53 def clear(self): 54 super().clear() 55 self.anchor_items = None 56 self.circle_item = None 57 self.indicator_item = None 58 59 def update_coordinates(self): 60 super().update_coordinates() 61 if self.scatterplot_item is not None: 62 self.update_anchors() 63 self.update_circle() 64 self.set_view_box_range() 65 self.view_box.setAspectLocked(True, 1) 66 67 def update_anchors(self): 68 raise NotImplementedError 69 70 def update_circle(self): 71 if self.scatterplot_item is not None and not self.circle_item: 72 self.circle_item = QGraphicsEllipseItem() 73 self.circle_item.setRect(QRectF(-1, -1, 2, 2)) 74 self.circle_item.setPen(pg.mkPen(QColor(0, 0, 0), width=2)) 75 self.plot_widget.addItem(self.circle_item) 76 77 def reset_button_clicked(self): 78 self.set_view_box_range() 79 80 def set_view_box_range(self): 81 raise NotImplementedError 82 83 def closest_draggable_item(self, pos): 84 return None 85 86 def show_indicator(self, anchor_idx): 87 self._update_indicator_item(anchor_idx) 88 89 def show_indicator_event(self, ev): 90 scene = self.plot_widget.scene() 91 if self.scatterplot_item is None or scene.drag_tooltip.isVisible(): 92 return False 93 if self.view_box.mouse_state == 1: 94 return True 95 96 pos = self.scatterplot_item.mapFromScene(ev.scenePos()) 97 anchor_idx = self.closest_draggable_item(pos) 98 if anchor_idx is not None: 99 self._update_indicator_item(anchor_idx) 100 if self.view_box.mouse_state == 0: 101 self.view_box.setCursor(Qt.OpenHandCursor) 102 else: 103 if self.indicator_item is not None: 104 self.plot_widget.removeItem(self.indicator_item) 105 self.indicator_item = None 106 self.view_box.setCursor(Qt.ArrowCursor) 107 return True 108 109 def _update_indicator_item(self, anchor_idx): 110 if self.indicator_item is not None: 111 self.plot_widget.removeItem(self.indicator_item) 112 self._add_indicator_item(anchor_idx) 113 114 def _add_indicator_item(self, anchor_idx): 115 pass 116