Ejemplo n.º 1
0
 def __init__(self, circuit):
     super(CircuitItem, self).__init__()
     self.setFlag(QGraphicsItem.ItemIsMovable)
     self.setFlag(QGraphicsItem.ItemIsSelectable)
     self.setFlag(QGraphicsItem.ItemSendsGeometryChanges)
     imgDir = filePath('icons/')
     self.data = circuit
     """The real info. The class CircuitItem is just a graphical container
     around it. data is saved / loaded to / from file.
     """
     self.image = QImage(imgDir + circuit.__class__.__name__ + '.png')
     """The graphical representation of our item on screen."""
     if not self.image:
         self.image = QImage(imgDir + 'Default.png')
         self.showCategory = True
     self.showName = True
     """Is the item's name shown on screen?"""
     self.showCategory = False
     """Is the item's category (circuit class) shown on screen?"""
     self.name = QGraphicsSimpleTextItem(self)
     # that won't rotate when the PlugItem is rotated by the user.
     self.name.setFlag(QGraphicsItem.ItemIgnoresTransformations)
     self.name.setText(self.data.name)
     self.category = QGraphicsSimpleTextItem(self)
     self.category.setFlag(QGraphicsItem.ItemIgnoresTransformations)
     self.category.setText(self.data.category)
     self.setupPaint()
Ejemplo n.º 2
0
 def __init__(self, plug):
     super(PlugItem, self).__init__()
     self.data = plug
     """The real info. The class PlugItem is just a graphical container
     around it. data is saved / loaded to / from file.
     """
     self.showName = False
     """Is the name of the item shown on screen?"""
     self.setFlag(QGraphicsItem.ItemIsMovable)
     self.setFlag(QGraphicsItem.ItemIsSelectable)
     self.setFlag(QGraphicsItem.ItemSendsGeometryChanges)
     self.setAcceptsHoverEvents(True)
     self.setPen(QPen(QBrush(QColor(QColor('black'))), 2))
     # This path is needed at each mouse over event, to check if
     # the mouse is over a pin. We save it as an instance field,
     # rather than recreate it at each event.
     self.pinPath = QPainterPath()
     if self.data.isInput:
         self.pinPath.addEllipse(
             self.bodyW + self.pinW / 2, self.bodyW / 2,
             self.pinW, self.pinW)
     else:
         self.pinPath.addEllipse(
             self.pinW / 2, self.bodyW / 2, self.pinW, self.pinW)
     f = QFont('Times', 12, 75)
     # Name and value text labels.
     self.name = QGraphicsSimpleTextItem(self)
     # that won't rotate when the PlugItem is rotated by the user.
     self.name.setFlag(QGraphicsItem.ItemIgnoresTransformations)
     self.name.setText(self.data.name)
     self.name.setFont(f)
     self.value = QGraphicsSimpleTextItem(self)
     self.value.setFlag(QGraphicsItem.ItemIgnoresTransformations)
     # Or else value would get the clicks, instead of the PlugItem.
     self.value.setFlag(QGraphicsItem.ItemStacksBehindParent)
     self.value.setFont(f)
     self.setupPaint()
