Beispiel #1
0
 def selectedItems(self, *args, **kwargs):
     return map(toGraphicsObjectIfPossible,
                QGraphicsScene.selectedItems(self, *args, **kwargs))
Beispiel #2
0
class Level(QFrame):
    def __init__(self, parent):
        QFrame.__init__(self,parent)

        self.filename = QString()
        self.copiedItem = QByteArray()
        self.pasteOffset = 5
        self.prevPoint = QPoint()
        self.addOffset = 5
        
        self.screenSize = (320, 240)
        self.bgColor = QColor(244,244,244)
        '''0.Portrait 1.Landscape'''
        self.orientation = 0
        self.currentItem = None
        

        self.printer = QPrinter(QPrinter.HighResolution)
        self.printer.setPageSize(QPrinter.Letter)


        '''1.Header'''
        self.levelBar = LevelBar(self)
        
        '''3.Tiler'''
        self.tiler = TileMapGrid(self)#Tiler(self)
        self.tiler.setMinimumHeight(100)
        #self.tiler.currentChanged.connect(self.closeDesigner)
        #self.tiler.setTabsClosable(True)
        #self.tiler.setTabShape(0)
        #self.tiler.hide()
        #self.levelLayout.addWidget(self.levelBar) 
        
        '''2.view'''
        viewLayoutWidget = QFrame()
        viewLayoutWidget.setFrameShape(QFrame.StyledPanel)
        viewLayout = QHBoxLayout(viewLayoutWidget)
        #viewLayout.setMargin(10)
        self.view = LevelView(viewLayoutWidget)
        '''scene'''
        self.scene = QGraphicsScene(self)
        #self.scene.selectionChanged.connect(self.setConnect)
        #self.view.setStyleSheet("border: 1px solid red;")
        
        self.setBackgroundColor(self.bgColor)
        self.setScreenSize(self.screenSize)
        
        self.view.setScene(self.scene)
        self.view.setAlignment(Qt.AlignCenter)
        self.scroll_off = 1
        self.setScrollBar()
        
        viewLayout.setMargin(0)
        viewLayout.addWidget(self.view)

        self.wrapped = [] # Needed to keep wrappers alive
        layout = QVBoxLayout(self)
        layout.addWidget(self.levelBar)
        layout.addWidget(viewLayoutWidget)
        layout.addWidget(self.tiler)
        layout.setMargin(0)
        self.setLayout(layout)
        
    def setScrollBar(self):
        if(self.scroll_off):
            self.view.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
            self.view.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
            self.scroll_off = 0
        else:
            self.view.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
            self.view.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
            self.scroll_off = 1
        
    def setBackgroundColor(self,color):
        self.bgColor = color
        self.scene.setBackgroundBrush(QBrush(color))
        
    def setScreenSize(self,size):
        self.screenSize = size
        self.setOrientation(self.orientation)
        
    def setOrientation(self,idx):
        self.orientation = idx
        if(idx == 0):
            self.view.setMaximumSize(self.screenSize[1], self.screenSize[0])
            self.scene.setSceneRect(0, 0, self.screenSize[1], self.screenSize[0])
        else:
            self.view.setMaximumSize(self.screenSize[0], self.screenSize[1])
            self.scene.setSceneRect(0, 0, self.screenSize[0], self.screenSize[1])
        
    def offerSave(self):
        if (Dirty and QMessageBox.question(self,
                            "Designer - Unsaved Changes",
                            "Save unsaved changes?",
                            QMessageBox.Yes|QMessageBox.No) == 
           QMessageBox.Yes):
            self.save()


    def position(self):
        point = self.mapFromGlobal(QCursor.pos())
        if not self.view.geometry().contains(point):
            coord = random.randint(36, 144)
            point = QPoint(coord, coord)
        else:
            if point == self.prevPoint:
                point += QPoint(self.addOffset, self.addOffset)
                self.addOffset += 5
            else:
                self.addOffset = 5
                self.prevPoint = point
        return self.view.mapToScene(point)
    
    def selectedItem(self):
        items = self.scene.selectedItems()
        if len(items) == 1:
            return items[0]
        return None
    
    def current(self,item):
        self.scene.clearSelection()
        sceneItems = self.scene.items()
        for items in sceneItems:
            if(items != item):
                item.setSelected(False)
                if(item.isConnected()):
                    self.propertyBar.disconnectText(item)
                    item.setConnected(False)
        self.currentItem = item
        self.currentItem.setConnected(True)
        self.currentItem.setSelected(True)
        self.propertyBar.connectText(self.currentItem)
        self.propertyBar.initText(self.currentItem)


    def addText(self):
        item = TextItem("SomeText", self.position())
        self.connect(item, SIGNAL("current"),self.current)
        self.connect(item, SIGNAL("copy"),self.copy)
        self.connect(item, SIGNAL("cut"),self.cut)
        self.connect(item, SIGNAL("paste"),self.paste)
        self.connect(item, SIGNAL("delete"),self.delete)
        #self.current(item)
        self.scene.addItem(item)
        

    def copy(self):
        item = self.selectedItem()
        if item is None:
            return
        self.copiedItem.clear()
        self.pasteOffset = 5
        stream = QDataStream(self.copiedItem, QIODevice.WriteOnly)
        self.writeItemToStream(stream, item)


    def cut(self):
        item = self.selectedItem()
        if item is None:
            return
        self.copy()
        self.scene.removeItem(item)
        del item


    def paste(self):
        if self.copiedItem.isEmpty():
            return
        stream = QDataStream(self.copiedItem, QIODevice.ReadOnly)
        item = self.readItemFromStream(stream, self.pasteOffset)
        self.pasteOffset += 5
        #self.scene.addItem(item)
        
    def delete(self):
        items = self.scene.selectedItems()
        if (len(items) and QMessageBox.question(self,
                "Designer - Delete",
                "Delete {0} item{1}?".format(len(items),
                "s" if len(items) != 1 else ""),
                QMessageBox.Yes|QMessageBox.No) ==
                QMessageBox.Yes):
            while items:
                item = items.pop()
                self.scene.removeItem(item)
                del item
                
    def readItemFromStream(self, stream, offset=0):
        type = QString()
        position = QPointF()
        matrix = QMatrix()
        stream >> type >> position >> matrix
        if offset:
            position += QPointF(offset, offset)
        if type == "Text":
            text = QString()
            font = QFont()
            stream >> text >> font
            self.scene.addItem(TextItem(text, position, font, matrix))
        elif type == "Box":
            rect = QRectF()
            stream >> rect
            style = Qt.PenStyle(stream.readInt16())
            self.scene.addItem(BoxItem(position, style, matrix))
        elif type == "Pixmap":
            pixmap = QPixmap()
            stream >> pixmap
            self.scene.addItem(self.createPixmapItem(pixmap, position, matrix))


    def writeItemToStream(self, stream, item):
        if isinstance(item, QGraphicsTextItem):
            stream << QString("Text") << item.pos() \
                   << item.matrix() << item.toPlainText() << item.font()
        elif isinstance(item, QGraphicsPixmapItem):
            stream << QString("Pixmap") << item.pos() \
                   << item.matrix() << item.pixmap()
        elif isinstance(item, BoxItem):
            stream << QString("Box") << item.pos() \
                   << item.matrix() << item.rect
            stream.writeInt16(item.style)

    def rotate(self):
        for item in self.scene.selectedItems():
            item.rotate(30)


    def print_(self):
        dialog = QPrintDialog(self.printer)
        if dialog.exec_():
            painter = QPainter(self.printer)
            painter.setRenderHint(QPainter.Antialiasing)
            painter.setRenderHint(QPainter.TextAntialiasing)
            self.scene.clearSelection()
            #self.removeBorders()
            self.scene.render(painter)
            #self.addBorders()


    def open(self):
        self.offerSave()
        path = (QFileInfo(self.filename).path()
                if not self.filename.isEmpty() else ".")
        fname = QFileDialog.getOpenFileName(self,
                "Page Designer - Open", path,
                "Page Designer Files (*.pgd)")
        if fname.isEmpty():
            return
        self.filename = fname
        fh = None
        try:
            fh = QFile(self.filename)
            if not fh.open(QIODevice.ReadOnly):
                raise IOError, unicode(fh.errorString())
            items = self.scene.items()
            while items:
                item = items.pop()
                self.scene.removeItem(item)
                del item
            self.addBorders()
            stream = QDataStream(fh)
            stream.setVersion(QDataStream.Qt_4_2)
            magic = stream.readInt32()
            if magic != MagicNumber:
                raise IOError, "not a valid .pgd file"
            fileVersion = stream.readInt16()
            if fileVersion != FileVersion:
                raise IOError, "unrecognised .pgd file version"
            while not fh.atEnd():
                self.readItemFromStream(stream)
        except IOError, e:
            QMessageBox.warning(self, "Page Designer -- Open Error",
                    "Failed to open {0}: {1}".format(self.filename, e))
        finally:
