def _add_time_point(self, center_x, center_y, time_point): """Add a single time point item.""" x = center_x - (self.TIMEPOINT_DIAMETER / 2) y = center_y - (self.TIMEPOINT_DIAMETER / 2) # Create the acutal time point item time_point_item = QGraphicsEllipseItem(0, 0, self.TIMEPOINT_DIAMETER, self.TIMEPOINT_DIAMETER) # The used color is the strongest one of the FRM II colors. time_point_item.setBrush(QBrush(QColor(0x00, 0x71, 0xbb))) time_point_item.setPen(QPen(0)) self.scene().addItem(time_point_item) time_point_item.setPos(x, y) # place the time point item above the timeline and the selection item time_point_item.setZValue(2) # Create the label of the time point showing the time in the # defined strftime format on the right side of the time point item. label = QGraphicsTextItem(time_point.strftime(self.STRFTIME_FMT)) label.setFont(QFont('Monospace')) label_height = label.boundingRect().height() # minor height adjustment label_y = y - label_height / 6 self.scene().addItem(label) label.setPos(x + self.SELECTION_DIAMETER + self.LABEL_SPACING, label_y) # store references to the item and the timepoint in the same dict # to be able to use it for forward and reverse lookup self._time_point_items[time_point] = time_point_item self._time_point_items[time_point_item] = time_point
def _select_item(self, item): """Select the given item by drawing a colored circle beneath the selected item (so it looks like a ring around it. Also emits the timepointSelected signal.""" # The selection_item used to signal the selection of a timepoint # is always the same and is only moved. if self._selection_item is None: self._selection_item = QGraphicsEllipseItem( 0, 0, self.SELECTION_DIAMETER, self.SELECTION_DIAMETER) # The used color is a cubical to the time point color self._selection_item.setBrush(QBrush(QColor(0x70, 0xbb, 0x00))) self._selection_item.setPen(QPen(0)) self.scene().addItem(self._selection_item) # center position of the timepoint circle center_x = item.pos().x() + self.TIMEPOINT_DIAMETER / 2 center_y = item.pos().y() + self.TIMEPOINT_DIAMETER / 2 # move selection item self._selection_item.setPos(center_x - self.SELECTION_DIAMETER / 2, center_y - self.SELECTION_DIAMETER / 2) # store the selection_item like a timepoint item (using the timepoint # of the selected item) self._time_point_items[self._selection_item] = \ self._time_point_items[item] # emit signal at the end to ensure a valid internal state before # anything can react to it self.timepointSelected.emit(self._time_point_items[item])
def update(self): outangle, r1 = self._calculate_reflection() # print(outangle, r1) tp = self.transformOriginPoint() tp.setX(r1) self.setTransformOriginPoint(tp) # print(self.rotation()) self.setRotation(outangle) # print(self._crystal.x(), self.rotation()) QGraphicsEllipseItem.update(self)
def __init__(self, x, y, size=60, width=10, parent=None, scene=None): self._width = width s = size + width / 2 QGraphicsEllipseItem.__init__(self, QRectF(-QPoint(s, s), QSizeF(2 * s, 2 * s)), parent) self.setBrush(QBrush(statuscolor[status.OK])) if not parent and scene: scene.addItem(self) self.setPos(x, y) self.setState(status.OK)
def __init__(self, x, y, size=20, parent=None, scene=None): TableBase.__init__(self, x, y, size, parent, scene) self._halowidth = max(size / 4, 10) self._halo = Halo(x, y, size, self._halowidth, self, scene) self._tuberadius = size / 5 p = QPointF(self._tuberadius, self._tuberadius) s = QSizeF(2 * self._tuberadius, 2 * self._tuberadius) self._tube = QGraphicsEllipseItem(QRectF(-p, s), self) self._tube.setPen(QPen(QColor('black'), 3)) self._tube.setBrush(QBrush(QColor('white'))) self._tube.setZValue(20)
def __init__(self, x, y, size=40, parent=None, scene=None): self._origin = QPoint(x, y) self._size = size self._radius = size / 2 if not self._color: self._color = QColor('white') QGraphicsEllipseItem.__init__(self, QRectF(-QPoint(size, size), QSizeF(2 * size, 2 * size)), parent) if not parent and scene: scene.addItem(self) self.setPos(x, y) self.setBrush(QBrush(self._color))
class DetTable(TableBase): """Class to display the detector including shielding and detector tube.""" _color = QColor('#ff66ff') def __init__(self, x, y, size=20, parent=None, scene=None): TableBase.__init__(self, x, y, size, parent, scene) self._halowidth = max(size / 4, 10) self._halo = Halo(x, y, size, self._halowidth, self, scene) self._tuberadius = size / 5 p = QPointF(self._tuberadius, self._tuberadius) s = QSizeF(2 * self._tuberadius, 2 * self._tuberadius) self._tube = QGraphicsEllipseItem(QRectF(-p, s), self) self._tube.setPen(QPen(QColor('black'), 3)) self._tube.setBrush(QBrush(QColor('white'))) self._tube.setZValue(20)
class TimelineWidget(QGraphicsView): """General widget to display timeline with a list of ordered timepoints. A timepoint is selectable via click and the timepointSelected signal can be used to react to it.""" timepointSelected = pyqtSignal(object) # datetime.datetime object # general layout and design parameters TIMEPOINT_DIAMETER = 30 SELECTION_DIAMETER = 40 TIMEPOINT_SPACING = 50 TIMELINE_WIDTH = 5 LABEL_SPACING = 20 MARGIN_HORIZONTAL = 5 STRFTIME_FMT = '%H:%M:%S\n%Y-%m-%d' def __init__(self, parent=None): QGraphicsView.__init__(self, QGraphicsScene(), parent) self.setAlignment(Qt.AlignLeft | Qt.AlignVCenter) self.setRenderHints(QPainter.Antialiasing | QPainter.SmoothPixmapTransform) # margins set to 0 to simplify calculations self.setContentsMargins(0, 0, 0, 0) self.setViewportMargins(0, 0, 0, 0) # full viewport updates required to avoid optical double selections # caused by scrolling self.setViewportUpdateMode(QGraphicsView.FullViewportUpdate) self._time_points = [] self._time_point_items = {} self._selection_item = None # start with at least one time point (current time) to be able # to reuse size calculation methods for the inital size self.setTimePoints([datetime.now()]) @property def time_points(self): """Sorted list of all timepoints (sorted new to old)""" return self._time_points @property def selected_time_point(self): """Get the selected timeout as datetime object. None if there is no selection.""" if self._selection_item is None: return None return self._time_point_items[self._selection_item] @property def previous_time_point(self): """Get the timepoint before (older than) the currently selected one as datetime object. None if there is no selection""" try: index = self._time_points.index(self.selected_time_point) return self._time_points[index + 1] except (ValueError, IndexError): return None def resizeEvent(self, event): """Clear and readd all items on resize. Avoids complex scaling.""" self.scene().clear() self.setTimePoints(self._time_points) def setTimePoints(self, time_points): """Sets and list of datetime objects as timepoints, sets up all necessary graphics items and adjusts sizes.""" self.scene().clear() self._selection_item = None # store the timepoints sorted from new to old self._time_points = list(reversed(sorted(time_points))) self._time_point_items = {} # draw the timeline self._timeline = self._add_timeline() # draw the time points self._add_time_points() # update the scene size and a slightly larger widget size to avoid # superfluous scrolling (and displaying of scroll bars) size = self.scene().itemsBoundingRect().size() self.setSceneRect(0, 0, size.width(), size.height() - 5) if time_points: self.setMinimumWidth(size.width() * 1.2) self.setMaximumWidth(size.width() * 1.2) def mousePressEvent(self, event): """Handle mouse press events to support item selection.""" item = self.itemAt(event.pos()) if item in self._time_point_items: self._select_item(item) return QGraphicsView.mousePressEvent(self, event) def _select_item(self, item): """Select the given item by drawing a colored circle beneath the selected item (so it looks like a ring around it. Also emits the timepointSelected signal.""" # The selection_item used to signal the selection of a timepoint # is always the same and is only moved. if self._selection_item is None: self._selection_item = QGraphicsEllipseItem( 0, 0, self.SELECTION_DIAMETER, self.SELECTION_DIAMETER) # The used color is a cubical to the time point color self._selection_item.setBrush(QBrush(QColor(0x70, 0xbb, 0x00))) self._selection_item.setPen(QPen(0)) self.scene().addItem(self._selection_item) # center position of the timepoint circle center_x = item.pos().x() + self.TIMEPOINT_DIAMETER / 2 center_y = item.pos().y() + self.TIMEPOINT_DIAMETER / 2 # move selection item self._selection_item.setPos(center_x - self.SELECTION_DIAMETER / 2, center_y - self.SELECTION_DIAMETER / 2) # store the selection_item like a timepoint item (using the timepoint # of the selected item) self._time_point_items[self._selection_item] = \ self._time_point_items[item] # emit signal at the end to ensure a valid internal state before # anything can react to it self.timepointSelected.emit(self._time_point_items[item]) def _add_timeline(self): """Draw the timeline.""" # height is either the necessary space to display all items or the # maximal available display size, so it's looks nicely in larger # windows and enables scrolling in smaller ones. height = self.TIMEPOINT_DIAMETER * len(self._time_points) height += self.TIMEPOINT_SPACING * len(self._time_points) height = max(height, self.viewport().height()) # draw the timeline left aligned with enough space to draw the items # and the selection ring. x = self.MARGIN_HORIZONTAL + (self.SELECTION_DIAMETER / 2) # position the line on the left side of the item item = QGraphicsLineItem(0, 0, 0, height) # The used color for the timeline is the lightest one of the FRM II # colors item.setPen(QPen(QBrush(QColor(0xa3, 0xc1, 0xe7)), self.TIMELINE_WIDTH)) self.scene().addItem(item) # move the whole item to the desired timeline position item.setPos(x, 0) return item def _add_time_points(self): """Add all time point items.""" if not self._time_points: return timeline_pos = self._timeline.pos() timeline_size = self._timeline.boundingRect().size() height = timeline_size.height() # time points are always equally distributed on the timeline spacing = height / float(len(self._time_points)) center_x = timeline_pos.x() # add half of the items spacing on the top and bottom of the timeline start = timeline_pos.y() - spacing / 2 for i, entry in enumerate(self._time_points): self._add_time_point(center_x, start + spacing * (i + 1), entry) def _add_time_point(self, center_x, center_y, time_point): """Add a single time point item.""" x = center_x - (self.TIMEPOINT_DIAMETER / 2) y = center_y - (self.TIMEPOINT_DIAMETER / 2) # Create the acutal time point item time_point_item = QGraphicsEllipseItem(0, 0, self.TIMEPOINT_DIAMETER, self.TIMEPOINT_DIAMETER) # The used color is the strongest one of the FRM II colors. time_point_item.setBrush(QBrush(QColor(0x00, 0x71, 0xbb))) time_point_item.setPen(QPen(0)) self.scene().addItem(time_point_item) time_point_item.setPos(x, y) # place the time point item above the timeline and the selection item time_point_item.setZValue(2) # Create the label of the time point showing the time in the # defined strftime format on the right side of the time point item. label = QGraphicsTextItem(time_point.strftime(self.STRFTIME_FMT)) label.setFont(QFont('Monospace')) label_height = label.boundingRect().height() # minor height adjustment label_y = y - label_height / 6 self.scene().addItem(label) label.setPos(x + self.SELECTION_DIAMETER + self.LABEL_SPACING, label_y) # store references to the item and the timepoint in the same dict # to be able to use it for forward and reverse lookup self._time_point_items[time_point] = time_point_item self._time_point_items[time_point_item] = time_point
def __init__(self): scene = QGraphicsScene() QGraphicsView.__init__(self, scene) self.setRenderHints(QPainter.Antialiasing) self._sample = Sample(0, 0, scene=scene) # draw the center point of the detector circle scene.addItem(QGraphicsEllipseItem(-2, -2, 4, 4)) # draw the detector circle # scene.addItem(ArcGraphicsItem(0, 0, self.detradius + 10, 0, 180)) # draw detector box self._detbox = DetectorBox(self.detradius, self.detopen) scene.addItem(self._detbox) # default values (used when no such devices are configured) self.values = { 'rd1': 27.5, 'rd2': 25.0, 'rd3': 22.5, 'rd4': 20.0, 'rd5': 17.5, 'rd6': 15.0, 'rd7': 12.5, 'rd8': 10.0, 'rd9': 7.5, 'rd10': 5.0, 'rd11': 2.5, 'rg1': 0.0, 'rg2': 0.0, 'rg3': 0.0, 'rg4': 0.0, 'rg5': 0.0, 'rg6': 0.0, 'rg7': 0.0, 'rg8': 0.0, 'rg9': 0.0, 'rg10': 0.0, 'rg11': 0.0, 'ra1': 0.0, 'ra2': 0.0, 'ra3': 0.0, 'ra4': 0.0, 'ra5': 0.0, 'ra6': 0.0, 'ra7': 0.0, 'ra8': 0.0, 'ra9': 0.0, 'ra10': 0.0, 'ra11': 0.0, 'ta1': 125.0, 'ta2': 112.0, 'ta3': 99.0, 'ta4': 86.0, 'ta5': 73.0, 'ta6': 60.0, 'ta7': 47.0, 'ta8': 34.0, 'ta9': 21.0, 'ta10': 8.0, 'ta11': -5.0, 'cad': 0.0, 'lsa': 910., } self.targets = self.values.copy() self.status = { 'rd1': status.OK, 'rd2': status.OK, 'rd3': status.OK, 'rd4': status.OK, 'rd5': status.OK, 'rd6': status.OK, 'rd7': status.OK, 'rd8': status.OK, 'rd9': status.OK, 'rd10': status.OK, 'rd11': status.OK, 'rg1': status.OK, 'rg2': status.OK, 'rg3': status.OK, 'rg4': status.OK, 'rg5': status.OK, 'rg6': status.OK, 'rg7': status.OK, 'rg8': status.OK, 'rg9': status.OK, 'rg10': status.OK, 'rg11': status.OK, 'ra1': status.OK, 'ra2': status.OK, 'ra3': status.OK, 'ra4': status.OK, 'ra5': status.OK, 'ra6': status.OK, 'ra7': status.OK, 'ra8': status.OK, 'ra9': status.OK, 'ra10': status.OK, 'ra11': status.OK, 'ta1': status.OK, 'ta2': status.OK, 'ta3': status.OK, 'ta4': status.OK, 'ta5': status.OK, 'ta6': status.OK, 'ta7': status.OK, 'ta8': status.OK, 'ta9': status.OK, 'ta10': status.OK, 'ta11': status.OK, 'cad': status.OK, 'lsa': status.OK, } for i in range(self.num_crystals): dt = DetectorTable(self.detsize, self.detradius, scene=scene) self._detectors.append(dt) self._guides.append(DetectorGuide(dt)) t = TableTarget(0, 0, self.detsize, scene=scene) # move the origin to make the rotation very easy t.setPos(-self.detradius, -self.detsize) t.setTransformOriginPoint(self.detradius, 0) self._detectors_t.append(t) y = (self.num_crystals // 2 - i) * 20 self._crystals.append( CrystalTable(0, y, self.crystalsize, scene=scene)) self._crystals_t.append( TableTarget(0, y, self.crystalsize, scene=scene)) self._inbeams.append( Beam(self._sample, self._crystals[i], scene=scene)) self._outbeams.append( Beam(self._crystals[i], self._detectors[i], scene=scene)) # self._outbeams.append( # Beam(self._crystals[i], self._reflections[i], scene=scene)) # self._reflections.append( # Reflex(r, self._crystals[i], self._sample, # self._detectors[i], scene=scene)) QGraphicsView.update(self)