Ejemplo n.º 3
0
    def reload(self, order_overview_widget, all_ops, all_operations, sort=1):

        # mainlog.debug("reload...")
        progress = QProgressDialog(_("Collecting data..."), None, 0,
                                   len(all_ops) + 3, order_overview_widget)
        progress.setWindowTitle("Horse")
        progress.setMinimumDuration(0)
        progress.setWindowModality(Qt.WindowModal)
        progress.setValue(progress.value() + 1)
        progress.show()

        for i in self.items():
            self.removeItem(i)

        self.posts_offsets = dict()
        self.drawn_operations_data = dict()

        self.cursor = QGraphicsRectItem(0, 0, 50, 300)
        self.cursor.setBrush(QBrush(QColor(208, 208, 255, 255)))
        self.cursor.setPen(QPen(Qt.transparent))
        self.addItem(self.cursor)

        bar_width = 8
        bar_height = int(bar_width * 60.0 / 8.0)

        ascent = QFontMetrics(self.base_font).ascent()
        ascent_big = QFontMetrics(self.base_font_big).ascent()

        post_ops = {}

        # mainlog.debug("reload...2")

        # z = 0
        # for op,order_part,parts in all_operations:
        #     z = op.planned_hours
        #     z = order_part.deadline
        #     z = order_part.qty
        #     z = order_part.human_identifier

        # all_operations = map(lambda i:i[0],all_operations)

        y = 0
        for opdef in all_ops:
            progress.setValue(progress.value() + 1)

            operations = filter(
                lambda op: op.operation_definition_id == opdef.
                operation_definition_id, all_operations)

            # We're only interested in the effort/time that remains
            # to be put on an operation. We're only interested in
            # the future.

            # We want the oeprations that are either
            # - ongoing
            # - ready to start.
            # In all cases we're only interested in operations
            # that are "active"

            if sort == 1:
                operations = sorted(
                    operations, key=lambda op: op.deadline or date(3000, 1, 1))
            elif sort == 2:
                operations = sorted(
                    operations,
                    key=lambda op: op.planned_hours * op.qty - op.done_hours)
            else:
                # Don't sort
                pass

            maximum = 16.0  #float !
            small_hours = 0
            op_ndx = 0
            current_x = 50
            bar_drawn = False

            total_done_hours = total_estimated = 0

            # --------------------------------------------------------------
            # Started operations

            bars_line = BarsLine(16, bar_width, bar_height, current_x, y, self,
                                 order_overview_widget)
            total_hours_to_do = 0

            for op in filter(lambda op: op.done_hours > 0, operations):
                hours_to_do = max(
                    0, op.planned_hours * op.qty -
                    op.done_hours)  # max protects against reporting errors
                total_hours_to_do += hours_to_do

                total_estimated += op.planned_hours * op.qty
                total_done_hours += op.done_hours

                bars_line.add_bar(hours_to_do, QBrush(Qt.green),
                                  self._operation_hoover_description(op),
                                  False,
                                  None)  # op.production_file.order_part)

            # --------------------------------------------------------------
            bars_line_unstarted_operations = BarsLine(16, bar_width,
                                                      bar_height,
                                                      current_x + 30, y, self,
                                                      order_overview_widget)
            total_hours_to_do_on_unstarted_operations = 0
            for op in filter(lambda op: op.done_hours == 0, operations):

                hours_to_do = op.planned_hours * op.qty
                total_hours_to_do_on_unstarted_operations += hours_to_do

                total_estimated += hours_to_do

                bars_line_unstarted_operations.add_bar(
                    hours_to_do, QBrush(Qt.yellow),
                    self._operation_hoover_description(op), False,
                    None)  #op.production_file.order_part)

            y_start = y

            total = total_hours_to_do + total_hours_to_do_on_unstarted_operations

            if total > 0:

                self.drawn_operations_data[
                    opdef.operation_definition_id] = "{}h".format(
                        int(round(total_estimated)))

                gi = QGraphicsSimpleTextItem(
                    _("{} - Estimated to do : {}h; done : {}h").format(
                        opdef.description, int(round(total)),
                        int(round(total_done_hours))))
                gi.setFont(self.base_font_big)
                gi.setPos(0, y - gi.boundingRect().height())
                self.addItem(gi)

                th = gi.boundingRect().height()

                gi = QGraphicsLineItem(-ascent_big, y, 1024 + 2 * ascent_big,
                                       y)
                gi.setPen(QPen(Qt.black))
                self.addItem(gi)

                y += th
            else:
                continue

            y_bars = y

            if total_hours_to_do > 0:
                # There's something to draw

                head = QGraphicsSimpleTextItem(_("Started"))
                head.setFont(self.base_font)
                head.setPos(current_x, y)
                self.addItem(head)
                y += head.boundingRect().height()

                y += bar_height
                bars_line.set_start_pos(current_x, y)
                bars_line.finish_bar()

                foot = QGraphicsSimpleTextItem(
                    _("{}h").format(int(total_hours_to_do + 0.5)))
                foot.setFont(self.base_font)
                foot.setPos(current_x, y)
                self.addItem(foot)
                y += foot.boundingRect().height()

                current_x = max(current_x + bars_line.estimate_width(),
                                head.boundingRect().right(),
                                foot.boundingRect().right())

                bar_drawn = True

            if total_hours_to_do_on_unstarted_operations > 0:

                if bars_line_unstarted_operations.estimate_width(
                ) + current_x > 1200:
                    x = 50
                    y += ascent_big
                else:
                    y = y_bars
                    x = current_x + 50

                head = QGraphicsSimpleTextItem(_("Not started yet"))
                head.setFont(self.base_font)
                head.setPos(x, y)
                self.addItem(head)
                y += head.boundingRect().height()

                y += bar_height
                bars_line_unstarted_operations.set_start_pos(x, y)
                bars_line_unstarted_operations.finish_bar()

                foot = QGraphicsSimpleTextItem(
                    _("{}h").format(
                        int(total_hours_to_do_on_unstarted_operations + 0.5)))
                foot.setFont(self.base_font)
                foot.setPos(x, y)
                self.addItem(foot)
                y += foot.boundingRect().height()

                bar_drawn = True

            y += 3 * ascent_big

            r = self.sceneRect()
            self.posts_offsets[opdef.operation_definition_id] =  \
                QRectF(r.x() - 2*ascent_big, y_start - 1.5*ascent_big,
                       r.width() + 4*ascent_big, (y - ascent_big) - (y_start - 1.5*ascent_big) )
            y += ascent_big

        # mainlog.debug("reload...3")
        import functools
        max_width = functools.reduce(lambda acc, po: max(acc, po.width()),
                                     self.posts_offsets.values(), 0)
        map(lambda po: po.setWidth(max_width), self.posts_offsets.values())

        # for r in self.posts_offsets.values():
        #     gi = QGraphicsLineItem(r.x(),r.y(),r.x()+r.width(),r.y())
        #     gi.setPen(QPen(Qt.lightGray))
        #     self.addItem(gi)

        progress.close()