Beispiel #3
0
class DualImageView(QGraphicsView):
    VERTICAL = 0
    HORIZONTAL = 1
    IMAGE_A = 0
    IMAGE_B = 1

    # no argument signal
    images_changed = pyqtSignal()
    annotations_changed = pyqtSignal()
    annotation_selected = pyqtSignal(int)
    no_selection = pyqtSignal()

    # click/point signals
    image_a_click = pyqtSignal(int,int)
    image_b_click = pyqtSignal(int,int)    

    # keyboard
    key_event = pyqtSignal(int)

    def __init__(self, main_win):
        super(QGraphicsView,self).__init__(main_win)
        self.parent_ = main_win
        self.main_win_ = main_win
        self.setInteractive(True)

        self.setStyleSheet("QGraphicsView { border: none; }")
        
        self.scene_ = QGraphicsScene(0,0,0,0,self.parent_)
        self.image_item_ = self.scene_.addPixmap(QPixmap())
        self.image_item_.setPos(0,0)
        #self.ann_group_ = QGraphicsItemGroup()
        #self.ann_group_.setPos(0,0)
        #self.scene_.addItem(self.ann_group_)
        self.setScene(self.scene_)
        self.scene_.selectionChanged.connect(self.on_selection_changed)
        
        # TODO: handle orientation
        self.orientation_ = DualImageView.VERTICAL
        self.images_ = [None, None]
        self.composite_ = None
        self.annotations_ = []
        self.dim_ = 0
        self.offset_ = np.array([0,0])
        self.cancel_click_ = False
        
        self.images_changed.connect(self.on_images_changed)
        self.annotations_changed.connect(self.on_annotations_changed)

    def on_selection_changed(self):
        log.debug("on_selection_changed")
        selected = self.scene_.selectedItems()
        if len(selected) > 0:
            self.cancel_click_ = True
            selected = self.scene_.selectedItems()[0]
            idx = -1
            for a in self.annotations_:
                idx += 1
                if a.item == selected:
                    log.debug(" emitting selection {0}".format(idx))
                    self.annotation_selected.emit(idx)
        else:
            self.no_selection.emit()

    @property
    def image_b_offset(self):
        return np.array([0,self.dim_],dtype=np.int32)

    def point_in_image(self, p):
        if p[1] < self.dim_:
            return 0
        else:
            return 1

    def point_to_image(self, which, p):
        if which == DualImageView.IMAGE_B:
            return p - self.image_b_offset
        return p

    def image_to_view(self, which, p):
        if which == DualImageView.IMAGE_B:
            return p + self.image_b_offset
        return p

    def on_images_changed(self):
        imga = self.images_[0]
        imgb = self.images_[1]
        width = max(imga.shape[1],imgb.shape[1])
        heighta = imga.shape[0]
        heightb = imgb.shape[0]
        height = heighta + heightb
        self.dim_ = heighta
        self.offset_ = np.array([0,heighta])
        # this assumes rgb images :-(
        comp = np.empty((height,width,imga.shape[2]),dtype=imga.dtype)
        comp[0:heighta,:imga.shape[1],:] = imga
        comp[heighta:(heighta+heightb),:imgb.shape[1],:] = imgb
        self.composite_ = comp
        qimg = qn.array2qimage(self.composite_)
        pix = QPixmap.fromImage(qimg)
        self.image_item_.setPixmap(pix)
        self.scene_.setSceneRect(0,0, width, height)
        self.repaint()
        
    def on_annotations_changed(self):
        #log.debug("on_annotations_changed")
        # self.scene_.removeItem(self.ann_group_)
        # self.ann_group_ = QGraphicsItemGroup()
        # self.ann_group_.setHandlesChildEvents(False)
        # self.ann_group_.setPos(0,0)
        # for a in self.annotations_:
        #     log.debug(" adding item")
        #     self.ann_group_.addToGroup(a.get_item())
        # self.scene_.addItem(self.ann_group_)
        self.repaint()

    def transform_raw_pt(self, ev):
        pt = self.mapToScene(ev.x(), ev.y())
        return np.array([int(pt.x()), int(pt.y())], dtype=np.int32)

    def clear(self):
        self.images_ = [None,None]
        self.composite_ = None
        self.annotations_ = None
        self.images_changed.emit()
        self.annotations_changed.emit()
        
    def set_images(self, img_pair):
        self.images_ = img_pair
        self.images_changed.emit()

    # @property
    # def annotations(self):
    #     return self.annotations_
    
    # @annotations.setter
    # def annotations(self, anns):
    #     self.annotations_ = anns
    #     self.annotations_changed.emit()

    # def set_annotations(self, anns):
    #     self.annotations_ = anns
    #     self.annotations_changed.emit()

    def paintEvent(self, ev):
        painter = QPainter(self.viewport())
        painter.fillRect(0,0,self.viewport().width(),self.viewport().height(), QColor(0,0,0))
        painter.end()
        QGraphicsView.paintEvent(self, ev)

    def annotation(self, idx):
        return self.annotations_[idx]

    def clear_annotations(self):
        for a in self.annotations_:
            self.scene_.removeItem(a.item)
        self.annotations_ = []
        self.annotations_changed.emit()

    def add_annotation(self, ann):
        ann.changed.connect(self.on_annotations_changed)
        self.annotations_.append(ann)
        self.scene_.addItem(ann.item)
        self.annotations_changed.emit()
        return len(self.annotations_) - 1
        
    def remove_last_annotation(self):
        self.scene_.removeItem(self.annotations_[-1].item)
        del self.annotations_[-1]
        self.annotations_changed.emit()

    def remove_annotation(self, idx):
        self.scene_.removeItem(self.annotations_[idx].item)
        del self.annotations_[idx]
        self.annotations_changed.emit()

    def mousePressEvent(self, ev):
        super(DualImageView,self).mousePressEvent(ev)
        if self.cancel_click_:
            return
        log.debug("mouse pressed: " + str(ev))
        self.img_local_pt = self.transform_raw_pt(ev)

    def mouseReleaseEvent(self, ev):
        super(DualImageView,self).mouseReleaseEvent(ev)
        if self.cancel_click_:
            self.cancel_click_ = False
            return
        log.debug("mouse released: " + str(ev))
        rel_pt = self.transform_raw_pt(ev)
        delta = rel_pt - self.img_local_pt
        if abs(delta[0]) < 3 and abs(delta[1] < 3):
            # it was a successful click
            self.mouseClicked(self.img_local_pt)
        else: 
            # recognize this as a rectangle drag
            self.mouseDragged(self.img_local_pt, delta)

    def mouseDragged(self, pt, delta):
        log.debug("mouse dragged: {0}, {1}".format(pt,delta))

    def mouseClicked(self, pt):
        log.debug("mouse clicked: {0}".format(pt))
        if pt[1] < self.dim_:
            self.image_a_click.emit(pt[0],pt[1])
        else:
            self.image_b_click.emit(pt[0],pt[1] - self.dim_)

    # handle the keyboard events here!
    def keyPressEvent(self, ev):
        pass

    def keyReleaseEvent(self, ev):
        k = ev.key()
        self.key_event.emit(k)