Ejemplo n.º 4
0
class CircuitItem(QGraphicsItem):
    """Graphical wrapper around the engine Circuit class."""

    textH = 12
    """Height of text."""
    ioH = 20
    """Height between to I/O pins."""
    ioW = 15
    """Length of I/O pins."""
    radius = 10
    """Radius of I/O pin heads."""

    def __init__(self, circuit):
        super(CircuitItem, self).__init__()
        self.setFlag(QGraphicsItem.ItemIsMovable)
        self.setFlag(QGraphicsItem.ItemIsSelectable)
        self.setFlag(QGraphicsItem.ItemSendsGeometryChanges)
        imgDir = filePath('icons/')
        self.data = circuit
        """The real info. The class CircuitItem is just a graphical container
        around it. data is saved / loaded to / from file.
        """
        self.image = QImage(imgDir + circuit.__class__.__name__ + '.png')
        """The graphical representation of our item on screen."""
        if not self.image:
            self.image = QImage(imgDir + 'Default.png')
            self.showCategory = True
        self.showName = True
        """Is the item's name shown on screen?"""
        self.showCategory = False
        """Is the item's category (circuit class) shown on screen?"""
        self.name = QGraphicsSimpleTextItem(self)
        # that won't rotate when the PlugItem is rotated by the user.
        self.name.setFlag(QGraphicsItem.ItemIgnoresTransformations)
        self.name.setText(self.data.name)
        self.category = QGraphicsSimpleTextItem(self)
        self.category.setFlag(QGraphicsItem.ItemIgnoresTransformations)
        self.category.setText(self.data.category)
        self.setupPaint()

    def boundingRect(self):
        """Qt requires overloading this when overloading QGraphicsItem."""
        W = 2 * self.radius + 2 * self.ioW + self.imgW
        ni = self.data.nb_inputs()
        no = self.data.nb_outputs()
        t = (1 - int(max(ni, no) / 2)) * self.ioH - self.radius / 2
        b = (1 + int(max(ni, no) / 2)) * self.ioH + self.radius / 2
        return (
            QRectF(-self.ioW - self.radius, t, W, b - t) if max(ni, no) > 1
            else QRectF(-self.ioW - self.radius, 0, W, self.image.height()))

    def handleAtPos(self, pos):
        """Is there an interactive handle where the mouse is? Return it."""
        for i in range(self.nIn):
            if self.inputPaths[i].contains(pos):
                return self.data.inputList[i]
        for i in range(self.nOut):
            if self.outputPaths[i].contains(pos):
                return self.data.outputList[i]

    def itemChange(self, change, value):
        """Warning view it will soon have to correct pos."""
        if change == QGraphicsItem.ItemPositionHasChanged:
            # Restart till we stop moving.
            self.scene().views()[0].timer.start()
        return QGraphicsItem.itemChange(self, change, value)

    def paint(self, painter, option, widget):
        """Draws the item."""
        painter.setPen(QPen(QColor('black'), 2))
        ni = self.data.nb_inputs()
        no = self.data.nb_outputs()
        for i in range(1 - int(ni / 2), 2 + int(ni / 2)):
            if i != 1 or ni % 2:
                painter.drawLine(-self.ioW, i * self.ioH, 0, i * self.ioH)
        for i in range(1 - int(no / 2), 2 + int(no / 2)):
            if i != 1 or no % 2:
                painter.drawLine(
                    self.imgW, i * self.ioH, self.imgW + self.ioW,
                    i * self.ioH)
        painter.drawImage(QRectF(0, 0, self.imgW, self.imgH), self.image)
        for i in range(ni):
            painter.drawPath(self.inputPaths[i])
        painter.drawLine(
            0, (1 - int(ni / 2)) * self.ioH, 0, (1 + int(ni / 2)) * self.ioH)
        for i in range(no):
            painter.drawPath(self.outputPaths[i])
        painter.drawLine(
            self.imgW,
            (1 - int(no / 2)) * self.ioH,
            self.imgW,
            (1 + int(no / 2)) * self.ioH)
        # Default selection box doesn't work; simple reimplementation.
        if option.state & QStyle.State_Selected:
            pen = QPen(Qt.black, 1, Qt.DashLine)
            painter.setPen(pen)
            painter.drawRect(self.boundingRect())

    def setCategoryVisibility(self, isVisible):
        """Show/Hide circuit category (mostly useful for user circuits)."""
        self.showCategory = isVisible
        self.setupPaint()

    def setNameVisibility(self, isVisible):
        """Shows/Hide the item name in the graphical view."""
        self.showName = isVisible
        self.setupPaint()

    def setNbInputs(self, nb):
        """Add/Remove inputs (for logical gates)."""
        if nb > self.data.nb_inputs():
            for x in range(nb - self.data.nb_inputs()):
                Plug(True, None, self.data)
        elif nb < self.data.nb_inputs():
            for x in range(self.data.nb_inputs() - nb):
                self.data.remove_input(self.data.inputList[0])
        self.setupPaint()

    def setupPaint(self):
        """Offscreen rather than onscreen redraw (few changes)."""
        self.nIn = self.data.nb_inputs()
        self.nOut = self.data.nb_outputs()
        # 3 sections with different heights must be aligned :
        self.imgH = self.image.size().height()   # central (png image)
        self.imgW = self.image.size().width()
        self.inH = (self.nIn - 1) * self.ioH + 2 * self.radius  # inputs
        self.outH = (self.nOut - 1) * self.ioH + 2 * self.radius    # outputs
        # therefore we calculate a vertical offset for each section :
        self.maxH = max(self.imgH, self.inH, self.outH)
        self.imgOff = (
            0 if self.maxH == self.imgH else (self.maxH - self.imgH) / 2.)
        self.inOff = (
            0 if self.maxH == self.inH else (self.maxH - self.inH) / 2.)
        self.outOff = (
            0 if self.maxH == self.outH else (self.maxH - self.outH) / 2.)
        # i/o mouseover detection. Create once, use on each mouseMoveEvent.
        self.inputPaths = []
        self.outputPaths = []
        ni = self.data.nb_inputs()
        no = self.data.nb_outputs()
        for i in range(1 - int(ni / 2), 2 + int(ni / 2)):
            if i != 1 or ni % 2:
                path = QPainterPath()
                path.addEllipse(
                    -self.ioW - self.radius, i * self.ioH - self.radius / 2,
                    self.radius, self.radius)
                self.inputPaths.append(path)
        for i in range(1 - int(no / 2), 2 + int(no / 2)):
            if i != 1 or no % 2:
                path = QPainterPath()
                path.addEllipse(
                    self.imgW + self.ioW, i * self.ioH - self.radius / 2,
                    self.radius, self.radius)
                self.outputPaths.append(path)
        self.name.setVisible(self.showName)
        self.category.setVisible(self.showCategory)
        if self.showName or self.showCategory:
            br = self.mapToScene(self.boundingRect())
            w = self.boundingRect().width()
            h = self.boundingRect().height()
            realX = min([i.x() for i in br])
            realY = min([i.y() for i in br])
            firstY = realY + (w if self.rotation() % 180 else h) + 1
            secondY = firstY + self.textH
            if self.showName:
                self.name.setBrush(QColor('red'))
                self.name.setText(self.data.name)
                self.name.setPos(self.mapFromScene(realX, firstY))
            if self.showCategory:
                self.category.setBrush(QColor('green'))
                self.category.setText(
                    self.data.category if self.data.category
                    else self.data.__class__.__name__)
                self.category.setPos(self.mapFromScene(
                    realX, secondY if self.showName else firstY))
        self.prepareGeometryChange()    # Must be called (cf Qt doc)
        self.update()       # Force onscreen redraw after changes.
Ejemplo n.º 5
0
class PlugItem(QGraphicsPathItem):
    """Graphical wrapper around the engine Plug class."""

    bodyW = 30
    """The width of the body of plugs."""
    pinW = 10
    """The width of the pin part of plugs."""

    def __init__(self, plug):
        super(PlugItem, self).__init__()
        self.data = plug
        """The real info. The class PlugItem is just a graphical container
        around it. data is saved / loaded to / from file.
        """
        self.showName = False
        """Is the name of the item shown on screen?"""
        self.setFlag(QGraphicsItem.ItemIsMovable)
        self.setFlag(QGraphicsItem.ItemIsSelectable)
        self.setFlag(QGraphicsItem.ItemSendsGeometryChanges)
        self.setAcceptsHoverEvents(True)
        self.setPen(QPen(QBrush(QColor(QColor('black'))), 2))
        # This path is needed at each mouse over event, to check if
        # the mouse is over a pin. We save it as an instance field,
        # rather than recreate it at each event.
        self.pinPath = QPainterPath()
        if self.data.isInput:
            self.pinPath.addEllipse(
                self.bodyW + self.pinW / 2, self.bodyW / 2,
                self.pinW, self.pinW)
        else:
            self.pinPath.addEllipse(
                self.pinW / 2, self.bodyW / 2, self.pinW, self.pinW)
        f = QFont('Times', 12, 75)
        # Name and value text labels.
        self.name = QGraphicsSimpleTextItem(self)
        # that won't rotate when the PlugItem is rotated by the user.
        self.name.setFlag(QGraphicsItem.ItemIgnoresTransformations)
        self.name.setText(self.data.name)
        self.name.setFont(f)
        self.value = QGraphicsSimpleTextItem(self)
        self.value.setFlag(QGraphicsItem.ItemIgnoresTransformations)
        # Or else value would get the clicks, instead of the PlugItem.
        self.value.setFlag(QGraphicsItem.ItemStacksBehindParent)
        self.value.setFont(f)
        self.setupPaint()

    def handleAtPos(self, pos):
        """Is there an interactive handle where the mouse is?
        Also return the Plug under this handle.
        """
        return self.data if self.pinPath.contains(pos) else None

    def itemChange(self, change, value):
        """Warning view it will soon have to correct pos."""
        if change == QGraphicsItem.ItemPositionHasChanged:
            # Restart till we stop moving.
            self.scene().views()[0].timer.start()
        return QGraphicsItem.itemChange(self, change, value)

    def setAndUpdate(self):
        """Change the undelying plug's value, and force updates items."""
        self.data.set(not self.data.value)
        for i in self.scene().items():
            if isinstance(i, PlugItem) or isinstance(i, WireItem):
                i.setupPaint()

    def setNameVisibility(self, isVisible):
        """Shows/Hide the item name in the graphical view."""
        self.showName = isVisible
        self.setupPaint()

    def setupPaint(self):
        """Offscreen rather than onscreen redraw (few changes)."""
        path = QPainterPath()
        if self.data.isInput:
            path.addEllipse(
                self.pinW / 2, self.pinW / 2, self.bodyW, self.bodyW)
        else:
            path.addRect(
                3 * self.pinW / 2 + 1, self.pinW / 2, self.bodyW, self.bodyW)
        path.addPath(self.pinPath)
        self.setPath(path)
        self.name.setVisible(self.showName)
        self.name.setText(self.data.name)
        br = self.mapToScene(self.boundingRect())
        w = self.boundingRect().width()
        h = self.boundingRect().height()
        realX = min([i.x() for i in br])
        realY = min([i.y() for i in br])
        self.name.setPos(self.mapFromScene(
            realX, realY + (w if self.rotation() % 180 else h) + 1))
        self.value.setText(
            str(int(self.data.value)) if self.data.value is not None else 'E')
        self.value.setPos(self.mapFromScene(realX + w / 3, realY + h / 3))
        self.value.setBrush(QColor('green' if self.data.value else 'red'))
        self.update()       # Force onscreen redraw after changes.