Beispiel #4
0
class MainForm(QDialog):

    def __init__(self, parent=None, filename=None):
        super(MainForm, self).__init__(parent)

        self.view = GraphicsView()
        background = QPixmap(filename)

        self.filename = os.path.splitext(filename)[0]
        if ("-%s" % ORG) in self.filename:
            self.filename = self.filename[:-len(ORG)-5] + ".png"

        self.view.setBackgroundBrush(QBrush(background))
        # self.view.setCacheMode(QGraphicsView.CacheBackground)
        # self.view.setDragMode(QGraphicsView.ScrollHandDrag)

        self.scene = QGraphicsScene(self)
        global scene
        scene = self.scene
        self.view.dialog = self
        self.view.setScene(self.scene)
        self.prevPoint = QPoint()
        self.lastStamp = -1 

        buttonLayout = QVBoxLayout()
        for text, slot in (
                ("&Tag", self.addTag),
                ("Align &bottom", self.alignBottom),
                ("Align &left", self.alignLeft),
                ("&Save", self.save),
                ("&Quit", self.accept)):
            button = QPushButton(text)
            if not MAC:
                button.setFocusPolicy(Qt.NoFocus)
            self.connect(button, SIGNAL("clicked()"), slot)
            if text == "&Save":
                buttonLayout.addStretch(5)
            if text == "&Quit":
                buttonLayout.addStretch(1)
            buttonLayout.addWidget(button)
        buttonLayout.addStretch()

        self.view.resize(background.width(), background.height())
        self.scene.setSceneRect(0, 0, background.size().width(), background.size().height())
        self.view.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)

        layout = QHBoxLayout()
        layout.addWidget(self.view, 1)
        layout.addLayout(buttonLayout)
        self.setLayout(layout)

        self.setWindowTitle(AppName)
        
        info_name = self.filename + "-" + TAG + ".txt"
            
        if os.path.exists(info_name):
            for tag, x, y in [line.strip().split("\t") for line in open(info_name, "rt").readlines()]:
                self.addTag(int(tag), QPointF(int(x), int(y)), adjust_position=False)
        global Dirty; Dirty=False
        self.show()
        self.raise_()

    def reject(self):
        self.accept()

    def accept(self):
        self.offerSave()
        QDialog.accept(self)
        
    def offerSave(self):
        if (Dirty and QMessageBox.question(self, "%s - Unsaved Changes" % AppName, "Save unsaved changes?", 
                                           QMessageBox.Yes|QMessageBox.No) == QMessageBox.Yes):
            self.save()

    def position(self):
        return QPointF(self.view.mapFromGlobal(QCursor.pos()))
    
    def addTag(self, stamp=None, position=None, adjust_position=True):
        if not position: position = self.position()
        if stamp is not None:
            self.lastStamp = stamp
        else:
            self.lastStamp += 1
        item = StampItem(self.lastStamp, position, self.scene, adjust_position=adjust_position)
        item.update()
        global Dirty; Dirty = True

    def save(self):
        vals = sorted([(item.stamp, item.pos().x(), item.pos().y()) for item in self.scene.items() if isinstance(item, StampItem)])
        info_name = "%s-%s.txt" %(self.filename, TAG)
        f = open(info_name, "wt")
        for tag, x, y in vals:
            f.write("%s\t%d\t%d\n" % (tag, x, y))
        f.close()
        save_png(self.filename, [(x-5, y-5) for _, x, y in vals])
        global Dirty; Dirty = False
        
    def renumberTags(self):
        """Number the tags by skipping the missing values"""
        vals = sorted([(item.stamp, item) for item in self.scene.items() if isinstance(item, StampItem)])
        for i, (_, v) in enumerate(vals):
            v.setStamp(i)
        if not vals: i = -1
        self.lastStamp = i
        global Dirty; Dirty = True
        
    def alignBottom(self):
        """Align tags horizontally, use bottom margin as a reference"""
        items = [item for item in self.scene.selectedItems() if isinstance(item, StampItem)]
        if items:
            ref_y = max(item.pos().y() for item in items)
            for item in items:
                item.setY(ref_y)
            global Dirty; Dirty = True
                
    def alignLeft(self):
        """Align tags vertically, use left margin as a reference"""
        items = [item for item in self.scene.selectedItems() if isinstance(item, StampItem)]
        if items:
            ref_x = min(item.pos().x() for item in items)
            for item in items:
                item.setX(ref_x)
            global Dirty; Dirty = True