Ejemplo n.º 6
0
    def _drawNodes(self,scene,selected_state,initial_state):
        for i in scene.items():
            scene.removeItem(i)

        pos = dict()

        sx = 1
        sy = 1
        if configuration.font_select:
            sx = sx * 2
            sy = sy

        pos[OrderStatusType.preorder_definition] = (200*sx,200*sy)
        pos[OrderStatusType.order_definition] = (10*sx,300*sy)
        pos[OrderStatusType.order_ready_for_production] = (300*sx,300*sy)
        pos[OrderStatusType.order_production_paused] = (200*sx,550*sy)
        pos[OrderStatusType.order_completed] = (400*sx,600*sy)
        pos[OrderStatusType.order_aborted] = (10*sx,600*sy)

        mainlog.debug("_drawNodes : selected_state {}".format(selected_state))
        mainlog.debug("_drawNodes : initial_state {}".format(initial_state))

        for org in OrderStatusType.symbols():
            x,y = pos[org]

            item = QGraphicsSimpleTextItem(org.description)

            if (selected_state and org in OrderStatusType.next_states(selected_state)) or org == initial_state or org == selected_state:
                item = MyQGraphicsSimpleTextItem(org, self)
                item.setFlags( item.flags() | QGraphicsItem.ItemIsSelectable)

                if org == selected_state:
                    mainlog.debug("Preselcting {}".format(org))
                    item.setSelected(True)

            item.setFont(self.thinfont)
            item.setPos(x,y)
            scene.addItem(item)

            pos[org] = item.boundingRegion( item.sceneTransform()).boundingRect()

            # scene.addRect(pos[org])


        g_orgs = dict()
        for org in OrderStatusType.symbols():
            g_orgs[org] = OrderStatusType.next_states(org)


        # Draw all arrows which don't end up or leave the selected_state
        drawn = []
        for org,dests in g_orgs.iteritems():
            for dest in dests:
                if selected_state != org and ((org,dest) not in drawn) and ((dest,org) not in drawn):
                    # If an arrow must have two directions, we draw it
                    # like that directly.
                    item = self._makeArrow( pos[org],pos[dest],dest in g_orgs and org in g_orgs[dest])
                    item.setPen(self.grey_pen)
                    scene.addItem( item)
                    drawn.append((org,dest))



        if initial_state:
            scene.addRect(pos[initial_state])

        if selected_state:
            for dest in OrderStatusType.next_states(selected_state):
                item = self._makeArrow( pos[selected_state],pos[dest],False)
                item.setBrush(QBrush(Qt.green))
                scene.addItem( item)
                drawn.append((org,dest))